transmission/files/webupload.patch : add missing patch
authorGraeme Gregory <dp@xora.org.uk>
Sat, 23 May 2009 20:48:29 +0000 (21:48 +0100)
committerGraeme Gregory <dp@xora.org.uk>
Sat, 23 May 2009 20:48:29 +0000 (21:48 +0100)
recipes/transmission/files/webupload.patch [new file with mode: 0644]

diff --git a/recipes/transmission/files/webupload.patch b/recipes/transmission/files/webupload.patch
new file mode 100644 (file)
index 0000000..66d80a1
--- /dev/null
@@ -0,0 +1,325 @@
+Patch is extracted from transmission svn to already applied upstream
+
+Index: libtransmission/rpc-server.c
+===================================================================
+--- libtransmission/rpc-server.c       (revision 8399)
++++ libtransmission/rpc-server.c       (revision 8400)
+@@ -32,6 +32,7 @@
+ #include "crypto.h"
+ #include "list.h"
+ #include "platform.h"
++#include "ptrarray.h"
+ #include "rpcimpl.h"
+ #include "rpc-server.h"
+ #include "trevent.h"
+@@ -83,6 +84,36 @@
+     } while( 0 )
++/***
++****
++***/
++
++static char*
++get_current_session_id( struct tr_rpc_server * server )
++{
++    const time_t now = time( NULL );
++
++    if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
++    {
++        int i;
++        const int n = 48;
++        const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
++        const size_t pool_size = strlen( pool );
++        char * buf = tr_new( char, n+1 );
++
++        for( i=0; i<n; ++i )
++            buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
++        buf[n] = '\0';
++
++        tr_free( server->sessionId );
++        server->sessionId = buf;
++        server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
++    }
++
++    return server->sessionId;
++}
++
++
+ /**
+ ***
+ **/
+@@ -104,10 +135,8 @@
+ }
+ static const char*
+-tr_memmem( const char * s1,
+-           size_t       l1,
+-           const char * s2,
+-           size_t       l2 )
++tr_memmem( const char * s1, size_t l1, /* haystack */
++           const char * s2, size_t l2 ) /* needle */
+ {
+     if( !l2 ) return s1;
+     while( l1 >= l2 )
+@@ -121,7 +150,68 @@
+     return NULL;
+ }
++struct tr_mimepart
++{
++    char * headers;
++    int headers_len;
++    char * body;
++    int body_len;
++};
++
+ static void
++tr_mimepart_free( struct tr_mimepart * p )
++{
++    tr_free( p->body );
++    tr_free( p->headers );
++    tr_free( p );
++}
++
++static void
++extract_parts_from_multipart( const struct evkeyvalq * headers,
++                              const struct evbuffer * body,
++                              tr_ptrArray * setme_parts )
++{
++    const char * content_type = evhttp_find_header( headers, "Content-Type" );
++    const char * in = (const char*) EVBUFFER_DATA( body );
++    size_t inlen = EVBUFFER_LENGTH( body );
++
++    const char * boundary_key = "boundary=";
++    const char * boundary_key_begin = strstr( content_type, boundary_key );
++    const char * boundary_val = boundary_key_begin ? boundary_key_begin + strlen( boundary_key ) : "arglebargle";
++    char * boundary = tr_strdup_printf( "--%s", boundary_val );
++    const size_t boundary_len = strlen( boundary );
++
++    const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
++    while( delim )
++    {
++        size_t part_len;
++        const char * part = delim + boundary_len;
++
++        inlen -= ( part - in );
++        in = part;
++
++        delim = tr_memmem( in, inlen, boundary, boundary_len );
++        part_len = delim ? (size_t)( delim - part ) : inlen;
++
++        if( part_len )
++        {
++            const char * rnrn = tr_memmem( part, part_len, "\r\n\r\n", 4 );
++            if( rnrn )
++            {
++                struct tr_mimepart * p = tr_new( struct tr_mimepart, 1 );
++                p->headers_len = rnrn - part;
++                p->headers = tr_strndup( part, p->headers_len );
++                p->body_len = (part+part_len) - (rnrn + 4);
++                p->body = tr_strndup( rnrn+4, p->body_len );
++                tr_ptrArrayAppend( setme_parts, p );
++            }
++        }
++    }
++
++    tr_free( boundary );
++}
++
++static void
+ handle_upload( struct evhttp_request * req,
+                struct tr_rpc_server *  server )
+ {
+@@ -131,76 +221,67 @@
+     }
+     else
+     {
+-        const char * content_type = evhttp_find_header( req->input_headers,
+-                                                        "Content-Type" );
++        int i;
++        int n;
++        tr_bool hasSessionId = FALSE;
++        tr_ptrArray parts = TR_PTR_ARRAY_INIT;
+         const char * query = strchr( req->uri, '?' );
+-        const int    paused = query && strstr( query + 1, "paused=true" );
++        const tr_bool paused = query && strstr( query + 1, "paused=true" );
+-        const char * in = (const char *) EVBUFFER_DATA( req->input_buffer );
+-        size_t       inlen = EVBUFFER_LENGTH( req->input_buffer );
++        extract_parts_from_multipart( req->input_headers, req->input_buffer, &parts );
++        n = tr_ptrArraySize( &parts );
+-        const char * boundary_key = "boundary=";
+-        const char * boundary_key_begin = strstr( content_type,
+-                                                  boundary_key );
+-        const char * boundary_val =
+-            boundary_key_begin ? boundary_key_begin +
+-            strlen( boundary_key ) : "arglebargle";
++        /* first look for the session id */
++        for( i=0; i<n; ++i ) {
++            struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
++            if( tr_memmem( p->headers, p->headers_len, TR_RPC_SESSION_ID_HEADER, strlen( TR_RPC_SESSION_ID_HEADER ) ) )
++                break;
++        }
++        if( i<n ) {
++            const struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
++            const char * ours = get_current_session_id( server );
++            const int ourlen = strlen( ours );
++            hasSessionId = ourlen<=p->body_len && !memcmp( p->body, ours, ourlen );
++        }
+-        char *       boundary = tr_strdup_printf( "--%s", boundary_val );
+-        const size_t boundary_len = strlen( boundary );
+-
+-        const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
+-        while( delim )
++        if( !hasSessionId )
+         {
+-            size_t       part_len;
+-            const char * part = delim + boundary_len;
+-            inlen -= ( part - in );
+-            in = part;
+-            delim = tr_memmem( in, inlen, boundary, boundary_len );
+-            part_len = delim ? (size_t)( delim - part ) : inlen;
+-
+-            if( part_len )
++            send_simple_response( req, 409, NULL );
++        }
++        else for( i=0; i<n; ++i )
++        {
++            struct tr_mimepart * p = tr_ptrArrayNth( &parts, i );
++            if( strstr( p->headers, "filename=\"" ) )
+             {
+-                char * text = tr_strndup( part, part_len );
+-                if( strstr( text, "filename=\"" ) )
+-                {
+-                    const char * body = strstr( text, "\r\n\r\n" );
+-                    if( body )
+-                    {
+-                        char * b64;
+-                        size_t  body_len;
+-                        tr_benc top, *args;
+-                        struct evbuffer * json = tr_getBuffer( );
++                char * b64;
++                int body_len = p->body_len;
++                tr_benc top, *args;
++                const char * body = p->body;
++                struct evbuffer * json = evbuffer_new( );
+-                        body += 4; /* walk past the \r\n\r\n */
+-                        body_len = part_len - ( body - text );
+-                        if( body_len >= 2
+-                          && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
+-                            body_len -= 2;
++                if( body_len >= 2 && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
++                    body_len -= 2;
+-                        tr_bencInitDict( &top, 2 );
+-                        args = tr_bencDictAddDict( &top, "arguments", 2 );
+-                        tr_bencDictAddStr( &top, "method", "torrent-add" );
+-                        b64 = tr_base64_encode( body, body_len, NULL );
+-                        tr_bencDictAddStr( args, "metainfo", b64 );
+-                        tr_bencDictAddBool( args, "paused", paused );
+-                        tr_bencSaveAsJSON( &top, json );
+-                        tr_rpc_request_exec_json( server->session,
+-                                                  EVBUFFER_DATA( json ),
+-                                                  EVBUFFER_LENGTH( json ),
+-                                                  NULL, NULL );
++                tr_bencInitDict( &top, 2 );
++                args = tr_bencDictAddDict( &top, "arguments", 2 );
++                tr_bencDictAddStr( &top, "method", "torrent-add" );
++                b64 = tr_base64_encode( body, body_len, NULL );
++                tr_bencDictAddStr( args, "metainfo", b64 );
++                tr_bencDictAddBool( args, "paused", paused );
++                tr_bencSaveAsJSON( &top, json );
++                tr_rpc_request_exec_json( server->session,
++                                          EVBUFFER_DATA( json ),
++                                          EVBUFFER_LENGTH( json ),
++                                          NULL, NULL );
+-                        tr_releaseBuffer( json );
+-                        tr_free( b64 );
+-                        tr_bencFree( &top );
+-                    }
+-                }
+-                tr_free( text );
++                evbuffer_free( json );
++                tr_free( b64 );
++                tr_bencFree( &top );
+             }
+         }
+-        tr_free( boundary );
++        tr_ptrArrayDestruct( &parts, (PtrArrayForeachFunc)tr_mimepart_free );
+         /* use xml here because json responses to file uploads is trouble.
+          * see http://www.malsup.com/jquery/form/#sample7 for details */
+@@ -473,32 +554,6 @@
+     return FALSE;
+ }
+-static char*
+-get_current_session_id( struct tr_rpc_server * server )
+-{
+-    const time_t now = time( NULL );
+-
+-    if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
+-    {
+-        int i;
+-        const int n = 48;
+-        const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+-        const size_t pool_size = strlen( pool );
+-        char * buf = tr_new( char, n+1 );
+-
+-        for( i=0; i<n; ++i )
+-            buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
+-        buf[n] = '\0';
+-
+-        tr_free( server->sessionId );
+-        server->sessionId = buf;
+-        server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
+-    }
+-
+-    return server->sessionId;
+-}
+-
+-
+ static tr_bool
+ test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
+ {
+@@ -567,6 +622,10 @@
+         {
+             handle_clutch( req, server );
+         }
++        else if( !strncmp( req->uri, "/transmission/upload", 20 ) )
++        {
++            handle_upload( req, server );
++        }
+ #ifdef REQUIRE_SESSION_ID
+         else if( !test_session_id( server, req ) )
+         {
+@@ -593,10 +652,6 @@
+         {
+             handle_rpc( req, server );
+         }
+-        else if( !strncmp( req->uri, "/transmission/upload", 20 ) )
+-        {
+-            handle_upload( req, server );
+-        }
+         else
+         {
+             send_simple_response( req, HTTP_NOTFOUND, req->uri );
+Index: web/javascript/transmission.js
+===================================================================
+--- web/javascript/transmission.js     (revision 8399)
++++ web/javascript/transmission.js     (revision 8400)
+@@ -1247,6 +1247,7 @@
+                       } else {
+                               args.url = '/transmission/upload?paused=' + (this[Prefs._AutoStart] ? 'false' : 'true');
+                               args.type = 'POST';
++                              args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
+                               args.dataType = 'xml';
+                               args.iframe = true;
+                               args.success = function( data ) {