transmission/files/webupload.patch : add missing patch
[vuplus_openembedded] / recipes / transmission / files / webupload.patch
1 Patch is extracted from transmission svn to already applied upstream
2
3 Index: libtransmission/rpc-server.c
4 ===================================================================
5 --- libtransmission/rpc-server.c        (revision 8399)
6 +++ libtransmission/rpc-server.c        (revision 8400)
7 @@ -32,6 +32,7 @@
8  #include "crypto.h"
9  #include "list.h"
10  #include "platform.h"
11 +#include "ptrarray.h"
12  #include "rpcimpl.h"
13  #include "rpc-server.h"
14  #include "trevent.h"
15 @@ -83,6 +84,36 @@
16      } while( 0 )
17  
18  
19 +/***
20 +****
21 +***/
22 +
23 +static char*
24 +get_current_session_id( struct tr_rpc_server * server )
25 +{
26 +    const time_t now = time( NULL );
27 +
28 +    if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
29 +    {
30 +        int i;
31 +        const int n = 48;
32 +        const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
33 +        const size_t pool_size = strlen( pool );
34 +        char * buf = tr_new( char, n+1 );
35 +
36 +        for( i=0; i<n; ++i )
37 +            buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
38 +        buf[n] = '\0';
39 +
40 +        tr_free( server->sessionId );
41 +        server->sessionId = buf;
42 +        server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
43 +    }
44 +
45 +    return server->sessionId;
46 +}
47 +
48 +
49  /**
50  ***
51  **/
52 @@ -104,10 +135,8 @@
53  }
54  
55  static const char*
56 -tr_memmem( const char * s1,
57 -           size_t       l1,
58 -           const char * s2,
59 -           size_t       l2 )
60 +tr_memmem( const char * s1, size_t l1, /* haystack */
61 +           const char * s2, size_t l2 ) /* needle */
62  {
63      if( !l2 ) return s1;
64      while( l1 >= l2 )
65 @@ -121,7 +150,68 @@
66      return NULL;
67  }
68  
69 +struct tr_mimepart
70 +{
71 +    char * headers;
72 +    int headers_len;
73 +    char * body;
74 +    int body_len;
75 +};
76 +
77  static void
78 +tr_mimepart_free( struct tr_mimepart * p )
79 +{
80 +    tr_free( p->body );
81 +    tr_free( p->headers );
82 +    tr_free( p );
83 +}
84 +
85 +static void
86 +extract_parts_from_multipart( const struct evkeyvalq * headers,
87 +                              const struct evbuffer * body,
88 +                              tr_ptrArray * setme_parts )
89 +{
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 );
93 +
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 );
99 +
100 +    const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
101 +    while( delim )
102 +    {
103 +        size_t part_len;
104 +        const char * part = delim + boundary_len;
105 +
106 +        inlen -= ( part - in );
107 +        in = part;
108 +
109 +        delim = tr_memmem( in, inlen, boundary, boundary_len );
110 +        part_len = delim ? (size_t)( delim - part ) : inlen;
111 +
112 +        if( part_len )
113 +        {
114 +            const char * rnrn = tr_memmem( part, part_len, "\r\n\r\n", 4 );
115 +            if( rnrn )
116 +            {
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 );
123 +            }
124 +        }
125 +    }
126 +
127 +    tr_free( boundary );
128 +}
129 +
130 +static void
131  handle_upload( struct evhttp_request * req,
132                 struct tr_rpc_server *  server )
133  {
134 @@ -131,76 +221,67 @@
135      }
136      else
137      {
138 -        const char * content_type = evhttp_find_header( req->input_headers,
139 -                                                        "Content-Type" );
140 +        int i;
141 +        int n;
142 +        tr_bool hasSessionId = FALSE;
143 +        tr_ptrArray parts = TR_PTR_ARRAY_INIT;
144  
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" );
148  
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 );
153  
154 -        const char * boundary_key = "boundary=";
155 -        const char * boundary_key_begin = strstr( content_type,
156 -                                                  boundary_key );
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 ) ) )
164 +                break;
165 +        }
166 +        if( i<n ) {
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 );
171 +        }
172  
173 -        char *       boundary = tr_strdup_printf( "--%s", boundary_val );
174 -        const size_t boundary_len = strlen( boundary );
175 -
176 -        const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
177 -        while( delim )
178 +        if( !hasSessionId )
179          {
180 -            size_t       part_len;
181 -            const char * part = delim + boundary_len;
182 -            inlen -= ( part - in );
183 -            in = part;
184 -            delim = tr_memmem( in, inlen, boundary, boundary_len );
185 -            part_len = delim ? (size_t)( delim - part ) : inlen;
186 -
187 -            if( part_len )
188 +            send_simple_response( req, 409, NULL );
189 +        }
190 +        else for( i=0; i<n; ++i )
191 +        {
192 +            struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
193 +            if( strstr( p->headers, "filename=\"" ) )
194              {
195 -                char * text = tr_strndup( part, part_len );
196 -                if( strstr( text, "filename=\"" ) )
197 -                {
198 -                    const char * body = strstr( text, "\r\n\r\n" );
199 -                    if( body )
200 -                    {
201 -                        char * b64;
202 -                        size_t  body_len;
203 -                        tr_benc top, *args;
204 -                        struct evbuffer * json = tr_getBuffer( );
205 +                char * b64;
206 +                int body_len = p->body_len;
207 +                tr_benc top, *args;
208 +                const char * body = p->body;
209 +                struct evbuffer * json = evbuffer_new( );
210  
211 -                        body += 4; /* walk past the \r\n\r\n */
212 -                        body_len = part_len - ( body - text );
213 -                        if( body_len >= 2
214 -                          && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
215 -                            body_len -= 2;
216 +                if( body_len >= 2 && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
217 +                    body_len -= 2;
218  
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 ),
229 -                                                  NULL, NULL );
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 ),
240 +                                          NULL, NULL );
241  
242 -                        tr_releaseBuffer( json );
243 -                        tr_free( b64 );
244 -                        tr_bencFree( &top );
245 -                    }
246 -                }
247 -                tr_free( text );
248 +                evbuffer_free( json );
249 +                tr_free( b64 );
250 +                tr_bencFree( &top );
251              }
252          }
253  
254 -        tr_free( boundary );
255 +        tr_ptrArrayDestruct( &parts, (PtrArrayForeachFunc)tr_mimepart_free );
256  
257          /* use xml here because json responses to file uploads is trouble.
258           * see http://www.malsup.com/jquery/form/#sample7 for details */
259 @@ -473,32 +554,6 @@
260      return FALSE;
261  }
262  
263 -static char*
264 -get_current_session_id( struct tr_rpc_server * server )
265 -{
266 -    const time_t now = time( NULL );
267 -
268 -    if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
269 -    {
270 -        int i;
271 -        const int n = 48;
272 -        const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
273 -        const size_t pool_size = strlen( pool );
274 -        char * buf = tr_new( char, n+1 );
275 -
276 -        for( i=0; i<n; ++i )
277 -            buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
278 -        buf[n] = '\0';
279 -
280 -        tr_free( server->sessionId );
281 -        server->sessionId = buf;
282 -        server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
283 -    }
284 -
285 -    return server->sessionId;
286 -}
287 -
288 -
289  static tr_bool
290  test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
291  {
292 @@ -567,6 +622,10 @@
293          {
294              handle_clutch( req, server );
295          }
296 +        else if( !strncmp( req->uri, "/transmission/upload", 20 ) )
297 +        {
298 +            handle_upload( req, server );
299 +        }
300  #ifdef REQUIRE_SESSION_ID
301          else if( !test_session_id( server, req ) )
302          {
303 @@ -593,10 +652,6 @@
304          {
305              handle_rpc( req, server );
306          }
307 -        else if( !strncmp( req->uri, "/transmission/upload", 20 ) )
308 -        {
309 -            handle_upload( req, server );
310 -        }
311          else
312          {
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 @@
319                         } else {
320                                 args.url = '/transmission/upload?paused=' + (this[Prefs._AutoStart] ? 'false' : 'true');
321                                 args.type = 'POST';
322 +                               args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
323                                 args.dataType = 'xml';
324                                 args.iframe = true;
325                                 args.success = function( data ) {