static int debug = 0;
static char * auth = NULL;
static char * netrc = NULL;
-static char * cookies = NULL;
static char*
tr_getcwd( void )
}
}
-/* very basic handling of cookies: when we get Set-Cookie, throw out all
- * the previous cookies... T only uses one cookie (session_id) */
-static size_t
-parseResponseHeader( void *ptr, size_t size, size_t nmemb, void * stream UNUSED )
+static void
+processRequests( const char * host,
+ int port,
+ const char ** reqs,
+ int reqCount )
{
- const char * line = ptr;
- const size_t linelen = size * nmemb;
- const char * lineend = line + linelen;
- const char * key = "Set-Cookie: ";
- const size_t keylen = strlen( key );
- if( ( linelen >= keylen ) && !memcmp( line, key, keylen ) ) {
- const char * begin = line + keylen;
- const char * end = begin;
- while(( end!=lineend ) && !strchr("\r\n",*end))
- ++end;
- tr_free( cookies );
- cookies = tr_strndup( begin, end-begin );
- }
-
- return linelen;
-}
+ int i;
+ CURL * curl;
+ struct evbuffer * buf = evbuffer_new( );
+ char * url = tr_strdup_printf(
+ "http://%s:%d/transmission/rpc", host, port );
-static CURL*
-tr_curl_easy_init( struct evbuffer * writebuf )
-{
- CURL * curl = curl_easy_init( );
+ curl = curl_easy_init( );
+ curl_easy_setopt( curl, CURLOPT_VERBOSE, debug );
+#ifdef HAVE_ZLIB
+ curl_easy_setopt( curl, CURLOPT_ENCODING, "deflate" );
+#endif
curl_easy_setopt( curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING );
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeFunc );
- curl_easy_setopt( curl, CURLOPT_WRITEDATA, writebuf );
- curl_easy_setopt( curl, CURLOPT_HEADERFUNCTION, parseResponseHeader );
+ curl_easy_setopt( curl, CURLOPT_WRITEDATA, buf );
curl_easy_setopt( curl, CURLOPT_POST, 1 );
+ curl_easy_setopt( curl, CURLOPT_URL, url );
curl_easy_setopt( curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL );
curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
curl_easy_setopt( curl, CURLOPT_TIMEOUT, 60L );
- curl_easy_setopt( curl, CURLOPT_VERBOSE, debug );
-#ifdef HAVE_ZLIB
- curl_easy_setopt( curl, CURLOPT_ENCODING, "deflate" );
-#endif
- if( cookies )
- curl_easy_setopt( curl, CURLOPT_COOKIE, cookies );
if( netrc )
curl_easy_setopt( curl, CURLOPT_NETRC_FILE, netrc );
if( auth )
curl_easy_setopt( curl, CURLOPT_USERPWD, auth );
- return curl;
-}
-
-static void
-processRequests( const char * host,
- int port,
- const char ** reqs,
- int reqCount )
-{
- int i;
- CURL * curl = NULL;
- struct evbuffer * buf = evbuffer_new( );
- char * url = tr_strdup_printf( "http://%s:%d/transmission/rpc", host, port );
-
- for( i=0; i<reqCount; ++i )
+ for( i = 0; i < reqCount; ++i )
{
CURLcode res;
- evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
-
- if( curl == NULL )
- {
- curl = tr_curl_easy_init( buf );
- curl_easy_setopt( curl, CURLOPT_URL, url );
- }
-
curl_easy_setopt( curl, CURLOPT_POSTFIELDS, reqs[i] );
-
if( debug )
fprintf( stderr, "posting:\n--------\n%s\n--------\n", reqs[i] );
if( ( res = curl_easy_perform( curl ) ) )
- tr_nerr( MY_NAME, "(%s:%d) %s", host, port, curl_easy_strerror( res ) );
- else {
- long response;
- curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response );
- switch( response ) {
- case 200:
- processResponse( host, port, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) );
- break;
- case 409:
- /* session_id cookie expired. by the time we reach line this our
- * curl header func has already found the new session_id, so make
- * a new CURL* and try again... */
- curl_easy_cleanup( curl );
- curl = NULL;
- --i;
- break;
- default:
- fprintf( stderr, "Unexpected response: %s\n", (char*)EVBUFFER_DATA(buf) );
- break;
- }
- }
+ tr_nerr( MY_NAME, "(%s:%d) %s", host, port,
+ curl_easy_strerror( res ) );
+ else
+ processResponse( host, port, EVBUFFER_DATA(
+ buf ), EVBUFFER_LENGTH( buf ) );
+
+ evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
}
/* cleanup */
tr_free( url );
evbuffer_free( buf );
- if( curl != NULL )
- curl_easy_cleanup( curl );
+ curl_easy_cleanup( curl );
}
int
struct in_addr bindAddress;
struct evhttp * httpd;
tr_session * session;
- char * sessionId;
char * username;
char * password;
char * whitelistStr;
return FALSE;
}
-static char*
-session_id_new( void )
-{
- 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';
- return buf;
-}
-
-static tr_bool
-test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
-{
- char * needle = tr_strdup_printf( "session_id=%s", server->sessionId );
- const char * haystack = evhttp_find_header( req->input_headers, "Cookie" );
- const tr_bool success = (haystack!=NULL) && (strstr(haystack,needle)!=NULL);
- tr_free( needle );
- return success;
-}
-
static void
-handle_request( struct evhttp_request * req, void * arg )
+handle_request( struct evhttp_request * req,
+ void * arg )
{
struct tr_rpc_server * server = arg;
if( req && req->evcon )
{
const char * auth;
- char * user = NULL;
- char * pass = NULL;
- char * cookie;
+ char * user = NULL;
+ char * pass = NULL;
evhttp_add_header( req->output_headers, "Server", MY_REALM );
- cookie = tr_strdup_printf( "session_id=%s;Path=/;Discard", server->sessionId );
- evhttp_add_header( req->output_headers, "Set-Cookie", cookie );
- tr_free( cookie );
auth = evhttp_find_header( req->input_headers, "Authorization" );
+
if( auth && !strncasecmp( auth, "basic ", 6 ) )
{
int plen;
if( !isAddressAllowed( server, req->remote_host ) )
{
- send_simple_response( req, 403,
+ send_simple_response( req, 401,
"<p>Unauthorized IP Address.</p>"
"<p>Either disable the IP address whitelist or add your address to it.</p>"
"<p>If you're editing settings.json, see the 'rpc-whitelist' and 'rpc-whitelist-enabled' entries.</p>"
{
handle_clutch( req, server );
}
- else if( !test_session_id( server, req ) )
- {
- send_simple_response( req, 409, "<p>Invalid session_id cookie.</p>" );
- }
else if( !strncmp( req->uri, "/transmission/rpc", 17 ) )
{
handle_rpc( req, server );
s = tr_new0( tr_rpc_server, 1 );
s->session = session;
- s->sessionId = session_id_new( );
found = tr_bencDictFindBool( settings, TR_PREFS_KEY_RPC_ENABLED, &boolVal );
assert( found );
QHttpRequestHeader header( "POST", path );
header.setValue( "User-Agent", QCoreApplication::instance()->applicationName() + "/" + LONG_VERSION_STRING );
header.setValue( "Content-Type", "application/json; charset=UTF-8" );
- if( !myCookies.isEmpty( ) )
- header.setValue( "Cookie", myCookies );
- QBuffer * buf = new QBuffer;
- buf->setData( data );
- myHttp.request( header, buf, &myBuffer );
+ myHttp.request( header, data, &myBuffer );
#ifdef DEBUG_HTTP
std::cerr << "sending " << qPrintable(header.toString()) << "\nBody:\n" << request << std::endl;
#endif
{
Q_UNUSED( id );
- QHttpResponseHeader response = myHttp.lastResponse();
- QIODevice * sourceDevice = myHttp.currentSourceDevice( );
-
#ifdef DEBUG_HTTP
std::cerr << "http request " << id << " ended.. response header: "
<< qPrintable( myHttp.lastResponse().toString() )
<< std::endl;
#endif
- // very basic handling of cookies: when we get Set-Cookie, throw out all
- // the previous cookies... T only uses one cookie (session_id)
- const QString responseCookies = response.value( "Set-Cookie" );
- if( !responseCookies.isEmpty( ) )
- myCookies = responseCookies;
-
- if( response.statusCode() == 409 )
- {
- // we got a 409 telling us our session cookie has expired.
- // now that we've updated our cookie, try again.
- exec( qobject_cast<QBuffer*>(sourceDevice)->buffer().constData( ) );
- }
- else if( error )
- {
+ if( error )
std::cerr << "http error: " << qPrintable(myHttp.errorString()) << std::endl;
- }
- else
- {
+ else {
const QByteArray& response( myBuffer.buffer( ) );
const char * json( response.constData( ) );
int jsonLength( response.size( ) );
if( jsonLength>0 && json[jsonLength-1] == '\n' ) --jsonLength;
+
parseResponse( json, jsonLength );
}
- delete sourceDevice;
myBuffer.buffer( ).clear( );
myBuffer.reset( );
assert( myBuffer.bytesAvailable( ) < 1 );