From 273e0a4504d1fb06fd6ce73a1f8759dbb79a793b Mon Sep 17 00:00:00 2001 From: Jordan Lee Date: Sat, 2 Feb 2013 16:22:21 +0000 Subject: [PATCH] (libT) copyediting: indentation/whitespace in rpc-server.c --- libtransmission/rpc-server.c | 1066 +++++++++++++++++----------------- 1 file changed, 539 insertions(+), 527 deletions(-) diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c index b472b80f9..0098f7acc 100644 --- a/libtransmission/rpc-server.c +++ b/libtransmission/rpc-server.c @@ -59,16 +59,16 @@ struct tr_rpc_server bool isPasswordEnabled; bool isWhitelistEnabled; tr_port port; - char * url; + char * url; struct in_addr bindAddress; - struct evhttp * httpd; - tr_session * session; - char * username; - char * password; - char * whitelistStr; - tr_list * whitelist; + struct evhttp * httpd; + tr_session * session; + char * username; + char * password; + char * whitelistStr; + tr_list * whitelist; - char * sessionId; + char * sessionId; time_t sessionIdExpiresAt; #ifdef HAVE_ZLIB @@ -78,10 +78,10 @@ struct tr_rpc_server }; #define dbgmsg(...) \ - do { \ - if (tr_logGetDeepEnabled ()) \ - tr_logAddDeep (__FILE__, __LINE__, MY_NAME, __VA_ARGS__); \ - } while (0) + do { \ + if (tr_logGetDeepEnabled ()) \ + tr_logAddDeep (__FILE__, __LINE__, MY_NAME, __VA_ARGS__); \ + } while (0) /*** @@ -91,27 +91,27 @@ struct tr_rpc_server static char* get_current_session_id (struct tr_rpc_server * server) { - const time_t now = tr_time (); + const time_t now = tr_time (); - if (!server->sessionId || (now >= server->sessionIdExpiresAt)) + if (!server->sessionId || (now >= server->sessionIdExpiresAt)) { - int i; - const int n = 48; - const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const size_t pool_size = strlen (pool); - unsigned char * buf = tr_new (unsigned char, n+1); + int i; + const int n = 48; + const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const size_t pool_size = strlen (pool); + unsigned char * buf = tr_new (unsigned char, n+1); - tr_cryptoRandBuf (buf, n); - for (i=0; isessionId); - server->sessionId = (char*) buf; - server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */ + tr_free (server->sessionId); + server->sessionId = (char*) buf; + server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */ } - return server->sessionId; + return server->sessionId; } @@ -122,346 +122,354 @@ get_current_session_id (struct tr_rpc_server * server) static void send_simple_response (struct evhttp_request * req, int code, - const char * text) + const char * text) { - const char * code_text = tr_webGetResponseStr (code); - struct evbuffer * body = evbuffer_new (); + const char * code_text = tr_webGetResponseStr (code); + struct evbuffer * body = evbuffer_new (); - evbuffer_add_printf (body, "

%d: %s

", code, code_text); - if (text) - evbuffer_add_printf (body, "%s", text); - evhttp_send_reply (req, code, code_text, body); + evbuffer_add_printf (body, "

%d: %s

