static int test_memmem (void) { char const haystack[12] = "abcabcabcabc"; char const needle[3] = "cab"; check (tr_memmem (haystack, sizeof haystack, haystack, sizeof haystack) == haystack); check (tr_memmem (haystack, sizeof haystack, needle, sizeof needle) == haystack + 2); check (tr_memmem (needle, sizeof needle, haystack, sizeof haystack) == NULL); return 0; }
static void extract_parts_from_multipart (const struct evkeyvalq * headers, struct evbuffer * body, tr_ptrArray * setme_parts) { const char * content_type = evhttp_find_header (headers, "Content-Type"); const char * in = (const char*) evbuffer_pullup (body, -1); size_t inlen = evbuffer_get_length (body); const char * boundary_key = "boundary="; const char * boundary_key_begin = content_type ? strstr (content_type, boundary_key) : NULL; 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 = (size_t) (rnrn - part); p->headers = tr_strndup (part, p->headers_len); p->body_len = (size_t) ((part + part_len) - (rnrn + 4)); p->body = tr_strndup (rnrn+4, p->body_len); tr_ptrArrayAppend (setme_parts, p); } } } tr_free (boundary); }
static const char * slice( const char * data, int * len, const char * delim ) { const char *body; int dlen; dlen = strlen( delim ); body = tr_memmem( data, *len, delim, dlen ); if( NULL != body ) { *len = body - data; body += dlen; } return body; }
static void handle_upload (struct evhttp_request * req, struct tr_rpc_server * server) { if (req->type != EVHTTP_REQ_POST) { send_simple_response (req, 405, NULL); } else { int i; int n; bool hasSessionId = false; tr_ptrArray parts = TR_PTR_ARRAY_INIT; const char * query = strchr (req->uri, '?'); const bool paused = query && strstr (query + 1, "paused=true"); extract_parts_from_multipart (req->input_headers, req->input_buffer, &parts); n = tr_ptrArraySize (&parts); /* 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 size_t ourlen = strlen (ours); hasSessionId = ourlen <= p->body_len && memcmp (p->body, ours, ourlen) == 0; } if (!hasSessionId) { int code = 409; const char * codetext = tr_webGetResponseStr (code); struct evbuffer * body = evbuffer_new (); evbuffer_add_printf (body, "%s", "{ \"success\": false, \"msg\": \"Bad Session-Id\" }");; evhttp_send_reply (req, code, codetext, body); evbuffer_free (body); } else for (i=0; i<n; ++i) { struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); size_t body_len = p->body_len; tr_variant top, *args; tr_variant test; bool have_source = false; char * body = p->body; if (body_len >= 2 && memcmp (&body[body_len - 2], "\r\n", 2) == 0) body_len -= 2; tr_variantInitDict (&top, 2); tr_variantDictAddStr (&top, TR_KEY_method, "torrent-add"); args = tr_variantDictAddDict (&top, TR_KEY_arguments, 2); tr_variantDictAddBool (args, TR_KEY_paused, paused); if (tr_urlIsValid (body, body_len)) { tr_variantDictAddRaw (args, TR_KEY_filename, body, body_len); have_source = true; } else if (!tr_variantFromBenc (&test, body, body_len)) { char * b64 = tr_base64_encode (body, body_len, NULL); tr_variantDictAddStr (args, TR_KEY_metainfo, b64); tr_free (b64); have_source = true; } if (have_source) tr_rpc_request_exec_json (server->session, &top, NULL, NULL); tr_variantFree (&top); } tr_ptrArrayDestruct (&parts, (PtrArrayForeachFunc)tr_mimepart_free); /* send "success" response */ { int code = HTTP_OK; const char * codetext = tr_webGetResponseStr (code); struct evbuffer * body = evbuffer_new (); evbuffer_add_printf (body, "%s", "{ \"success\": true, \"msg\": \"Torrent Added\" }");; evhttp_send_reply (req, code, codetext, body); evbuffer_free (body); } } }
static void recvAnswer( tr_tracker_t * tc ) { tr_torrent_t * tor = tc->tor; int ret; int i; benc_val_t beAll; benc_val_t * bePeers, * beFoo; uint8_t * body; int bodylen; if( tc->pos == tc->size ) { tc->size *= 2; tc->buf = realloc( tc->buf, tc->size ); } ret = tr_netRecv( tc->socket, &tc->buf[tc->pos], tc->size - tc->pos ); if( ret & TR_NET_BLOCK ) { return; } if( !( ret & TR_NET_CLOSE ) ) { // printf( "got %d bytes\n", ret ); tc->pos += ret; return; } tr_netClose( tc->socket ); tr_fdSocketClosed( tor->fdlimit, 1 ); // printf( "connection closed, got total %d bytes\n", tc->pos ); tc->status = TC_STATUS_IDLE; tc->dateTry = tr_date(); if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) && 0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) ) { /* We don't have a complete HTTP status line */ tr_inf( "Tracker: incomplete HTTP status line" ); tc->lastAttempt = TC_ATTEMPT_NOREACH; return; } if( '2' != tc->buf[9] ) { /* we didn't get a 2xx status code */ tr_err( "Tracker: invalid HTTP status code: %c%c%c", tc->buf[9], tc->buf[10], tc->buf[11] ); tc->lastAttempt = TC_ATTEMPT_ERROR; return; } /* find the end of the http headers */ body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 ); if( NULL != body ) { body += 4; } /* hooray for trackers that violate the HTTP spec */ else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) || NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) ) { body += 2; } else { tr_err( "Tracker: could not find end of HTTP headers" ); tc->lastAttempt = TC_ATTEMPT_NOREACH; return; } bodylen = tc->pos - (body - tc->buf); /* Find and load the dictionary */ for( i = 0; i < bodylen; i++ ) { if( !tr_bencLoad( &body[i], bodylen - i, &beAll, NULL ) ) { break; } } if( i >= bodylen ) { if( tc->stopped || 0 < tc->newPort ) { tc->lastAttempt = TC_ATTEMPT_OK; goto nodict; } tr_err( "Tracker: no valid dictionary found in answer" ); tc->lastAttempt = TC_ATTEMPT_ERROR; return; } // tr_bencPrint( &beAll ); if( ( bePeers = tr_bencDictFind( &beAll, "failure reason" ) ) ) { tr_err( "Tracker: %s", bePeers->val.s.s ); tor->error |= TR_ETRACKER; snprintf( tor->trackerError, sizeof( tor->trackerError ), "%s", bePeers->val.s.s ); tc->lastAttempt = TC_ATTEMPT_ERROR; goto cleanup; } tor->error &= ~TR_ETRACKER; tc->lastAttempt = TC_ATTEMPT_OK; if( !tc->interval ) { /* Get the tracker interval, ignore it if it is not between 10 sec and 5 mins */ if( !( beFoo = tr_bencDictFind( &beAll, "interval" ) ) || !( beFoo->type & TYPE_INT ) ) { tr_err( "Tracker: no 'interval' field" ); goto cleanup; } tc->interval = beFoo->val.i; tc->interval = MIN( tc->interval, 300 ); tc->interval = MAX( 10, tc->interval ); tr_inf( "Tracker: interval = %d seconds", tc->interval ); } if( ( beFoo = tr_bencDictFind( &beAll, "complete" ) ) && ( beFoo->type & TYPE_INT ) ) { tc->seeders = beFoo->val.i; } if( ( beFoo = tr_bencDictFind( &beAll, "incomplete" ) ) && ( beFoo->type & TYPE_INT ) ) { tc->leechers = beFoo->val.i; } if( tc->seeders + tc->leechers >= 50 ) { tc->hasManyPeers = 1; } if( !( bePeers = tr_bencDictFind( &beAll, "peers" ) ) ) { if( tc->stopped || 0 < tc->newPort ) { goto nodict; } tr_err( "Tracker: no \"peers\" field" ); goto cleanup; } if( bePeers->type & TYPE_LIST ) { char * ip; int port; /* Original protocol */ tr_inf( "Tracker: got %d peers", bePeers->val.l.count ); for( i = 0; i < bePeers->val.l.count; i++ ) { beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "ip" ); if( !beFoo ) continue; ip = beFoo->val.s.s; beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "port" ); if( !beFoo ) continue; port = beFoo->val.i; tr_peerAddOld( tor, ip, port ); } if( bePeers->val.l.count >= 50 ) { tc->hasManyPeers = 1; } } else if( bePeers->type & TYPE_STR ) { struct in_addr addr; in_port_t port; /* "Compact" extension */ if( bePeers->val.s.i % 6 ) { tr_err( "Tracker: \"peers\" of size %d", bePeers->val.s.i ); tr_lockUnlock( &tor->lock ); goto cleanup; } tr_inf( "Tracker: got %d peers", bePeers->val.s.i / 6 ); for( i = 0; i < bePeers->val.s.i / 6; i++ ) { memcpy( &addr, &bePeers->val.s.s[6*i], 4 ); memcpy( &port, &bePeers->val.s.s[6*i+4], 2 ); tr_peerAddCompact( tor, addr, port ); } if( bePeers->val.s.i / 6 >= 50 ) { tc->hasManyPeers = 1; } } nodict: /* Success */ tc->started = 0; tc->completed = 0; tc->dateOk = tr_date(); if( tc->stopped ) { tor->status = TR_STATUS_STOPPED; tc->stopped = 0; } else if( 0 < tc->newPort ) { tc->started = 1; tc->download = tor->downloaded; tc->upload = tor->uploaded; } cleanup: tr_bencFree( &beAll ); }
static void handle_upload( struct evhttp_request * req, struct tr_rpc_server * server ) { if( req->type != EVHTTP_REQ_POST ) { send_simple_response( req, 405, NULL ); } else { const char * content_type = evhttp_find_header( req->input_headers, "Content-Type" ); const char * query = strchr( req->uri, '?' ); const int 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 ); 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 ) { 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( ); 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; 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_bencDictAddInt( 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 ); } } tr_free( boundary ); /* use xml here because json responses to file uploads is trouble. * see http://www.malsup.com/jquery/form/#sample7 for details */ evhttp_add_header( req->output_headers, "Content-Type", "text/xml; charset=UTF-8" ); send_simple_response( req, HTTP_OK, NULL ); } }