summaryrefslogtreecommitdiff
path: root/ot_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_http.c')
-rw-r--r--ot_http.c180
1 files changed, 116 insertions, 64 deletions
diff --git a/ot_http.c b/ot_http.c
index 6bf343c..2216453 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -14,9 +14,6 @@
14#include <sys/types.h> 14#include <sys/types.h>
15#include <unistd.h> 15#include <unistd.h>
16 16
17/* Libowfat */
18#include "io.h"
19
20/* Opentracker */ 17/* Opentracker */
21#include "ot_accesslist.h" 18#include "ot_accesslist.h"
22#include "ot_fullscrape.h" 19#include "ot_fullscrape.h"
@@ -25,9 +22,12 @@
25#include "ot_ip.h" 22#include "ot_ip.h"
26#include "ot_mutex.h" 23#include "ot_mutex.h"
27#include "ot_scan.h" 24#include "ot_scan.h"
25#include "ot_event.h"
28#include "ot_fdstate.h" 26#include "ot_fdstate.h"
27#include "ot_vector.h"
28#include "ot_fmt.h"
29#include "ot_stats.h" 29#include "ot_stats.h"
30#include "scan_urlencoded_query.h" 30#include "ot_urlencoded.h"
31#include "trackerlogic.h" 31#include "trackerlogic.h"
32 32
33#define OT_MAXMULTISCRAPE_COUNT 64 33#define OT_MAXMULTISCRAPE_COUNT 64
@@ -43,7 +43,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
43 ssize_t written_size; 43 ssize_t written_size;
44 44
45 if (!cookie) { 45 if (!cookie) {
46 io_close(sock); 46 event_del((int)sock), close((int)sock);
47 return; 47 return;
48 } 48 }
49 49
@@ -67,7 +67,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
67 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) { 67 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) {
68 buf_reset(&cookie->request); 68 buf_reset(&cookie->request);
69 free(cookie); 69 free(cookie);
70 io_close(sock); 70 event_del((int)sock), close((int)sock);
71 return; 71 return;
72 } 72 }
73 73
@@ -77,7 +77,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
77 if (!(outbuf = malloc(ws->reply_size - written_size))) { 77 if (!(outbuf = malloc(ws->reply_size - written_size))) {
78 buf_reset(&cookie->request); 78 buf_reset(&cookie->request);
79 free(cookie); 79 free(cookie);
80 io_close(sock); 80 event_del((int)sock), close((int)sock);
81 return; 81 return;
82 } 82 }
83 83
@@ -88,7 +88,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
88 free(outbuf); 88 free(outbuf);
89 buf_reset(&cookie->request); 89 buf_reset(&cookie->request);
90 free(cookie); 90 free(cookie);
91 io_close(sock); 91 event_del((int)sock), close((int)sock);
92 return; 92 return;
93 } 93 }
94 } 94 }
@@ -98,9 +98,9 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
98 /* writeable short data sockets just have a tcp timeout */ 98 /* writeable short data sockets just have a tcp timeout */
99 if (!ws->keep_alive) { 99 if (!ws->keep_alive) {
100 fdstate_set_expiry(sock, 0); 100 fdstate_set_expiry(sock, 0);
101 io_dontwantread(sock); 101 http_interest_drop(sock, cookie, EVENT_IN);
102 } 102 }
103 io_wantwrite(sock); 103 http_interest_add(sock, cookie, EVENT_OUT);
104 } 104 }
105} 105}
106 106
@@ -113,6 +113,21 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
113#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) 113#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP)
114#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) 114#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404)
115#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) 115#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500)
116static void http_interest(const int64_t sock, struct http_data *cookie, int what) {
117 if (cookie->interest == what)
118 return;
119 cookie->interest = what;
120 event_modify((int)sock, what, fdstate_generation((int)sock));
121}
122
123void http_interest_add(const int64_t sock, struct http_data *cookie, int what) {
124 http_interest(sock, cookie, cookie->interest | what);
125}
126
127void http_interest_drop(const int64_t sock, struct http_data *cookie, int what) {
128 http_interest(sock, cookie, cookie->interest & ~what);
129}
130
116ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) { 131ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) {
117 const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", 132 const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required",
118 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; 133 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"};
@@ -157,7 +172,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t
157 172
158 /* If we came here, wait for the answer is over */ 173 /* If we came here, wait for the answer is over */
159 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { 174 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) {
160 io_dontwantread(sock); 175 http_interest_drop(sock, cookie, EVENT_IN);
161 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; 176 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK;
162 } 177 }
163 178
@@ -208,7 +223,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t
208 } 223 }
209 224
210 fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT_SEND); 225 fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT_SEND);
211 io_wantwrite(sock); 226 http_interest_add(sock, cookie, EVENT_OUT);
212 return 0; 227 return 0;
213} 228}
214 229
@@ -219,7 +234,6 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
219 {"scrp", TASK_STATS_SCRAPE}, 234 {"scrp", TASK_STATS_SCRAPE},
220 {"udp4", TASK_STATS_UDP}, 235 {"udp4", TASK_STATS_UDP},
221 {"tcp4", TASK_STATS_TCP}, 236 {"tcp4", TASK_STATS_TCP},
222 {"busy", TASK_STATS_BUSY_NETWORKS},
223 {"torr", TASK_STATS_TORRENTS}, 237 {"torr", TASK_STATS_TORRENTS},
224 {"fscr", TASK_STATS_FULLSCRAPE}, 238 {"fscr", TASK_STATS_FULLSCRAPE},
225 {"s24s", TASK_STATS_SLASH24S}, 239 {"s24s", TASK_STATS_SLASH24S},
@@ -244,6 +258,7 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
244 {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}}; 258 {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}};
245 259
246 struct http_data *cookie = fdstate_cookie(sock); 260 struct http_data *cookie = fdstate_cookie(sock);
261 char *reply;
247 int mode = TASK_STATS_PEERS, scanon = 1, format = 0; 262 int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
248 263
249 /* A socket without one is a dead socket, which is what http_sendiovecdata 264 /* A socket without one is a dead socket, which is what http_sendiovecdata
@@ -257,21 +272,21 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
257#endif 272#endif
258 273
259 while (scanon) { 274 while (scanon) {
260 switch (scan_find_keywords(keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM)) { 275 switch (urlencoded_match_keyword(keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM)) {
261 case -2: 276 case -2:
262 scanon = 0; 277 scanon = 0;
263 break; /* TERMINATOR */ 278 break; /* TERMINATOR */
264 case -1: 279 case -1:
265 HTTPERROR_400_PARAM; /* PARSE ERROR */ 280 HTTPERROR_400_PARAM; /* PARSE ERROR */
266 case -3: 281 case -3:
267 scan_urlencoded_skipvalue(&read_ptr); 282 urlencoded_skip_value(&read_ptr);
268 break; 283 break;
269 case 1: /* matched "mode" */ 284 case 1: /* matched "mode" */
270 if ((mode = scan_find_keywords(keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) 285 if ((mode = urlencoded_match_keyword(keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0)
271 HTTPERROR_400_PARAM; 286 HTTPERROR_400_PARAM;
272 break; 287 break;
273 case 2: /* matched "format" */ 288 case 2: /* matched "format" */
274 if ((format = scan_find_keywords(keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) 289 if ((format = urlencoded_match_keyword(keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0)
275 HTTPERROR_400_PARAM; 290 HTTPERROR_400_PARAM;
276 break; 291 break;
277 case 3: 292 case 3:
@@ -303,7 +318,7 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
303 /* Clients waiting for us should not easily timeout */ 318 /* Clients waiting for us should not easily timeout */
304 fdstate_set_expiry(sock, 0); 319 fdstate_set_expiry(sock, 0);
305 fullscrape_deliver(sock, format); 320 fullscrape_deliver(sock, format);
306 io_dontwantread(sock); 321 http_interest_drop(sock, cookie, EVENT_IN);
307 return ws->reply_size = -2; 322 return ws->reply_size = -2;
308 } 323 }
309#endif 324#endif
@@ -320,7 +335,9 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
320 } 335 }
321 336
322 /* Simple stats can be answerred immediately */ 337 /* Simple stats can be answerred immediately */
323 return ws->reply_size = return_stats_for_tracker(ws->reply, mode, 0); 338 reply = ws->reply;
339 return_stats_for_tracker(&reply, ws->outbuf + G_OUTBUF_SIZE, mode, 0);
340 return ws->reply_size = reply - ws->reply;
324} 341}
325 342
326#ifdef WANT_MODEST_FULLSCRAPES 343#ifdef WANT_MODEST_FULLSCRAPES
@@ -396,17 +413,20 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *
396 /* Clients waiting for us should not easily timeout */ 413 /* Clients waiting for us should not easily timeout */
397 fdstate_set_expiry(sock, 0); 414 fdstate_set_expiry(sock, 0);
398 fullscrape_deliver(sock, format); 415 fullscrape_deliver(sock, format);
399 io_dontwantread(sock); 416 http_interest_drop(sock, cookie, EVENT_IN);
400 return ws->reply_size = -2; 417 return ws->reply_size = -2;
401} 418}
402#endif 419#endif
403 420
421static int compare_hash(const void *left, const void *right) { return memcmp(left, right, sizeof(ot_hash)); }
422
404static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { 423static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) {
405 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; 424 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}};
406 425
407 ot_hash *multiscrape_buf = (ot_hash *)ws->request; 426 ot_hash *multiscrape_buf = (ot_hash *)ws->request;
408 int scanon = 1; 427 char *reply = ws->reply;
409 size_t numwant = 0; 428 int scanon = 1;
429 size_t i, unique, numwant = 0;
410 430
411 /* This is to hack around stupid clients that send "scrape ?info_hash" */ 431 /* This is to hack around stupid clients that send "scrape ?info_hash" */
412 if (read_ptr[-1] != '?') { 432 if (read_ptr[-1] != '?') {
@@ -418,18 +438,18 @@ static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws,
418 } 438 }
419 439
420 while (scanon) { 440 while (scanon) {
421 switch (scan_find_keywords(keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM)) { 441 switch (urlencoded_match_keyword(keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM)) {
422 case -2: 442 case -2:
423 scanon = 0; 443 scanon = 0;
424 break; /* TERMINATOR */ 444 break; /* TERMINATOR */
425 default: 445 default:
426 HTTPERROR_400_PARAM; /* PARSE ERROR */ 446 HTTPERROR_400_PARAM; /* PARSE ERROR */
427 case -3: 447 case -3:
428 scan_urlencoded_skipvalue(&read_ptr); 448 urlencoded_skip_value(&read_ptr);
429 break; 449 break;
430 case 1: /* matched "info_hash" */ 450 case 1: /* matched "info_hash" */
431 /* ignore this, when we have less than 20 bytes */ 451 /* ignore this, when we have less than 20 bytes */
432 if (scan_urlencoded_query(&read_ptr, (char *)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE) != (ssize_t)sizeof(ot_hash)) 452 if (urlencoded_parse(&read_ptr, (char *)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE) != (ssize_t)sizeof(ot_hash))
433 HTTPERROR_400_PARAM; 453 HTTPERROR_400_PARAM;
434 break; 454 break;
435 } 455 }
@@ -443,8 +463,17 @@ static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws,
443 if (numwant > OT_MAXMULTISCRAPE_COUNT) 463 if (numwant > OT_MAXMULTISCRAPE_COUNT)
444 numwant = OT_MAXMULTISCRAPE_COUNT; 464 numwant = OT_MAXMULTISCRAPE_COUNT;
445 465
466 /* A bencoded dictionary has its keys in order and names each one once, so
467 the answer cannot just follow the order the client asked in */
468 qsort(multiscrape_buf, numwant, sizeof(ot_hash), compare_hash);
469 for (i = unique = 1; i < numwant; ++i)
470 if (memcmp(multiscrape_buf[i], multiscrape_buf[unique - 1], sizeof(ot_hash)))
471 memcpy(multiscrape_buf[unique++], multiscrape_buf[i], sizeof(ot_hash));
472 numwant = unique;
473
446 /* Enough for http header + whole scrape string */ 474 /* Enough for http header + whole scrape string */
447 ws->reply_size = return_tcp_scrape_for_torrent((const ot_hash *)multiscrape_buf, numwant, ws->reply); 475 return_tcp_scrape_for_torrent((const ot_hash *)multiscrape_buf, numwant, &reply, ws->outbuf + G_OUTBUF_SIZE);
476 ws->reply_size = reply - ws->reply;
448 stats_issue_event(EVENT_SCRAPE, FLAG_TCP, ws->reply_size); 477 stats_issue_event(EVENT_SCRAPE, FLAG_TCP, ws->reply_size);
449 return ws->reply_size; 478 return ws->reply_size;
450} 479}
@@ -480,9 +509,20 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event",
480#endif 509#endif
481 {"peer_id", 9}, {NULL, -3}}; 510 {"peer_id", 9}, {NULL, -3}};
482static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; 511static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}};
512
513/* For the replies that are one fixed string and nothing else, where the only
514 thing the caller wants back is how long it turned out */
515static ssize_t reply_literal(struct ot_workstruct *ws, const char *text) {
516 char *reply = ws->reply;
517
518 fmt_bytes(&reply, ws->outbuf + G_OUTBUF_SIZE, text, strlen(text));
519 return reply - ws->reply;
520}
521
483static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { 522static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) {
484 size_t numwant; 523 size_t numwant;
485 int tmp, scanon; 524 int64_t tmp;
525 int scanon;
486 unsigned short port = 0; 526 unsigned short port = 0;
487 char *write_ptr; 527 char *write_ptr;
488 ssize_t len; 528 ssize_t len;
@@ -501,7 +541,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
501 if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) { 541 if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) {
502 ot_ip6 proxied_ip; 542 ot_ip6 proxied_ip;
503 char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for"); 543 char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for");
504 if (fwd && ip_scan(fwd, proxied_ip)) { 544 if (fwd && ip_parse(fwd, proxied_ip)) {
505 OT_SETIP(ws->peer, proxied_ip); 545 OT_SETIP(ws->peer, proxied_ip);
506 } else 546 } else
507 OT_SETIP(ws->peer, cookie->ip); 547 OT_SETIP(ws->peer, cookie->ip);
@@ -518,32 +558,32 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
518 scanon = 1; 558 scanon = 1;
519 559
520 while (scanon) { 560 while (scanon) {
521 switch (scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM)) { 561 switch (urlencoded_match_keyword(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM)) {
522 case -2: 562 case -2:
523 scanon = 0; 563 scanon = 0;
524 break; /* TERMINATOR */ 564 break; /* TERMINATOR */
525 case -1: 565 case -1:
526 HTTPERROR_400_PARAM; /* PARSE ERROR */ 566 HTTPERROR_400_PARAM; /* PARSE ERROR */
527 case -3: 567 case -3:
528 scan_urlencoded_skipvalue(&read_ptr); 568 urlencoded_skip_value(&read_ptr);
529 break; 569 break;
530 case 1: /* matched "port" */ 570 case 1: /* matched "port" */
531 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); 571 len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
532 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp) || (tmp > 0xffff)) 572 if ((len <= 0) || scan_int(write_ptr, len, &tmp) || (tmp > 0xffff))
533 HTTPERROR_400_PARAM; 573 HTTPERROR_400_PARAM;
534 port = htons(tmp); 574 port = htons((uint16_t)tmp);
535 OT_SETPORT(&ws->peer, &port); 575 OT_SETPORT(&ws->peer, &port);
536 break; 576 break;
537 case 2: /* matched "left" */ 577 case 2: /* matched "left" */
538 if ((len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) 578 if ((len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0)
539 HTTPERROR_400_PARAM; 579 HTTPERROR_400_PARAM;
540 if (scan_fixed_int(write_ptr, len, &tmp)) 580 if (scan_int(write_ptr, len, &tmp))
541 tmp = 0; 581 tmp = 0;
542 if (!tmp) 582 if (!tmp)
543 OT_PEERFLAG(&ws->peer) |= PEER_FLAG_SEEDING; 583 OT_PEERFLAG(&ws->peer) |= PEER_FLAG_SEEDING;
544 break; 584 break;
545 case 3: /* matched "event" */ 585 case 3: /* matched "event" */
546 switch (scan_find_keywords(keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE)) { 586 switch (urlencoded_match_keyword(keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE)) {
547 case -1: 587 case -1:
548 HTTPERROR_400_PARAM; 588 HTTPERROR_400_PARAM;
549 case 1: /* matched "completed" */ 589 case 1: /* matched "completed" */
@@ -557,18 +597,18 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
557 } 597 }
558 break; 598 break;
559 case 4: /* matched "numwant" */ 599 case 4: /* matched "numwant" */
560 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); 600 len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
561 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp)) 601 if ((len <= 0) || scan_int(write_ptr, len, &tmp))
562 HTTPERROR_400_PARAM; 602 HTTPERROR_400_PARAM;
563 if (tmp < 0) 603 if (tmp < 0)
564 tmp = 50; 604 tmp = 50;
565 if (tmp > 200) 605 if (tmp > 200)
566 tmp = 200; 606 tmp = 200;
567 numwant = tmp; 607 numwant = (size_t)tmp;
568 break; 608 break;
569 case 5: /* matched "compact" */ 609 case 5: /* matched "compact" */
570 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); 610 len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
571 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp)) 611 if ((len <= 0) || scan_int(write_ptr, len, &tmp))
572 HTTPERROR_400_PARAM; 612 HTTPERROR_400_PARAM;
573 if (!tmp) 613 if (!tmp)
574 HTTPERROR_400_COMPACT; 614 HTTPERROR_400_COMPACT;
@@ -577,7 +617,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
577 if (ws->hash) 617 if (ws->hash)
578 HTTPERROR_400_DOUBLEHASH; 618 HTTPERROR_400_DOUBLEHASH;
579 /* ignore this, when we have less than 20 bytes */ 619 /* ignore this, when we have less than 20 bytes */
580 if (scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20) 620 if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20)
581 HTTPERROR_400_PARAM; 621 HTTPERROR_400_PARAM;
582 ws->hash = (ot_hash *)write_ptr; 622 ws->hash = (ot_hash *)write_ptr;
583 break; 623 break;
@@ -585,9 +625,9 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
585 case 7: /* matched "ip" */ 625 case 7: /* matched "ip" */
586 { 626 {
587 char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; 627 char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16;
588 len = scan_urlencoded_query(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); 628 len = urlencoded_parse(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE);
589 tmp_buf2[len] = 0; 629 tmp_buf2[len] = 0;
590 if ((len <= 0) || !ip_scan(tmp_buf2, tmp_buf1)) 630 if ((len <= 0) || ip_parse(tmp_buf2, tmp_buf1) != (size_t)len)
591 HTTPERROR_400_PARAM; 631 HTTPERROR_400_PARAM;
592 OT_SETIP(&ws->peer, tmp_buf1); 632 OT_SETIP(&ws->peer, tmp_buf1);
593 } break; 633 } break;
@@ -601,21 +641,21 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
601 uint64_t value; 641 uint64_t value;
602 signed short parsed, bits; 642 signed short parsed, bits;
603 643
604 len = scan_urlencoded_query(&read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE); 644 len = urlencoded_parse(&read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE);
605 tmp_buf[len] = 0; 645 tmp_buf[len] = 0;
606 if (len <= 0) 646 if (len <= 0)
607 HTTPERROR_400_PARAM; 647 HTTPERROR_400_PARAM;
608 if (*tmp_buf == '-') { 648 if (*tmp_buf == '-') {
609 loglist_reset(); 649 loglist_reset();
610 return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n"); 650 return ws->reply_size = reply_literal(ws, "Successfully removed.\n");
611 } 651 }
612 parsed = ip_scan(tmp_buf, net.address); 652 parsed = ip_parse(tmp_buf, net.address);
613 if (!parsed) 653 if (!parsed)
614 HTTPERROR_400_PARAM; 654 HTTPERROR_400_PARAM;
615 if (tmp_buf[parsed++] != '/') 655 if (tmp_buf[parsed++] != '/')
616 bits = 128; 656 bits = 128;
617 else { 657 else {
618 parsed = scan_udec(tmp_buf + parsed, &value, 128); 658 parsed = scan_uint(tmp_buf + parsed, &value, 128);
619 if (!parsed) 659 if (!parsed)
620 HTTPERROR_400_PARAM; 660 HTTPERROR_400_PARAM;
621 bits = (signed short)value; 661 bits = (signed short)value;
@@ -624,13 +664,13 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
624 } 664 }
625 net.bits = bits; 665 net.bits = bits;
626 loglist_add_network(&net); 666 loglist_add_network(&net);
627 return ws->reply_size = sprintf(ws->reply, "Successfully added.\n"); 667 return ws->reply_size = reply_literal(ws, "Successfully added.\n");
628 //} 668 //}
629 } break; 669 } break;
630#endif 670#endif
631 case 9: /* matched "peer_id" */ 671 case 9: /* matched "peer_id" */
632 /* ignore this, when we have less than 20 bytes */ 672 /* ignore this, when we have less than 20 bytes */
633 if (scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20) 673 if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20)
634 HTTPERROR_400_PARAM; 674 HTTPERROR_400_PARAM;
635 ws->peer_id = write_ptr; 675 ws->peer_id = write_ptr;
636 break; 676 break;
@@ -647,7 +687,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
647 687
648 /* Scanned whole query string */ 688 /* Scanned whole query string */
649 if (!ws->hash) 689 if (!ws->hash)
650 return ws->reply_size = sprintf(ws->reply, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e"); 690 return ws->reply_size = reply_literal(ws, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e");
651 691
652 if (OT_PEERFLAG(&ws->peer) & PEER_FLAG_STOPPED) 692 if (OT_PEERFLAG(&ws->peer) & PEER_FLAG_STOPPED)
653 ws->reply_size = remove_peer_from_torrent(FLAG_TCP, ws); 693 ws->reply_size = remove_peer_from_torrent(FLAG_TCP, ws);
@@ -697,6 +737,24 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) {
697 /* Tell subroutines where to put reply data */ 737 /* Tell subroutines where to put reply data */
698 ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH; 738 ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH;
699 739
740 /* Find out if the client wants to keep this connection alive, before any
741 subroutine gets to answer: an error reply finishes with the connection
742 on its way out, and ws outlives the connection it was serving */
743 ws->keep_alive = 0;
744#ifdef WANT_KEEPALIVE
745 if ((write_ptr = http_header(ws->request, ws->header_size, "connection")) && (*write_ptr == 'K' || *write_ptr == 'k'))
746 ws->keep_alive = 1;
747#endif
748 {
749 struct http_data *connection = fdstate_cookie(sock);
750 if (connection) {
751 if (ws->keep_alive)
752 connection->flag |= STRUCT_HTTP_FLAG_KEEPALIVE;
753 else
754 connection->flag &= ~STRUCT_HTTP_FLAG_KEEPALIVE;
755 }
756 }
757
700 /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */ 758 /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */
701 if (memcmp(read_ptr, "GET /", 5)) 759 if (memcmp(read_ptr, "GET /", 5))
702 HTTPERROR_400; 760 HTTPERROR_400;
@@ -709,7 +767,7 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) {
709 In reality we abandoned requiring the url to be correct. This now 767 In reality we abandoned requiring the url to be correct. This now
710 only decodes url encoded characters, we check for announces and 768 only decodes url encoded characters, we check for announces and
711 scrapes by looking for "a*" or "sc" */ 769 scrapes by looking for "a*" or "sc" */
712 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_PATH); 770 len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_PATH);
713 771
714 /* If parsing returned an error, leave with not found */ 772 /* If parsing returned an error, leave with not found */
715 if (g_redirecturl && (len == -2)) 773 if (g_redirecturl && (len == -2))
@@ -733,14 +791,6 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) {
733 else 791 else
734 HTTPERROR_404; 792 HTTPERROR_404;
735 793
736 /* Find out if the client wants to keep this connection alive */
737 ws->keep_alive = 0;
738#ifdef WANT_KEEPALIVE
739 read_ptr = http_header(ws->request, ws->header_size, "connection");
740 if (read_ptr && (*read_ptr == 'K' || *read_ptr == 'k'))
741 ws->keep_alive = 1;
742#endif
743
744 /* If routines handled sending themselves, just return */ 794 /* If routines handled sending themselves, just return */
745 if (ws->reply_size == -2) 795 if (ws->reply_size == -2)
746 return 0; 796 return 0;
@@ -758,9 +808,11 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) {
758 reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf(ws->outbuf, 0, "%zd", ws->reply_size); 808 reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf(ws->outbuf, 0, "%zd", ws->reply_size);
759 ws->reply = ws->outbuf + reply_off; 809 ws->reply = ws->outbuf + reply_off;
760 810
761 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete 811 /* 2. Now we write the header so that its terminating '\0' lands exactly one byte before the content starts. The bound is the
762 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ 812 space step 1 reserved, so the '\0' falls where step 3 expects it. Complete packet size is increased by size of header plus
763 ws->reply_size += 1 + sprintf(ws->reply, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", ws->reply_size); 813 one byte '\n', we will copy over '\0' in next step */
814 ws->reply_size += 1 + snprintf(ws->reply, (size_t)(SUCCESS_HTTP_HEADER_LENGTH - reply_off),
815 "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", ws->reply_size);
764 816
765 /* 3. Finally we join both blocks neatly */ 817 /* 3. Finally we join both blocks neatly */
766 ws->outbuf[SUCCESS_HTTP_HEADER_LENGTH - 1] = '\n'; 818 ws->outbuf[SUCCESS_HTTP_HEADER_LENGTH - 1] = '\n';