Changeset 8351
- Timestamp:
- May 8, 2009, 2:37:46 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/daemon/remote.c
r8274 r8351 133 133 static char * auth = NULL; 134 134 static char * netrc = NULL; 135 static char * cookies = NULL; 135 136 136 137 static char* … … 1274 1275 } 1275 1276 1277 /* very basic handling of cookies: when we get Set-Cookie, throw out all 1278 * the previous cookies... T only uses one cookie (session_id) */ 1279 static size_t 1280 parseResponseHeader( void *ptr, size_t size, size_t nmemb, void * stream UNUSED ) 1281 { 1282 const char * line = ptr; 1283 const size_t linelen = size * nmemb; 1284 const char * lineend = line + linelen; 1285 const char * key = "Set-Cookie: "; 1286 const size_t keylen = strlen( key ); 1287 if( ( linelen >= keylen ) && !memcmp( line, key, keylen ) ) { 1288 const char * begin = line + keylen; 1289 const char * end = begin; 1290 while(( end!=lineend ) && !strchr("\r\n",*end)) 1291 ++end; 1292 tr_free( cookies ); 1293 cookies = tr_strndup( begin, end-begin ); 1294 } 1295 1296 return linelen; 1297 } 1298 1299 static CURL* 1300 tr_curl_easy_init( struct evbuffer * writebuf ) 1301 { 1302 CURL * curl = curl_easy_init( ); 1303 curl_easy_setopt( curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING ); 1304 curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeFunc ); 1305 curl_easy_setopt( curl, CURLOPT_WRITEDATA, writebuf ); 1306 curl_easy_setopt( curl, CURLOPT_HEADERFUNCTION, parseResponseHeader ); 1307 curl_easy_setopt( curl, CURLOPT_POST, 1 ); 1308 curl_easy_setopt( curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL ); 1309 curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY ); 1310 curl_easy_setopt( curl, CURLOPT_TIMEOUT, 60L ); 1311 curl_easy_setopt( curl, CURLOPT_VERBOSE, debug ); 1312 #ifdef HAVE_ZLIB 1313 curl_easy_setopt( curl, CURLOPT_ENCODING, "deflate" ); 1314 #endif 1315 if( cookies ) 1316 curl_easy_setopt( curl, CURLOPT_COOKIE, cookies ); 1317 if( netrc ) 1318 curl_easy_setopt( curl, CURLOPT_NETRC_FILE, netrc ); 1319 if( auth ) 1320 curl_easy_setopt( curl, CURLOPT_USERPWD, auth ); 1321 return curl; 1322 } 1323 1324 1276 1325 static void 1277 1326 processRequests( const char * host, … … 1280 1329 int reqCount ) 1281 1330 { 1282 int 1283 CURL * curl;1331 int i; 1332 CURL * curl = NULL; 1284 1333 struct evbuffer * buf = evbuffer_new( ); 1285 char * url = tr_strdup_printf( 1286 "http://%s:%d/transmission/rpc", host, port ); 1287 1288 curl = curl_easy_init( ); 1289 curl_easy_setopt( curl, CURLOPT_VERBOSE, debug ); 1290 #ifdef HAVE_ZLIB 1291 curl_easy_setopt( curl, CURLOPT_ENCODING, "deflate" ); 1292 #endif 1293 curl_easy_setopt( curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING ); 1294 curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeFunc ); 1295 curl_easy_setopt( curl, CURLOPT_WRITEDATA, buf ); 1296 curl_easy_setopt( curl, CURLOPT_POST, 1 ); 1297 curl_easy_setopt( curl, CURLOPT_URL, url ); 1298 curl_easy_setopt( curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL ); 1299 curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY ); 1300 curl_easy_setopt( curl, CURLOPT_TIMEOUT, 60L ); 1301 if( netrc ) 1302 curl_easy_setopt( curl, CURLOPT_NETRC_FILE, netrc ); 1303 if( auth ) 1304 curl_easy_setopt( curl, CURLOPT_USERPWD, auth ); 1305 1306 for( i = 0; i < reqCount; ++i ) 1334 char * url = tr_strdup_printf( "http://%s:%d/transmission/rpc", host, port ); 1335 1336 for( i=0; i<reqCount; ++i ) 1307 1337 { 1308 1338 CURLcode res; 1339 evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) ); 1340 1341 if( curl == NULL ) 1342 { 1343 curl = tr_curl_easy_init( buf ); 1344 curl_easy_setopt( curl, CURLOPT_URL, url ); 1345 } 1346 1309 1347 curl_easy_setopt( curl, CURLOPT_POSTFIELDS, reqs[i] ); 1348 1310 1349 if( debug ) 1311 1350 fprintf( stderr, "posting:\n--------\n%s\n--------\n", reqs[i] ); 1312 1351 if( ( res = curl_easy_perform( curl ) ) ) 1313 tr_nerr( MY_NAME, "(%s:%d) %s", host, port, 1314 curl_easy_strerror( res ) ); 1315 else 1316 processResponse( host, port, EVBUFFER_DATA( 1317 buf ), EVBUFFER_LENGTH( buf ) ); 1318 1319 evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) ); 1352 tr_nerr( MY_NAME, "(%s:%d) %s", host, port, curl_easy_strerror( res ) ); 1353 else { 1354 long response; 1355 curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response ); 1356 switch( response ) { 1357 case 200: 1358 processResponse( host, port, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) ); 1359 break; 1360 case 409: 1361 /* session_id cookie expired. by the time we reach line this our 1362 * curl header func has already found the new session_id, so make 1363 * a new CURL* and try again... */ 1364 curl_easy_cleanup( curl ); 1365 curl = NULL; 1366 --i; 1367 break; 1368 default: 1369 fprintf( stderr, "Unexpected response: %s\n", (char*)EVBUFFER_DATA(buf) ); 1370 break; 1371 } 1372 } 1320 1373 } 1321 1374 … … 1323 1376 tr_free( url ); 1324 1377 evbuffer_free( buf ); 1325 curl_easy_cleanup( curl ); 1378 if( curl != NULL ) 1379 curl_easy_cleanup( curl ); 1326 1380 } 1327 1381 -
trunk/libtransmission/rpc-server.c
r8340 r8351 57 57 struct evhttp * httpd; 58 58 tr_session * session; 59 char * sessionId; 59 60 char * username; 60 61 char * password; … … 451 452 } 452 453 453 static void 454 handle_request( struct evhttp_request * req, 455 void * arg ) 454 static char* 455 session_id_new( void ) 456 { 457 int i; 458 const int n = 48; 459 const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 460 const size_t pool_size = strlen( pool ); 461 char * buf = tr_new( char, n+1 ); 462 for( i=0; i<n; ++i ) 463 buf[i] = pool[ tr_cryptoRandInt( pool_size ) ]; 464 buf[n] = '\0'; 465 return buf; 466 } 467 468 static tr_bool 469 test_session_id( struct tr_rpc_server * server, struct evhttp_request * req ) 470 { 471 char * needle = tr_strdup_printf( "session_id=%s", server->sessionId ); 472 const char * haystack = evhttp_find_header( req->input_headers, "Cookie" ); 473 const tr_bool success = (haystack!=NULL) && (strstr(haystack,needle)!=NULL); 474 tr_free( needle ); 475 return success; 476 } 477 478 static void 479 handle_request( struct evhttp_request * req, void * arg ) 456 480 { 457 481 struct tr_rpc_server * server = arg; … … 460 484 { 461 485 const char * auth; 462 char * user = NULL; 463 char * pass = NULL; 486 char * user = NULL; 487 char * pass = NULL; 488 char * cookie; 464 489 465 490 evhttp_add_header( req->output_headers, "Server", MY_REALM ); 491 cookie = tr_strdup_printf( "session_id=%s;Path=/;Discard", server->sessionId ); 492 evhttp_add_header( req->output_headers, "Set-Cookie", cookie ); 493 tr_free( cookie ); 466 494 467 495 auth = evhttp_find_header( req->input_headers, "Authorization" ); 468 469 496 if( auth && !strncasecmp( auth, "basic ", 6 ) ) 470 497 { … … 480 507 if( !isAddressAllowed( server, req->remote_host ) ) 481 508 { 482 send_simple_response( req, 40 1,509 send_simple_response( req, 403, 483 510 "<p>Unauthorized IP Address.</p>" 484 511 "<p>Either disable the IP address whitelist or add your address to it.</p>" … … 511 538 { 512 539 handle_clutch( req, server ); 540 } 541 else if( !test_session_id( server, req ) ) 542 { 543 send_simple_response( req, 409, "<p>Invalid session_id cookie.</p>" ); 513 544 } 514 545 else if( !strncmp( req->uri, "/transmission/rpc", 17 ) ) … … 767 798 s = tr_new0( tr_rpc_server, 1 ); 768 799 s->session = session; 800 s->sessionId = session_id_new( ); 769 801 770 802 found = tr_bencDictFindBool( settings, TR_PREFS_KEY_RPC_ENABLED, &boolVal ); -
trunk/qt/session.cc
r8334 r8351 542 542 header.setValue( "User-Agent", QCoreApplication::instance()->applicationName() + "/" + LONG_VERSION_STRING ); 543 543 header.setValue( "Content-Type", "application/json; charset=UTF-8" ); 544 myHttp.request( header, data, &myBuffer ); 544 if( !myCookies.isEmpty( ) ) 545 header.setValue( "Cookie", myCookies ); 546 QBuffer * buf = new QBuffer; 547 buf->setData( data ); 548 myHttp.request( header, buf, &myBuffer ); 545 549 #ifdef DEBUG_HTTP 546 550 std::cerr << "sending " << qPrintable(header.toString()) << "\nBody:\n" << request << std::endl; … … 561 565 { 562 566 Q_UNUSED( id ); 567 568 QHttpResponseHeader response = myHttp.lastResponse(); 569 QIODevice * sourceDevice = myHttp.currentSourceDevice( ); 563 570 564 571 #ifdef DEBUG_HTTP … … 570 577 #endif 571 578 572 if( error ) 579 // very basic handling of cookies: when we get Set-Cookie, throw out all 580 // the previous cookies... T only uses one cookie (session_id) 581 const QString responseCookies = response.value( "Set-Cookie" ); 582 if( !responseCookies.isEmpty( ) ) 583 myCookies = responseCookies; 584 585 if( response.statusCode() == 409 ) 586 { 587 // we got a 409 telling us our session cookie has expired. 588 // now that we've updated our cookie, try again. 589 exec( qobject_cast<QBuffer*>(sourceDevice)->buffer().constData( ) ); 590 } 591 else if( error ) 592 { 573 593 std::cerr << "http error: " << qPrintable(myHttp.errorString()) << std::endl; 574 else { 594 } 595 else 596 { 575 597 const QByteArray& response( myBuffer.buffer( ) ); 576 598 const char * json( response.constData( ) ); 577 599 int jsonLength( response.size( ) ); 578 600 if( jsonLength>0 && json[jsonLength-1] == '\n' ) --jsonLength; 579 580 601 parseResponse( json, jsonLength ); 581 602 } 582 603 604 delete sourceDevice; 583 605 myBuffer.buffer( ).clear( ); 584 606 myBuffer.reset( ); -
trunk/qt/session.h
r8345 r8351 133 133 tr_session * mySession; 134 134 QString myConfigDir; 135 QString myCookies; 135 136 QUrl myUrl; 136 137 QBuffer myBuffer;
Note: See TracChangeset
for help on using the changeset viewer.