", code, code_text); + if (text) + evbuffer_add_printf (body, "%s", text); + evhttp_send_reply (req, code, code_text, body); - evbuffer_free (body); + evbuffer_free (body); } struct tr_mimepart { - char * headers; - int headers_len; - char * body; - int body_len; + 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); + tr_free (p->body); + tr_free (p->headers); + tr_free (p); } static void -extract_parts_from_multipart (const struct evkeyvalq * headers, - struct evbuffer * body, - tr_ptrArray * setme_parts) +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 * 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 * 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) + const char * delim = tr_memmem (in, inlen, boundary, boundary_len); + while (delim) { - size_t part_len; - const char * part = delim + boundary_len; + size_t part_len; + const char * part = delim + boundary_len; - inlen -= (part - in); - in = part; + inlen -= (part - in); + in = part; - delim = tr_memmem (in, inlen, boundary, boundary_len); - part_len = delim ? (size_t)(delim - part) : inlen; + delim = tr_memmem (in, inlen, boundary, boundary_len); + part_len = delim ? (size_t)(delim - part) : inlen; - if (part_len) + if (part_len) { - const char * rnrn = tr_memmem (part, part_len, "\r\n\r\n", 4); - if (rnrn) + 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); + 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); + tr_free (boundary); } static void handle_upload (struct evhttp_request * req, - struct tr_rpc_server * server) + struct tr_rpc_server * server) { - if (req->type != EVHTTP_REQ_POST) + if (req->type != EVHTTP_REQ_POST) { - send_simple_response (req, 405, NULL); + send_simple_response (req, 405, NULL); } - else + else { - int i; - int n; - bool hasSessionId = false; - tr_ptrArray parts = TR_PTR_ARRAY_INIT; + 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"); + 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); + extract_parts_from_multipart (req->input_headers, req->input_buffer, &parts); + n = tr_ptrArraySize (&parts); - /* first look for the session id */ - for (i=0; iheaders, p->headers_len, TR_RPC_SESSION_ID_HEADER, strlen (TR_RPC_SESSION_ID_HEADER))) - break; - } - if (ibody_len && !memcmp (p->body, ours, ourlen); - } - - if (!hasSessionId) + /* first look for the session id */ + for (i=0; iheaders, p->headers_len, TR_RPC_SESSION_ID_HEADER, strlen (TR_RPC_SESSION_ID_HEADER))) + break; } - else for (i=0; ibody_len; - tr_variant top, *args; - tr_variant test; - bool have_source = false; - char * body = p->body; + 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); + } - if (body_len >= 2 && !memcmp (&body[body_len - 2], "\r\n", 2)) - body_len -= 2; + 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; ibody_len; + tr_variant top, *args; + tr_variant test; + bool have_source = false; + char * body = p->body; - 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 (body_len >= 2 && !memcmp (&body[body_len - 2], "\r\n", 2)) + body_len -= 2; - if (tr_urlIsValid (body, body_len)) + 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; + tr_variantDictAddRaw (args, TR_KEY_filename, body, body_len); + have_source = true; } - else if (!tr_variantFromBenc (&test, body, body_len)) + 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; + 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) + if (have_source) { - struct evbuffer * json = tr_variantToBuf (&top, TR_VARIANT_FMT_JSON); - tr_rpc_request_exec_json (server->session, - evbuffer_pullup (json, -1), - evbuffer_get_length (json), - NULL, NULL); - evbuffer_free (json); + struct evbuffer * json = tr_variantToBuf (&top, TR_VARIANT_FMT_JSON); + tr_rpc_request_exec_json (server->session, + evbuffer_pullup (json, -1), + evbuffer_get_length (json), + NULL, NULL); + evbuffer_free (json); } - tr_variantFree (&top); + tr_variantFree (&top); } - tr_ptrArrayDestruct (&parts, (PtrArrayForeachFunc)tr_mimepart_free); + 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); - } + /* 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 const char* mimetype_guess (const char * path) { - unsigned int i; + unsigned int i; - const struct - { - const char * suffix; - const char * mime_type; - } types[] = { - /* these are the ones we need for serving the web client's files... */ - { "css", "text/css" }, - { "gif", "image/gif" }, - { "html", "text/html" }, - { "ico", "image/vnd.microsoft.icon" }, - { "js", "application/javascript" }, - { "png", "image/png" } - }; - const char * dot = strrchr (path, '.'); + const struct { + const char * suffix; + const char * mime_type; + } types[] = { + /* these are the ones we need for serving the web client's files... */ + { "css", "text/css" }, + { "gif", "image/gif" }, + { "html", "text/html" }, + { "ico", "image/vnd.microsoft.icon" }, + { "js", "application/javascript" }, + { "png", "image/png" } + }; + const char * dot = strrchr (path, '.'); - for (i = 0; dot && i < TR_N_ELEMENTS (types); ++i) - if (!strcmp (dot + 1, types[i].suffix)) - return types[i].mime_type; + for (i = 0; dot && i < TR_N_ELEMENTS (types); ++i) + if (!strcmp (dot + 1, types[i].suffix)) + return types[i].mime_type; - return "application/octet-stream"; + return "application/octet-stream"; } static void -add_response (struct evhttp_request * req, struct tr_rpc_server * server, - struct evbuffer * out, struct evbuffer * content) +add_response (struct evhttp_request * req, + struct tr_rpc_server * server, + struct evbuffer * out, + struct evbuffer * content) { #ifndef HAVE_ZLIB - evbuffer_add_buffer (out, content); + evbuffer_add_buffer (out, content); #else - const char * key = "Accept-Encoding"; - const char * encoding = evhttp_find_header (req->input_headers, key); - const int do_compress = encoding && strstr (encoding, "gzip"); + const char * key = "Accept-Encoding"; + const char * encoding = evhttp_find_header (req->input_headers, key); + const int do_compress = encoding && strstr (encoding, "gzip"); - if (!do_compress) + if (!do_compress) { - evbuffer_add_buffer (out, content); + evbuffer_add_buffer (out, content); } - else + else { - int state; - struct evbuffer_iovec iovec[1]; - void * content_ptr = evbuffer_pullup (content, -1); - const size_t content_len = evbuffer_get_length (content); + int state; + struct evbuffer_iovec iovec[1]; + void * content_ptr = evbuffer_pullup (content, -1); + const size_t content_len = evbuffer_get_length (content); - if (!server->isStreamInitialized) + if (!server->isStreamInitialized) { - int compressionLevel; + int compressionLevel; - server->isStreamInitialized = true; - server->stream.zalloc = (alloc_func) Z_NULL; - server->stream.zfree = (free_func) Z_NULL; - server->stream.opaque = (voidpf) Z_NULL; + server->isStreamInitialized = true; + server->stream.zalloc = (alloc_func) Z_NULL; + server->stream.zfree = (free_func) Z_NULL; + server->stream.opaque = (voidpf) Z_NULL; - /* zlib's manual says: "Add 16 to windowBits to write a simple gzip header - * and trailer around the compressed data instead of a zlib wrapper." */ + /* zlib's manual says: "Add 16 to windowBits to write a simple gzip header + * and trailer around the compressed data instead of a zlib wrapper." */ #ifdef TR_LIGHTWEIGHT - compressionLevel = Z_DEFAULT_COMPRESSION; + compressionLevel = Z_DEFAULT_COMPRESSION; #else - compressionLevel = Z_BEST_COMPRESSION; + compressionLevel = Z_BEST_COMPRESSION; #endif - deflateInit2 (&server->stream, compressionLevel, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY); + deflateInit2 (&server->stream, compressionLevel, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY); } - server->stream.next_in = content_ptr; - server->stream.avail_in = content_len; + server->stream.next_in = content_ptr; + server->stream.avail_in = content_len; - /* allocate space for the raw data and call deflate () just once -- - * we won't use the deflated data if it's longer than the raw data, - * so it's okay to let deflate () run out of output buffer space */ - evbuffer_reserve_space (out, content_len, iovec, 1); - server->stream.next_out = iovec[0].iov_base; - server->stream.avail_out = iovec[0].iov_len; - state = deflate (&server->stream, Z_FINISH); + /* allocate space for the raw data and call deflate () just once -- + * we won't use the deflated data if it's longer than the raw data, + * so it's okay to let deflate () run out of output buffer space */ + evbuffer_reserve_space (out, content_len, iovec, 1); + server->stream.next_out = iovec[0].iov_base; + server->stream.avail_out = iovec[0].iov_len; + state = deflate (&server->stream, Z_FINISH); - if (state == Z_STREAM_END) + if (state == Z_STREAM_END) { - iovec[0].iov_len -= server->stream.avail_out; + iovec[0].iov_len -= server->stream.avail_out; #if 0 - fprintf (stderr, "compressed response is %.2f of original (raw==%zu bytes; compressed==%zu)\n", - (double)evbuffer_get_length (out)/content_len, - content_len, evbuffer_get_length (out)); + fprintf (stderr, "compressed response is %.2f of original (raw==%zu bytes; compressed==%zu)\n", + (double)evbuffer_get_length (out)/content_len, + content_len, evbuffer_get_length (out)); #endif - evhttp_add_header (req->output_headers, - "Content-Encoding", "gzip"); + evhttp_add_header (req->output_headers, + "Content-Encoding", "gzip"); } - else + else { - memcpy (iovec[0].iov_base, content_ptr, content_len); - iovec[0].iov_len = content_len; + memcpy (iovec[0].iov_base, content_ptr, content_len); + iovec[0].iov_len = content_len; } - evbuffer_commit_space (out, iovec, 1); - deflateReset (&server->stream); + evbuffer_commit_space (out, iovec, 1); + deflateReset (&server->stream); } #endif } static void -add_time_header (struct evkeyvalq * headers, const char * key, time_t value) +add_time_header (struct evkeyvalq * headers, + const char * key, + time_t value) { - /* According to RFC 2616 this must follow RFC 1123's date format, - so use gmtime instead of localtime... */ - char buf[128]; - struct tm tm = *gmtime (&value); - strftime (buf, sizeof (buf), "%a, %d %b %Y %H:%M:%S GMT", &tm); - evhttp_add_header (headers, key, buf); + /* According to RFC 2616 this must follow RFC 1123's date format, + so use gmtime instead of localtime... */ + char buf[128]; + struct tm tm = *gmtime (&value); + strftime (buf, sizeof (buf), "%a, %d %b %Y %H:%M:%S GMT", &tm); + evhttp_add_header (headers, key, buf); } static void -evbuffer_ref_cleanup_tr_free (const void * data UNUSED, size_t datalen UNUSED, void * extra) +evbuffer_ref_cleanup_tr_free (const void * data UNUSED, + size_t datalen UNUSED, + void * extra) { - tr_free (extra); + tr_free (extra); } static void -serve_file (struct evhttp_request * req, - struct tr_rpc_server * server, - const char * filename) +serve_file (struct evhttp_request * req, + struct tr_rpc_server * server, + const char * filename) { - if (req->type != EVHTTP_REQ_GET) + if (req->type != EVHTTP_REQ_GET) { - evhttp_add_header (req->output_headers, "Allow", "GET"); - send_simple_response (req, 405, NULL); + evhttp_add_header (req->output_headers, "Allow", "GET"); + send_simple_response (req, 405, NULL); } - else + else { - void * file; - size_t file_len; - struct evbuffer * content; - const int error = errno; + void * file; + size_t file_len; + struct evbuffer * content; + const int error = errno; - errno = 0; - file_len = 0; - file = tr_loadFile (filename, &file_len); - content = evbuffer_new (); - evbuffer_add_reference (content, file, file_len, evbuffer_ref_cleanup_tr_free, file); + errno = 0; + file_len = 0; + file = tr_loadFile (filename, &file_len); + content = evbuffer_new (); + evbuffer_add_reference (content, file, file_len, evbuffer_ref_cleanup_tr_free, file); - if (errno) + if (errno) { - char * tmp = tr_strdup_printf ("%s (%s)", filename, tr_strerror (errno)); - send_simple_response (req, HTTP_NOTFOUND, tmp); - tr_free (tmp); + char * tmp = tr_strdup_printf ("%s (%s)", filename, tr_strerror (errno)); + send_simple_response (req, HTTP_NOTFOUND, tmp); + tr_free (tmp); } - else + else { - struct evbuffer * out; - const time_t now = tr_time (); + struct evbuffer * out; + const time_t now = tr_time (); - errno = error; - out = evbuffer_new (); - evhttp_add_header (req->output_headers, "Content-Type", mimetype_guess (filename)); - add_time_header (req->output_headers, "Date", now); - add_time_header (req->output_headers, "Expires", now+ (24*60*60)); - add_response (req, server, out, content); - evhttp_send_reply (req, HTTP_OK, "OK", out); + errno = error; + out = evbuffer_new (); + evhttp_add_header (req->output_headers, "Content-Type", mimetype_guess (filename)); + add_time_header (req->output_headers, "Date", now); + add_time_header (req->output_headers, "Expires", now+ (24*60*60)); + add_response (req, server, out, content); + evhttp_send_reply (req, HTTP_OK, "OK", out); - evbuffer_free (out); + evbuffer_free (out); } - evbuffer_free (content); + evbuffer_free (content); } } @@ -469,51 +477,51 @@ static void handle_web_client (struct evhttp_request * req, struct tr_rpc_server * server) { - const char * webClientDir = tr_getWebClientDir (server->session); + const char * webClientDir = tr_getWebClientDir (server->session); - if (!webClientDir || !*webClientDir) + if (!webClientDir || !*webClientDir) { send_simple_response (req, HTTP_NOTFOUND, - "

Couldn't find Transmission's web interface files!

" - "

Users: to tell Transmission where to look, " - "set the TRANSMISSION_WEB_HOME environment " - "variable to the folder where the web interface's " - "index.html is located.

" - "

Package Builders: to set a custom default at compile time, " - "#define PACKAGE_DATA_DIR in libtransmission/platform.c " - "or tweak tr_getClutchDir () by hand.

"); + "

Couldn't find Transmission's web interface files!

" + "

Users: to tell Transmission where to look, " + "set the TRANSMISSION_WEB_HOME environment " + "variable to the folder where the web interface's " + "index.html is located.

" + "

Package Builders: to set a custom default at compile time, " + "#define PACKAGE_DATA_DIR in libtransmission/platform.c " + "or tweak tr_getClutchDir () by hand.

"); } - else + else { - char * pch; - char * subpath; + char * pch; + char * subpath; - subpath = tr_strdup (req->uri + strlen (server->url) + 4); - if ((pch = strchr (subpath, '?'))) - *pch = '\0'; + subpath = tr_strdup (req->uri + strlen (server->url) + 4); + if ((pch = strchr (subpath, '?'))) + *pch = '\0'; - if (strstr (subpath, "..")) + if (strstr (subpath, "..")) { - send_simple_response (req, HTTP_NOTFOUND, "

Tsk, tsk.

"); + send_simple_response (req, HTTP_NOTFOUND, "

Tsk, tsk.

"); } - else + else { - char * filename = tr_strdup_printf ("%s%s%s", - webClientDir, - TR_PATH_DELIMITER_STR, - subpath && *subpath ? subpath : "index.html"); - serve_file (req, server, filename); - tr_free (filename); + char * filename = tr_strdup_printf ("%s%s%s", + webClientDir, + TR_PATH_DELIMITER_STR, + subpath && *subpath ? subpath : "index.html"); + serve_file (req, server, filename); + tr_free (filename); } - tr_free (subpath); + tr_free (subpath); } } struct rpc_response_data { - struct evhttp_request * req; - struct tr_rpc_server * server; + struct evhttp_request * req; + struct tr_rpc_server * server; }; static void @@ -521,223 +529,220 @@ rpc_response_func (tr_session * session UNUSED, struct evbuffer * response, void * user_data) { - struct rpc_response_data * data = user_data; - struct evbuffer * buf = evbuffer_new (); + struct rpc_response_data * data = user_data; + struct evbuffer * buf = evbuffer_new (); - add_response (data->req, data->server, buf, response); - evhttp_add_header (data->req->output_headers, - "Content-Type", "application/json; charset=UTF-8"); - evhttp_send_reply (data->req, HTTP_OK, "OK", buf); + add_response (data->req, data->server, buf, response); + evhttp_add_header (data->req->output_headers, + "Content-Type", "application/json; charset=UTF-8"); + evhttp_send_reply (data->req, HTTP_OK, "OK", buf); - evbuffer_free (buf); - tr_free (data); + evbuffer_free (buf); + tr_free (data); } static void -handle_rpc (struct evhttp_request * req, - struct tr_rpc_server * server) +handle_rpc (struct evhttp_request * req, struct tr_rpc_server * server) { - struct rpc_response_data * data = tr_new0 (struct rpc_response_data, 1); + struct rpc_response_data * data = tr_new0 (struct rpc_response_data, 1); - data->req = req; - data->server = server; + data->req = req; + data->server = server; - if (req->type == EVHTTP_REQ_GET) + if (req->type == EVHTTP_REQ_GET) { - const char * q; - if ((q = strchr (req->uri, '?'))) - tr_rpc_request_exec_uri (server->session, q+1, -1, rpc_response_func, data); + const char * q; + if ((q = strchr (req->uri, '?'))) + tr_rpc_request_exec_uri (server->session, q+1, -1, rpc_response_func, data); } - else if (req->type == EVHTTP_REQ_POST) + else if (req->type == EVHTTP_REQ_POST) { - tr_rpc_request_exec_json (server->session, - evbuffer_pullup (req->input_buffer, -1), - evbuffer_get_length (req->input_buffer), - rpc_response_func, data); + tr_rpc_request_exec_json (server->session, + evbuffer_pullup (req->input_buffer, -1), + evbuffer_get_length (req->input_buffer), + rpc_response_func, data); } } static bool -isAddressAllowed (const tr_rpc_server * server, - const char * address) +isAddressAllowed (const tr_rpc_server * server, const char * address) { - tr_list * l; + tr_list * l; - if (!server->isWhitelistEnabled) - return true; + if (!server->isWhitelistEnabled) + return true; - for (l=server->whitelist; l!=NULL; l=l->next) - if (tr_wildmat (address, l->data)) - return true; + for (l=server->whitelist; l!=NULL; l=l->next) + if (tr_wildmat (address, l->data)) + return true; - return false; + return false; } static bool test_session_id (struct tr_rpc_server * server, struct evhttp_request * req) { - const char * ours = get_current_session_id (server); - const char * theirs = evhttp_find_header (req->input_headers, TR_RPC_SESSION_ID_HEADER); - const bool success = theirs && !strcmp (theirs, ours); - return success; + const char * ours = get_current_session_id (server); + const char * theirs = evhttp_find_header (req->input_headers, TR_RPC_SESSION_ID_HEADER); + const bool success = theirs && !strcmp (theirs, ours); + return success; } static void handle_request (struct evhttp_request * req, void * arg) { - struct tr_rpc_server * server = arg; + struct tr_rpc_server * server = arg; - if (req && req->evcon) + if (req && req->evcon) { - const char * auth; - char * user = NULL; - char * pass = NULL; + const char * auth; + char * user = NULL; + char * pass = NULL; - evhttp_add_header (req->output_headers, "Server", MY_REALM); + evhttp_add_header (req->output_headers, "Server", MY_REALM); - auth = evhttp_find_header (req->input_headers, "Authorization"); - if (auth && !evutil_ascii_strncasecmp (auth, "basic ", 6)) + auth = evhttp_find_header (req->input_headers, "Authorization"); + if (auth && !evutil_ascii_strncasecmp (auth, "basic ", 6)) { - int plen; - char * p = tr_base64_decode (auth + 6, 0, &plen); - if (p && plen && ((pass = strchr (p, ':')))) + int plen; + char * p = tr_base64_decode (auth + 6, 0, &plen); + if (p && plen && ((pass = strchr (p, ':')))) { - user = p; - *pass++ = '\0'; + user = p; + *pass++ = '\0'; } } - if (!isAddressAllowed (server, req->remote_host)) + if (!isAddressAllowed (server, req->remote_host)) { - send_simple_response (req, 403, - "

Unauthorized IP Address.

" - "

Either disable the IP address whitelist or add your address to it.

" - "

If you're editing settings.json, see the 'rpc-whitelist' and 'rpc-whitelist-enabled' entries.

" - "

If you're still using ACLs, use a whitelist instead. See the transmission-daemon manpage for details.

"); + send_simple_response (req, 403, + "

Unauthorized IP Address.

" + "

Either disable the IP address whitelist or add your address to it.

" + "

If you're editing settings.json, see the 'rpc-whitelist' and 'rpc-whitelist-enabled' entries.

" + "

If you're still using ACLs, use a whitelist instead. See the transmission-daemon manpage for details.

"); } - else if (server->isPasswordEnabled + else if (server->isPasswordEnabled && (!pass || !user || strcmp (server->username, user) || !tr_ssha1_matches (server->password, pass))) { - evhttp_add_header (req->output_headers, - "WWW-Authenticate", - "Basic realm=\"" MY_REALM "\""); - send_simple_response (req, 401, "Unauthorized User"); + evhttp_add_header (req->output_headers, + "WWW-Authenticate", + "Basic realm=\"" MY_REALM "\""); + send_simple_response (req, 401, "Unauthorized User"); } - else if (strncmp (req->uri, server->url, strlen (server->url))) + else if (strncmp (req->uri, server->url, strlen (server->url))) { - char * location = tr_strdup_printf ("%sweb/", server->url); - evhttp_add_header (req->output_headers, "Location", location); - send_simple_response (req, HTTP_MOVEPERM, NULL); - tr_free (location); + char * location = tr_strdup_printf ("%sweb/", server->url); + evhttp_add_header (req->output_headers, "Location", location); + send_simple_response (req, HTTP_MOVEPERM, NULL); + tr_free (location); } - else if (!strncmp (req->uri + strlen (server->url), "web/", 4)) + else if (!strncmp (req->uri + strlen (server->url), "web/", 4)) { - handle_web_client (req, server); + handle_web_client (req, server); } - else if (!strncmp (req->uri + strlen (server->url), "upload", 6)) + else if (!strncmp (req->uri + strlen (server->url), "upload", 6)) { - handle_upload (req, server); + handle_upload (req, server); } #ifdef REQUIRE_SESSION_ID - else if (!test_session_id (server, req)) + else if (!test_session_id (server, req)) { - const char * sessionId = get_current_session_id (server); - char * tmp = tr_strdup_printf ( - "

