Changeset 5860


Ignore:
Timestamp:
May 20, 2008, 5:33:54 PM (14 years ago)
Author:
charles
Message:

(1) RPC "add-torrent" now lets clients embed base64-encoded metainfo directly into the request
(2) remove the RISON code; it didn't make the final cut
(3) add base64 encode/decode utilities and unit tests

Location:
trunk
Files:
1 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/daemon/remote.c

    r5857 r5860  
    101101}
    102102
     103static char*
     104getEncodedMetainfo( const char * filename )
     105{
     106    size_t len;
     107    uint8_t * buf = tr_loadFile( filename, &len );
     108    char * b64 = tr_base64_encode( buf, len, NULL );
     109    tr_free( buf );
     110    return b64;
     111}
     112
    103113static void
    104114readargs( int argc, char ** argv )
     
    133143    while((( opt = getopt_long( argc, argv, optstr, longopts, NULL ))) != -1 )
    134144    {
     145        char * tmp;
    135146        char buf[MAX_PATH_LENGTH];
    136147        tr_benc top, *args;
    137148        tr_bencInitDict( &top, 3 );
    138         args = tr_bencDictAddDict( &top, "args", 0 );
     149        args = tr_bencDictAddDict( &top, "arguments", 0 );
    139150
    140151        switch( opt )
     
    143154            case 'h': showUsage( ); break;
    144155            case 'a': tr_bencDictAddStr( &top, "method", "torrent-add" );
    145                       tr_bencDictAddStr( args, "filename", optarg );
     156                      tr_bencDictAddStr( args, "metainfo", ((tmp=getEncodedMetainfo(optarg))) );
     157                      tr_free( tmp );
    146158                      break;
    147159            case 'c': tr_bencDictAddStr( &top, "method", "session-set" );
  • trunk/doc/rpc-spec.txt

    r5843 r5860  
    159159   "download-dir"     | string    path to download the torrent to
    160160   "filename"         | string    location of the .torrent file
     161   "metainfo"         | string    base64-encoded .torrent content
    161162   "paused"           | boolean   if true, don't start the torrent
    162163   "peer-limit"       | int       maximum number of peers
    163164
    164    The "filename" argument is required; all others are optional.
     165   Either "filename" OR "metainfo" must be included.
     166   All other arguments are optional.
    165167
    166168   Response arguments: on success, a "torrent-added" object in the
  • trunk/libtransmission/JSON_checker.c

    r5810 r5860  
    386386        if (jc->parse_buffer == &jc->static_parse_buffer[0]) {
    387387            jc->parse_buffer = (char*)malloc(jc->parse_buffer_capacity * sizeof(jc->parse_buffer[0]));
     388            memcpy( jc->parse_buffer, jc->static_parse_buffer, jc->parse_buffer_count );
    388389        } else {
    389390            jc->parse_buffer = (char*)realloc(jc->parse_buffer, jc->parse_buffer_capacity * sizeof(jc->parse_buffer[0]));
  • trunk/libtransmission/Makefile.am

    r5843 r5860  
    55
    66libtransmission_a_SOURCES = \
    7     ConvertUTF.c \
    8     JSON_checker.c \
    97    bencode.c \
    108    blocklist.c \
    119    clients.c \
    1210    completion.c \
     11    ConvertUTF.c \
    1312    crypto.c \
    1413    fastresume.c \
     
    1817    inout.c \
    1918    json.c \
     19    JSON_checker.c \
    2020    list.c \
    2121    makemeta.c \
     
    4646
    4747noinst_HEADERS = \
    48     ConvertUTF.h \
    49     JSON_checker.h \
    5048    bencode.h \
    5149    blocklist.h \
    5250    clients.h \
     51    ConvertUTF.h \
    5352    crypto.h \
    5453    completion.h \
     
    5958    inout.h \
    6059    json.h \
     60    JSON_checker.h \
    6161    list.h \
    6262    makemeta.h \
     
    9393    json-test \
    9494    test-fastset \
    95     test-peer-id
     95    test-peer-id \
     96    utils-test
    9697
    9798noinst_PROGRAMS = $(TESTS)
     
    121122test_peer_id_SOURCES = test-peer-id.c
    122123test_peer_id_LDADD = $(APPS_LDADD)
     124utils_test_SOURCES = utils-test.c
     125utils_test_LDADD = $(APPS_LDADD)
    123126
    124127
  • trunk/libtransmission/bencode-test.c

    r5843 r5860  
    273273
    274274static int
    275 testRISONSnippet( const char * rison_str, const char * expected )
    276 {
    277     char * serialized = tr_rison2json( rison_str, -1 );
    278 #if 0
    279 fprintf( stderr, " expected: [%s]\n", expected );
    280 fprintf( stderr, "      got: [%s]\n", serialized );
    281 #endif
    282     check( !strcmp( serialized, expected ) );
    283     tr_free( serialized );
    284     return 0;
    285 }
    286 
    287 static int
    288 testRISON( void )
    289 {
    290     int val;
    291     const char * rison;
    292     const char * expected;
    293 
    294     rison = "(a:0,b:foo,c:'23skidoo')";
    295     expected = "{ \"a\": 0, \"b\": \"foo\", \"c\": \"23skidoo\" }";
    296     if(( val = testRISONSnippet( rison, expected )))
    297         return val;
    298 
    299     rison = "(method:torrent-info)";
    300     expected = "{ \"method\": \"torrent-info\" }";
    301     if(( val = testRISONSnippet( rison, expected )))
    302         return val;
    303 
    304     return 0;
    305 }
    306 
    307 static int
    308275testJSONSnippet( const char * benc_str, const char * expected )
    309276{
     
    406373        return i;
    407374
    408     if(( i = testRISON( )))
    409         return i;
    410 
    411375    if(( i = testStackSmash( )))
    412376        return i;
  • trunk/libtransmission/bencode.h

    r5843 r5860  
    9191int    tr_bencInitStrDup( tr_benc * val, const char * str );
    9292void   tr_bencInitRaw( tr_benc * val, const void * src, size_t byteCount );
    93 int    tr_bencInitStrDupLen( tr_benc * val, const char * str, int len );
    9493void   tr_bencInitInt( tr_benc * val, int64_t num );
    9594int   tr_bencInitDict( tr_benc * val, int reserveCount );
  • trunk/libtransmission/json.c

    r5843 r5860  
    148148    return err;
    149149}
    150 
    151 /***
    152 **** RISON-to-JSON converter
    153 ***/
    154 
    155 enum { ESCAPE,
    156        STRING_BEGIN,
    157        STRING, ESCAPE_STRING,
    158        UNQUOTED_STRING, ESCAPE_UNQUOTED_STRING,
    159        VAL_BEGIN,
    160        OTHER };
    161 
    162 char*
    163 tr_rison2json( const char * str, int rison_len )
    164 {
    165     struct evbuffer * out = evbuffer_new( );
    166     int stack[1000], *parents=stack;
    167     int mode = OTHER;
    168     char * ret;
    169     const char * end;
    170 
    171     if( rison_len < 0 )
    172         end = str + strlen( str );
    173     else
    174         end = str + rison_len;
    175 
    176 #define IN_OBJECT ((parents!=stack) && (parents[-1]=='}'))
    177 
    178     for( ; str!=end; ++str )
    179     {
    180         if( mode == ESCAPE )
    181         {
    182             switch( *str )
    183             {
    184                 case '(': evbuffer_add_printf( out, "[ " ); *parents++ = ']'; break;
    185                 case 't': evbuffer_add_printf( out, " true" ); break;
    186                 case 'f': evbuffer_add_printf( out, " false" ); break;
    187                 case 'n': evbuffer_add_printf( out, " null" ); break;
    188                 default: fprintf( stderr, "invalid escape sequence!\n" ); break;
    189             }
    190             mode = OTHER;
    191         }
    192         else if( mode == STRING_BEGIN )
    193         {
    194             switch( *str )
    195             {
    196                 case '\'': evbuffer_add_printf( out, "\"" ); mode = STRING; break;
    197                 case ')': evbuffer_add_printf( out, " %c", *--parents ); mode = OTHER; break;
    198                 default: evbuffer_add_printf( out, "\"%c", *str ); mode = UNQUOTED_STRING; break;
    199             }
    200         }
    201         else if( mode == UNQUOTED_STRING )
    202         {
    203             switch( *str )
    204             {
    205                 case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
    206                 case ':': evbuffer_add_printf( out, "\": "); mode = VAL_BEGIN; break;
    207                 case '!': mode = ESCAPE_UNQUOTED_STRING; break;
    208                 case ')': if( IN_OBJECT ) { evbuffer_add_printf( out, "\" }"); mode = OTHER; break; }
    209                 case ',': if( IN_OBJECT ) { evbuffer_add_printf( out, "\", "); mode = STRING_BEGIN; break; }
    210                           /* fallthrough */
    211                 default: evbuffer_add_printf( out, "%c", *str ); break;
    212             }
    213         }
    214         else if( mode == VAL_BEGIN )
    215         {
    216             if( *str == '\'' ) { evbuffer_add_printf( out, "\"" ); mode = STRING; }
    217             else if( isdigit( *str ) ) { evbuffer_add_printf( out, "%c", *str ); mode = OTHER; }
    218             else { evbuffer_add_printf( out, "\"%c", *str ); mode = UNQUOTED_STRING; }
    219         }
    220         else if( mode == STRING )
    221         {
    222             switch( *str )
    223             {
    224                 case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
    225                 case '!': mode = ESCAPE_STRING; break;
    226                 default: evbuffer_add_printf( out, "%c", *str ); break;
    227             }
    228         }
    229         else if( mode == ESCAPE_STRING || mode == ESCAPE_UNQUOTED_STRING )
    230         {
    231             switch( *str )
    232             {
    233                 case '!': evbuffer_add_printf( out, "!" ); break;
    234                 case '\'': evbuffer_add_printf( out, "'" ); break;
    235                 default: fprintf( stderr, "invalid string escape sequence\n" ); break;
    236             }
    237             if( mode == ESCAPE_UNQUOTED_STRING ) mode = UNQUOTED_STRING;
    238             if( mode == ESCAPE_STRING ) mode = STRING;
    239         }
    240         else
    241         {
    242             switch( *str )
    243             {
    244                 case '(': evbuffer_add_printf( out, "{ " ); mode=STRING_BEGIN; *parents++ = '}'; break;
    245                 case '!': mode = ESCAPE; break;
    246                 case ')': evbuffer_add_printf( out, " %c", *--parents ); break;
    247                 case '\'': evbuffer_add_printf( out, "\"" ); mode = STRING; break;
    248                 case ':': if( IN_OBJECT ) {
    249                               evbuffer_add_printf( out, ": " ); mode = VAL_BEGIN;
    250                           } else {
    251                               evbuffer_add_printf( out, "%c", *str );
    252                           }
    253                           break;
    254                 case ',': if( IN_OBJECT ) {
    255                               evbuffer_add_printf( out, ", " ); mode = STRING_BEGIN;
    256                           } else {
    257                               evbuffer_add_printf( out, "%c", *str );
    258                           }
    259                           break;
    260                 default: evbuffer_add_printf( out, "%c", *str ); break;
    261             }
    262         }
    263     }
    264 
    265     ret = tr_strdup( (char*) EVBUFFER_DATA( out ) );
    266     evbuffer_free( out );
    267     return ret;
    268 }
  • trunk/libtransmission/json.h

    r5843 r5860  
    1818                  const uint8_t   ** setme_end );
    1919
    20 char* tr_rison2json( const char    * rison,
    21                      int             rison_len );
    22 
    2320#endif
  • trunk/libtransmission/rpc-server.c

    r5855 r5860  
    6767
    6868        evbuffer_add_printf( s->out, "HTTP/1.1 200 OK\r\n"
    69                                      "Content-Type: text/x-json\r\n"
     69                                     "Content-Type: application/json\r\n"
    7070                                     "Content-Length: %d\r\n"
    7171                                     "\r\n"
  • trunk/libtransmission/rpc.c

    r5843 r5860  
    528528torrentAdd( tr_handle * h, tr_benc * args_in, tr_benc * args_out )
    529529{
    530     const char * filename;
    531     if( !tr_bencDictFindStr( args_in, "filename", &filename ) )
    532         return "no filename specified";
     530    const char * filename = NULL;
     531    const char * metainfo_base64 = NULL;
     532    tr_bencDictFindStr( args_in, "filename", &filename );
     533    tr_bencDictFindStr( args_in, "metainfo", &metainfo_base64 );
     534    if( !filename && !metainfo_base64 )
     535        return "no filename or metainfo specified";
    533536    else
    534537    {
     
    540543
    541544        ctor = tr_ctorNew( h );
    542         tr_ctorSetMetainfoFromFile( ctor, filename );
     545
     546        /* set the metainfo */
     547        if( filename )
     548            tr_ctorSetMetainfoFromFile( ctor, filename );
     549        else {
     550            int len;
     551            char * metainfo = tr_base64_decode( metainfo_base64, -1,  &len );
     552            tr_ctorSetMetainfo( ctor, (uint8_t*)metainfo, len );
     553            tr_free( metainfo );
     554        }
     555
     556        /* set the optional arguments */
    543557        if( tr_bencDictFindStr( args_in, "download-dir", &str ) )
    544558            tr_ctorSetDownloadDir( ctor, TR_FORCE, str );
     
    547561        if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
    548562            tr_ctorSetPeerLimit( ctor, TR_FORCE, i );
     563
    549564        tor = tr_torrentNew( h, ctor, &err );
    550565        tr_ctorFree( ctor );
  • trunk/libtransmission/utils.c

    r5843 r5860  
    602602        out[len] = '\0';
    603603    }
     604
    604605    return out;
    605606}
     
    10151016    return err;
    10161017}
     1018
     1019#include <string.h>
     1020#include <openssl/sha.h>
     1021#include <openssl/hmac.h>
     1022#include <openssl/evp.h>
     1023#include <openssl/bio.h>
     1024#include <openssl/buffer.h>
     1025
     1026char *
     1027tr_base64_encode( const void * input, int length, int * setme_len )
     1028{
     1029    char * ret;
     1030    BIO * b64;
     1031    BIO * bmem;
     1032    BUF_MEM * bptr;
     1033
     1034    if( length < 1 )
     1035       length = strlen( input );
     1036
     1037    bmem = BIO_new( BIO_s_mem( ) );
     1038    b64 = BIO_new( BIO_f_base64( ) );
     1039    b64 = BIO_push( b64, bmem );
     1040    BIO_write( b64, input, length );
     1041    (void) BIO_flush( b64 );
     1042    BIO_get_mem_ptr( b64, &bptr );
     1043    ret = tr_strndup( bptr->data, bptr->length );
     1044    if( setme_len )
     1045        *setme_len = bptr->length;
     1046
     1047    BIO_free_all( b64 );
     1048    return ret;
     1049}
     1050
     1051char *
     1052tr_base64_decode( const void * input, int length, int * setme_len )
     1053{
     1054    char * ret;
     1055    BIO * b64;
     1056    BIO * bmem;
     1057    int retlen;
     1058
     1059    if( length < 1 )
     1060       length = strlen( input );
     1061
     1062    ret = tr_new0( char, length );
     1063    b64 = BIO_new( BIO_f_base64( ) );
     1064    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
     1065    bmem = BIO_push( b64, bmem );
     1066    retlen = BIO_read( bmem, ret, length );
     1067    if( setme_len )
     1068        *setme_len = retlen;
     1069
     1070    BIO_free_all( bmem );
     1071    return ret;
     1072}
  • trunk/libtransmission/utils.h

    r5855 r5860  
    192192char* tr_strndup( const char * str, int len ) TR_GNUC_MALLOC;
    193193char* tr_strdup_printf( const char * fmt, ... )  TR_GNUC_PRINTF( 1, 2 ) TR_GNUC_MALLOC;
     194char* tr_base64_encode( const void * input, int inlen, int *outlen ) TR_GNUC_MALLOC;
     195char* tr_base64_decode( const void * input, int inlen, int *outlen ) TR_GNUC_MALLOC;
     196
    194197size_t tr_strlcpy( char * dst, const char * src, size_t siz );
    195198
Note: See TracChangeset for help on using the changeset viewer.