1 Patch is extracted from transmission svn to already applied upstream
3 Index: libtransmission/rpc-server.c
4 ===================================================================
5 --- libtransmission/rpc-server.c (revision 8399)
6 +++ libtransmission/rpc-server.c (revision 8400)
11 +#include "ptrarray.h"
13 #include "rpc-server.h"
24 +get_current_session_id( struct tr_rpc_server * server )
26 + const time_t now = time( NULL );
28 + if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
32 + const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
33 + const size_t pool_size = strlen( pool );
34 + char * buf = tr_new( char, n+1 );
36 + for( i=0; i<n; ++i )
37 + buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
40 + tr_free( server->sessionId );
41 + server->sessionId = buf;
42 + server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
45 + return server->sessionId;
56 -tr_memmem( const char * s1,
60 +tr_memmem( const char * s1, size_t l1, /* haystack */
61 + const char * s2, size_t l2 ) /* needle */
78 +tr_mimepart_free( struct tr_mimepart * p )
81 + tr_free( p->headers );
86 +extract_parts_from_multipart( const struct evkeyvalq * headers,
87 + const struct evbuffer * body,
88 + tr_ptrArray * setme_parts )
90 + const char * content_type = evhttp_find_header( headers, "Content-Type" );
91 + const char * in = (const char*) EVBUFFER_DATA( body );
92 + size_t inlen = EVBUFFER_LENGTH( body );
94 + const char * boundary_key = "boundary=";
95 + const char * boundary_key_begin = strstr( content_type, boundary_key );
96 + const char * boundary_val = boundary_key_begin ? boundary_key_begin + strlen( boundary_key ) : "arglebargle";
97 + char * boundary = tr_strdup_printf( "--%s", boundary_val );
98 + const size_t boundary_len = strlen( boundary );
100 + const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
104 + const char * part = delim + boundary_len;
106 + inlen -= ( part - in );
109 + delim = tr_memmem( in, inlen, boundary, boundary_len );
110 + part_len = delim ? (size_t)( delim - part ) : inlen;
114 + const char * rnrn = tr_memmem( part, part_len, "\r\n\r\n", 4 );
117 + struct tr_mimepart * p = tr_new( struct tr_mimepart, 1 );
118 + p->headers_len = rnrn - part;
119 + p->headers = tr_strndup( part, p->headers_len );
120 + p->body_len = (part+part_len) - (rnrn + 4);
121 + p->body = tr_strndup( rnrn+4, p->body_len );
122 + tr_ptrArrayAppend( setme_parts, p );
127 + tr_free( boundary );
131 handle_upload( struct evhttp_request * req,
132 struct tr_rpc_server * server )
134 @@ -131,76 +221,67 @@
138 - const char * content_type = evhttp_find_header( req->input_headers,
142 + tr_bool hasSessionId = FALSE;
143 + tr_ptrArray parts = TR_PTR_ARRAY_INIT;
145 const char * query = strchr( req->uri, '?' );
146 - const int paused = query && strstr( query + 1, "paused=true" );
147 + const tr_bool paused = query && strstr( query + 1, "paused=true" );
149 - const char * in = (const char *) EVBUFFER_DATA( req->input_buffer );
150 - size_t inlen = EVBUFFER_LENGTH( req->input_buffer );
151 + extract_parts_from_multipart( req->input_headers, req->input_buffer, &parts );
152 + n = tr_ptrArraySize( &parts );
154 - const char * boundary_key = "boundary=";
155 - const char * boundary_key_begin = strstr( content_type,
157 - const char * boundary_val =
158 - boundary_key_begin ? boundary_key_begin +
159 - strlen( boundary_key ) : "arglebargle";
160 + /* first look for the session id */
161 + for( i=0; i<n; ++i ) {
162 + struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
163 + if( tr_memmem( p->headers, p->headers_len, TR_RPC_SESSION_ID_HEADER, strlen( TR_RPC_SESSION_ID_HEADER ) ) )
167 + const struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
168 + const char * ours = get_current_session_id( server );
169 + const int ourlen = strlen( ours );
170 + hasSessionId = ourlen<=p->body_len && !memcmp( p->body, ours, ourlen );
173 - char * boundary = tr_strdup_printf( "--%s", boundary_val );
174 - const size_t boundary_len = strlen( boundary );
176 - const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
178 + if( !hasSessionId )
181 - const char * part = delim + boundary_len;
182 - inlen -= ( part - in );
184 - delim = tr_memmem( in, inlen, boundary, boundary_len );
185 - part_len = delim ? (size_t)( delim - part ) : inlen;
188 + send_simple_response( req, 409, NULL );
190 + else for( i=0; i<n; ++i )
192 + struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
193 + if( strstr( p->headers, "filename=\"" ) )
195 - char * text = tr_strndup( part, part_len );
196 - if( strstr( text, "filename=\"" ) )
198 - const char * body = strstr( text, "\r\n\r\n" );
203 - tr_benc top, *args;
204 - struct evbuffer * json = tr_getBuffer( );
206 + int body_len = p->body_len;
207 + tr_benc top, *args;
208 + const char * body = p->body;
209 + struct evbuffer * json = evbuffer_new( );
211 - body += 4; /* walk past the \r\n\r\n */
212 - body_len = part_len - ( body - text );
214 - && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
216 + if( body_len >= 2 && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
219 - tr_bencInitDict( &top, 2 );
220 - args = tr_bencDictAddDict( &top, "arguments", 2 );
221 - tr_bencDictAddStr( &top, "method", "torrent-add" );
222 - b64 = tr_base64_encode( body, body_len, NULL );
223 - tr_bencDictAddStr( args, "metainfo", b64 );
224 - tr_bencDictAddBool( args, "paused", paused );
225 - tr_bencSaveAsJSON( &top, json );
226 - tr_rpc_request_exec_json( server->session,
227 - EVBUFFER_DATA( json ),
228 - EVBUFFER_LENGTH( json ),
230 + tr_bencInitDict( &top, 2 );
231 + args = tr_bencDictAddDict( &top, "arguments", 2 );
232 + tr_bencDictAddStr( &top, "method", "torrent-add" );
233 + b64 = tr_base64_encode( body, body_len, NULL );
234 + tr_bencDictAddStr( args, "metainfo", b64 );
235 + tr_bencDictAddBool( args, "paused", paused );
236 + tr_bencSaveAsJSON( &top, json );
237 + tr_rpc_request_exec_json( server->session,
238 + EVBUFFER_DATA( json ),
239 + EVBUFFER_LENGTH( json ),
242 - tr_releaseBuffer( json );
244 - tr_bencFree( &top );
248 + evbuffer_free( json );
250 + tr_bencFree( &top );
254 - tr_free( boundary );
255 + tr_ptrArrayDestruct( &parts, (PtrArrayForeachFunc)tr_mimepart_free );
257 /* use xml here because json responses to file uploads is trouble.
258 * see http://www.malsup.com/jquery/form/#sample7 for details */
264 -get_current_session_id( struct tr_rpc_server * server )
266 - const time_t now = time( NULL );
268 - if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
272 - const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
273 - const size_t pool_size = strlen( pool );
274 - char * buf = tr_new( char, n+1 );
276 - for( i=0; i<n; ++i )
277 - buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
280 - tr_free( server->sessionId );
281 - server->sessionId = buf;
282 - server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
285 - return server->sessionId;
290 test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
294 handle_clutch( req, server );
296 + else if( !strncmp( req->uri, "/transmission/upload", 20 ) )
298 + handle_upload( req, server );
300 #ifdef REQUIRE_SESSION_ID
301 else if( !test_session_id( server, req ) )
305 handle_rpc( req, server );
307 - else if( !strncmp( req->uri, "/transmission/upload", 20 ) )
309 - handle_upload( req, server );
313 send_simple_response( req, HTTP_NOTFOUND, req->uri );
314 Index: web/javascript/transmission.js
315 ===================================================================
316 --- web/javascript/transmission.js (revision 8399)
317 +++ web/javascript/transmission.js (revision 8400)
318 @@ -1247,6 +1247,7 @@
320 args.url = '/transmission/upload?paused=' + (this[Prefs._AutoStart] ? 'false' : 'true');
322 + args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
323 args.dataType = 'xml';
325 args.success = function( data ) {