Your request had an invalid session-id header.

" - "

To fix this, follow these steps:" - "

  1. When reading a response, get its X-Transmission-Session-Id header and remember it" - "
  2. Add the updated header to your outgoing requests" - "
  3. When you get this 409 error message, resend your request with the updated header" - "

" - "

This requirement has been added to help prevent " - "CSRF " - "attacks.

" - "

%s: %s

", - TR_RPC_SESSION_ID_HEADER, sessionId); - evhttp_add_header (req->output_headers, TR_RPC_SESSION_ID_HEADER, sessionId); - send_simple_response (req, 409, tmp); - tr_free (tmp); + const char * sessionId = get_current_session_id (server); + char * tmp = tr_strdup_printf ( + "

Your request had an invalid session-id header.

" + "

To fix this, follow these steps:" + "

  1. When reading a response, get its X-Transmission-Session-Id header and remember it" + "
  2. Add the updated header to your outgoing requests" + "
  3. When you get this 409 error message, resend your request with the updated header" + "

" + "

This requirement has been added to help prevent " + "CSRF " + "attacks.

" + "

%s: %s

", + TR_RPC_SESSION_ID_HEADER, sessionId); + evhttp_add_header (req->output_headers, TR_RPC_SESSION_ID_HEADER, sessionId); + send_simple_response (req, 409, tmp); + tr_free (tmp); } #endif - else if (!strncmp (req->uri + strlen (server->url), "rpc", 3)) + else if (!strncmp (req->uri + strlen (server->url), "rpc", 3)) { - handle_rpc (req, server); + handle_rpc (req, server); } - else + else { - send_simple_response (req, HTTP_NOTFOUND, req->uri); + send_simple_response (req, HTTP_NOTFOUND, req->uri); } - tr_free (user); + tr_free (user); } } static void startServer (void * vserver) { - tr_rpc_server * server = vserver; - tr_address addr; + tr_rpc_server * server = vserver; + tr_address addr; - if (!server->httpd) + if (!server->httpd) { - addr.type = TR_AF_INET; - addr.addr.addr4 = server->bindAddress; - server->httpd = evhttp_new (server->session->event_base); - evhttp_bind_socket (server->httpd, tr_address_to_string (&addr), server->port); - evhttp_set_gencb (server->httpd, handle_request, server); - + addr.type = TR_AF_INET; + addr.addr.addr4 = server->bindAddress; + server->httpd = evhttp_new (server->session->event_base); + evhttp_bind_socket (server->httpd, tr_address_to_string (&addr), server->port); + evhttp_set_gencb (server->httpd, handle_request, server); } } static void stopServer (tr_rpc_server * server) { - if (server->httpd) + if (server->httpd) { - evhttp_free (server->httpd); - server->httpd = NULL; + evhttp_free (server->httpd); + server->httpd = NULL; } } static void onEnabledChanged (void * vserver) { - tr_rpc_server * server = vserver; + tr_rpc_server * server = vserver; - if (!server->isEnabled) - stopServer (server); - else - startServer (server); + if (!server->isEnabled) + stopServer (server); + else + startServer (server); } void tr_rpcSetEnabled (tr_rpc_server * server, bool isEnabled) { - server->isEnabled = isEnabled; + server->isEnabled = isEnabled; - tr_runInEventThread (server->session, onEnabledChanged, server); + tr_runInEventThread (server->session, onEnabledChanged, server); } bool tr_rpcIsEnabled (const tr_rpc_server * server) { - return server->isEnabled; + return server->isEnabled; } static void restartServer (void * vserver) { - tr_rpc_server * server = vserver; + tr_rpc_server * server = vserver; - if (server->isEnabled) + if (server->isEnabled) { - stopServer (server); - startServer (server); + stopServer (server); + startServer (server); } } @@ -745,87 +750,89 @@ void tr_rpcSetPort (tr_rpc_server * server, tr_port port) { - assert (server != NULL); + assert (server != NULL); - if (server->port != port) + if (server->port != port) { - server->port = port; + server->port = port; - if (server->isEnabled) - tr_runInEventThread (server->session, restartServer, server); + if (server->isEnabled) + tr_runInEventThread (server->session, restartServer, server); } } tr_port tr_rpcGetPort (const tr_rpc_server * server) { - return server->port; + return server->port; } void tr_rpcSetUrl (tr_rpc_server * server, const char * url) { - char * tmp = server->url; - server->url = tr_strdup (url); - dbgmsg ("setting our URL to [%s]", server->url); - tr_free (tmp); + char * tmp = server->url; + server->url = tr_strdup (url); + dbgmsg ("setting our URL to [%s]", server->url); + tr_free (tmp); } const char* tr_rpcGetUrl (const tr_rpc_server * server) { - return server->url ? server->url : ""; + return server->url ? server->url : ""; } void tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr) { - void * tmp; - const char * walk; + void * tmp; + const char * walk; - /* keep the string */ - tmp = server->whitelistStr; - server->whitelistStr = tr_strdup (whitelistStr); + /* keep the string */ + tmp = server->whitelistStr; + server->whitelistStr = tr_strdup (whitelistStr); + tr_free (tmp); + + /* clear out the old whitelist entries */ + while ((tmp = tr_list_pop_front (&server->whitelist))) tr_free (tmp); - /* clear out the old whitelist entries */ - while ((tmp = tr_list_pop_front (&server->whitelist))) - tr_free (tmp); + /* build the new whitelist entries */ + for (walk=whitelistStr; walk && *walk;) + { + const char * delimiters = " ,;"; + const size_t len = strcspn (walk, delimiters); + char * token = tr_strndup (walk, len); + tr_list_append (&server->whitelist, token); + if (strcspn (token, "+-") < len) + tr_logAddNamedInfo (MY_NAME, "Adding address to whitelist: %s (And it has a '+' or '-'! Are you using an old ACL by mistake?)", token); + else + tr_logAddNamedInfo (MY_NAME, "Adding address to whitelist: %s", token); - /* build the new whitelist entries */ - for (walk=whitelistStr; walk && *walk;) { - const char * delimiters = " ,;"; - const size_t len = strcspn (walk, delimiters); - char * token = tr_strndup (walk, len); - tr_list_append (&server->whitelist, token); - if (strcspn (token, "+-") < len) - tr_logAddNamedInfo (MY_NAME, "Adding address to whitelist: %s (And it has a '+' or '-'! Are you using an old ACL by mistake?)", token); - else - tr_logAddNamedInfo (MY_NAME, "Adding address to whitelist: %s", token); + if (walk[len]=='\0') + break; - if (walk[len]=='\0') - break; - walk += len + 1; + walk += len + 1; } } const char* tr_rpcGetWhitelist (const tr_rpc_server * server) { - return server->whitelistStr ? server->whitelistStr : ""; + return server->whitelistStr ? server->whitelistStr : ""; } void tr_rpcSetWhitelistEnabled (tr_rpc_server * server, bool isEnabled) { - server->isWhitelistEnabled = isEnabled != 0; + server->isWhitelistEnabled = isEnabled != 0; } bool tr_rpcGetWhitelistEnabled (const tr_rpc_server * server) { - return server->isWhitelistEnabled; + return server->isWhitelistEnabled; } /**** @@ -835,56 +842,56 @@ tr_rpcGetWhitelistEnabled (const tr_rpc_server * server) void tr_rpcSetUsername (tr_rpc_server * server, const char * username) { - char * tmp = server->username; - server->username = tr_strdup (username); - dbgmsg ("setting our Username to [%s]", server->username); - tr_free (tmp); + char * tmp = server->username; + server->username = tr_strdup (username); + dbgmsg ("setting our Username to [%s]", server->username); + tr_free (tmp); } const char* tr_rpcGetUsername (const tr_rpc_server * server) { - return server->username ? server->username : ""; + return server->username ? server->username : ""; } void tr_rpcSetPassword (tr_rpc_server * server, const char * password) { - tr_free (server->password); - if (*password != '{') - server->password = tr_ssha1 (password); - else - server->password = strdup (password); - dbgmsg ("setting our Password to [%s]", server->password); + tr_free (server->password); + if (*password != '{') + server->password = tr_ssha1 (password); + else + server->password = strdup (password); + dbgmsg ("setting our Password to [%s]", server->password); } const char* tr_rpcGetPassword (const tr_rpc_server * server) { - return server->password ? server->password : "" ; + return server->password ? server->password : "" ; } void tr_rpcSetPasswordEnabled (tr_rpc_server * server, bool isEnabled) { - server->isPasswordEnabled = isEnabled; - dbgmsg ("setting 'password enabled' to %d", (int)isEnabled); + server->isPasswordEnabled = isEnabled; + dbgmsg ("setting 'password enabled' to %d", (int)isEnabled); } bool tr_rpcIsPasswordEnabled (const tr_rpc_server * server) { - return server->isPasswordEnabled; + return server->isPasswordEnabled; } const char * tr_rpcGetBindAddress (const tr_rpc_server * server) { - tr_address addr; - addr.type = TR_AF_INET; - addr.addr.addr4 = server->bindAddress; - return tr_address_to_string (&addr); + tr_address addr; + addr.type = TR_AF_INET; + addr.addr.addr4 = server->bindAddress; + return tr_address_to_string (&addr); } /**** @@ -894,29 +901,29 @@ tr_rpcGetBindAddress (const tr_rpc_server * server) static void closeServer (void * vserver) { - void * tmp; - tr_rpc_server * s = vserver; + void * tmp; + tr_rpc_server * s = vserver; - stopServer (s); - while ((tmp = tr_list_pop_front (&s->whitelist))) - tr_free (tmp); + stopServer (s); + while ((tmp = tr_list_pop_front (&s->whitelist))) + tr_free (tmp); #ifdef HAVE_ZLIB - if (s->isStreamInitialized) - deflateEnd (&s->stream); + if (s->isStreamInitialized) + deflateEnd (&s->stream); #endif - tr_free (s->url); - tr_free (s->sessionId); - tr_free (s->whitelistStr); - tr_free (s->username); - tr_free (s->password); - tr_free (s); + tr_free (s->url); + tr_free (s->sessionId); + tr_free (s->whitelistStr); + tr_free (s->username); + tr_free (s->password); + tr_free (s); } void tr_rpcClose (tr_rpc_server ** ps) { - tr_runInEventThread ((*ps)->session, closeServer, *ps); - *ps = NULL; + tr_runInEventThread ((*ps)->session, closeServer, *ps); + *ps = NULL; } static void @@ -929,88 +936,93 @@ missing_settings_key (const tr_quark q) tr_rpc_server * tr_rpcInit (tr_session * session, tr_variant * settings) { - tr_rpc_server * s; - bool boolVal; - int64_t i; - const char * str; - tr_quark key; - tr_address address; + tr_rpc_server * s; + bool boolVal; + int64_t i; + const char * str; + tr_quark key; + tr_address address; - s = tr_new0 (tr_rpc_server, 1); - s->session = session; + s = tr_new0 (tr_rpc_server, 1); + s->session = session; - key = TR_KEY_rpc_enabled; - if (!tr_variantDictFindBool (settings, key, &boolVal)) - missing_settings_key (key); - else - s->isEnabled = boolVal; + key = TR_KEY_rpc_enabled; + if (!tr_variantDictFindBool (settings, key, &boolVal)) + missing_settings_key (key); + else + s->isEnabled = boolVal; - key = TR_KEY_rpc_port; - if (!tr_variantDictFindInt (settings, key, &i)) - missing_settings_key (key); - else - s->port = i; + key = TR_KEY_rpc_port; + if (!tr_variantDictFindInt (settings, key, &i)) + missing_settings_key (key); + else + s->port = i; - key = TR_KEY_rpc_url; - if (!tr_variantDictFindStr (settings, key, &str, NULL)) - missing_settings_key (key); - else - s->url = tr_strdup (str); + key = TR_KEY_rpc_url; + if (!tr_variantDictFindStr (settings, key, &str, NULL)) + missing_settings_key (key); + else + s->url = tr_strdup (str); - key = TR_KEY_rpc_whitelist_enabled; - if (!tr_variantDictFindBool (settings, key, &boolVal)) - missing_settings_key (key); - else - tr_rpcSetWhitelistEnabled (s, boolVal); + key = TR_KEY_rpc_whitelist_enabled; + if (!tr_variantDictFindBool (settings, key, &boolVal)) + missing_settings_key (key); + else + tr_rpcSetWhitelistEnabled (s, boolVal); - key = TR_KEY_rpc_authentication_required; - if (!tr_variantDictFindBool (settings, key, &boolVal)) - missing_settings_key (key); - else - tr_rpcSetPasswordEnabled (s, boolVal); + key = TR_KEY_rpc_authentication_required; + if (!tr_variantDictFindBool (settings, key, &boolVal)) + missing_settings_key (key); + else + tr_rpcSetPasswordEnabled (s, boolVal); - key = TR_KEY_rpc_whitelist; - if (!tr_variantDictFindStr (settings, key, &str, NULL) && str) - missing_settings_key (key); - else - tr_rpcSetWhitelist (s, str); + key = TR_KEY_rpc_whitelist; + if (!tr_variantDictFindStr (settings, key, &str, NULL) && str) + missing_settings_key (key); + else + tr_rpcSetWhitelist (s, str); - key = TR_KEY_rpc_username; - if (!tr_variantDictFindStr (settings, key, &str, NULL)) - missing_settings_key (key); - else - tr_rpcSetUsername (s, str); + key = TR_KEY_rpc_username; + if (!tr_variantDictFindStr (settings, key, &str, NULL)) + missing_settings_key (key); + else + tr_rpcSetUsername (s, str); - key = TR_KEY_rpc_password; - if (!tr_variantDictFindStr (settings, key, &str, NULL)) - missing_settings_key (key); - else - tr_rpcSetPassword (s, str); + key = TR_KEY_rpc_password; + if (!tr_variantDictFindStr (settings, key, &str, NULL)) + missing_settings_key (key); + else + tr_rpcSetPassword (s, str); - key = TR_KEY_rpc_bind_address; - if (!tr_variantDictFindStr (settings, key, &str, NULL)) { - missing_settings_key (key); - address = tr_inaddr_any; - } else if (!tr_address_from_string (&address, str)) { - tr_logAddNamedError (MY_NAME, _("%s is not a valid address"), str); - address = tr_inaddr_any; - } else if (address.type != TR_AF_INET) { - tr_logAddNamedError (MY_NAME, _("%s is not an IPv4 address. RPC listeners must be IPv4"), str); - address = tr_inaddr_any; - } - s->bindAddress = address.addr.addr4; - - if (s->isEnabled) + key = TR_KEY_rpc_bind_address; + if (!tr_variantDictFindStr (settings, key, &str, NULL)) { - tr_logAddNamedInfo (MY_NAME, _("Serving RPC and Web requests on port 127.0.0.1:%d%s"), (int) s->port, s->url); - tr_runInEventThread (session, startServer, s); + missing_settings_key (key); + address = tr_inaddr_any; + } + else if (!tr_address_from_string (&address, str)) + { + tr_logAddNamedError (MY_NAME, _("%s is not a valid address"), str); + address = tr_inaddr_any; + } + else if (address.type != TR_AF_INET) + { + tr_logAddNamedError (MY_NAME, _("%s is not an IPv4 address. RPC listeners must be IPv4"), str); + address = tr_inaddr_any; + } + s->bindAddress = address.addr.addr4; - if (s->isWhitelistEnabled) - tr_logAddNamedInfo (MY_NAME, "%s", _("Whitelist enabled")); + if (s->isEnabled) + { + tr_logAddNamedInfo (MY_NAME, _("Serving RPC and Web requests on port 127.0.0.1:%d%s"), (int) s->port, s->url); + tr_runInEventThread (session, startServer, s); - if (s->isPasswordEnabled) - tr_logAddNamedInfo (MY_NAME, "%s", _("Password required")); + if (s->isWhitelistEnabled) + tr_logAddNamedInfo (MY_NAME, "%s", _("Whitelist enabled")); + + if (s->isPasswordEnabled) + tr_logAddNamedInfo (MY_NAME, "%s", _("Password required")); } - return s; + return s; }