summaryrefslogtreecommitdiff
path: root/ot_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_http.c')
-rw-r--r--ot_http.c81
1 files changed, 49 insertions, 32 deletions
diff --git a/ot_http.c b/ot_http.c
index 626547b..46ca5a9 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -15,15 +15,14 @@
15#include <unistd.h> 15#include <unistd.h>
16 16
17/* Libowfat */ 17/* Libowfat */
18#include "array.h"
19#include "iob.h" 18#include "iob.h"
20#include "ip6.h"
21 19
22/* Opentracker */ 20/* Opentracker */
23#include "ot_accesslist.h" 21#include "ot_accesslist.h"
24#include "ot_fullscrape.h" 22#include "ot_fullscrape.h"
25#include "ot_http.h" 23#include "ot_http.h"
26#include "ot_iovec.h" 24#include "ot_iovec.h"
25#include "ot_ip.h"
27#include "ot_mutex.h" 26#include "ot_mutex.h"
28#include "ot_scan.h" 27#include "ot_scan.h"
29#include "ot_stats.h" 28#include "ot_stats.h"
@@ -45,7 +44,7 @@ ssize_t g_stats_path_len;
45 44
46enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; 45enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 };
47 46
48static void http_senddata(const int64 sock, struct ot_workstruct *ws) { 47static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
49 struct http_data *cookie = io_getcookie(sock); 48 struct http_data *cookie = io_getcookie(sock);
50 ssize_t written_size; 49 ssize_t written_size;
51 50
@@ -54,20 +53,25 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) {
54 return; 53 return;
55 } 54 }
56 55
57 /* whoever sends data is not interested in its input-array */ 56 /* whoever sends data is not interested in its input buffer */
58 if (ws->keep_alive && ws->header_size != ws->request_size) { 57 if (ws->keep_alive && ws->header_size != ws->request_size) {
59 size_t rest = ws->request_size - ws->header_size; 58 size_t rest = ws->request_size - ws->header_size;
60 if (array_start(&cookie->request)) { 59 if (cookie->request.data) {
61 memmove(array_start(&cookie->request), ws->request + ws->header_size, rest); 60 memmove(cookie->request.data, ws->request + ws->header_size, rest);
62 array_truncate(&cookie->request, 1, rest); 61 buf_truncate(&cookie->request, rest);
63 } else 62 } else if (buf_cat(&cookie->request, ws->request + ws->header_size, rest)) {
64 array_catb(&cookie->request, ws->request + ws->header_size, rest); 63 /* Without room for what the client pipelined behind this request, answer
64 this one and let the connection close, rather than keeping it open
65 around a request we have silently dropped */
66 buf_reset(&cookie->request);
67 ws->keep_alive = 0;
68 }
65 } else 69 } else
66 array_reset(&cookie->request); 70 buf_reset(&cookie->request);
67 71
68 written_size = write(sock, ws->reply, ws->reply_size); 72 written_size = write(sock, ws->reply, ws->reply_size);
69 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) { 73 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) {
70 array_reset(&cookie->request); 74 buf_reset(&cookie->request);
71 free(cookie); 75 free(cookie);
72 io_close(sock); 76 io_close(sock);
73 return; 77 return;
@@ -78,7 +82,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) {
78 tai6464 t; 82 tai6464 t;
79 83
80 if (!(outbuf = malloc(ws->reply_size - written_size))) { 84 if (!(outbuf = malloc(ws->reply_size - written_size))) {
81 array_reset(&cookie->request); 85 buf_reset(&cookie->request);
82 free(cookie); 86 free(cookie);
83 io_close(sock); 87 io_close(sock);
84 return; 88 return;
@@ -90,7 +94,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) {
90 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) { 94 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) {
91 free(cookie->batch); 95 free(cookie->batch);
92 free(outbuf); 96 free(outbuf);
93 array_reset(&cookie->request); 97 buf_reset(&cookie->request);
94 free(cookie); 98 free(cookie);
95 io_close(sock); 99 io_close(sock);
96 return; 100 return;
@@ -120,7 +124,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) {
120#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) 124#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP)
121#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) 125#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404)
122#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) 126#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500)
123ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) { 127ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) {
124 char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", 128 char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required",
125 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; 129 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"};
126 char *title = error_code[code]; 130 char *title = error_code[code];
@@ -140,7 +144,7 @@ ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) {
140 return ws->reply_size = -2; 144 return ws->reply_size = -2;
141} 145}
142 146
143ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) { 147ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) {
144 struct http_data *cookie = io_getcookie(sock); 148 struct http_data *cookie = io_getcookie(sock);
145 io_batch *current; 149 io_batch *current;
146 char *header; 150 char *header;
@@ -154,8 +158,15 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t io
154 HTTPERROR_500; 158 HTTPERROR_500;
155 } 159 }
156 160
161 /* Descriptor numbers get recycled, so a result can only belong to this
162 connection if this connection is in fact waiting for one. */
163 if (!(cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER))) {
164 iovec_free(&iovec_entries, &iovector);
165 return 0;
166 }
167
157 /* If this socket collected request in a buffer, free it now */ 168 /* If this socket collected request in a buffer, free it now */
158 array_reset(&cookie->request); 169 buf_reset(&cookie->request);
159 170
160 /* If we came here, wait for the answer is over */ 171 /* If we came here, wait for the answer is over */
161 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { 172 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) {
@@ -232,7 +243,7 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t io
232 return 0; 243 return 0;
233} 244}
234 245
235static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { 246static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) {
236 static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}}; 247 static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}};
237 static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS}, 248 static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS},
238 {"conn", TASK_STATS_CONNS}, 249 {"conn", TASK_STATS_CONNS},
@@ -263,12 +274,16 @@ static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, cha
263 {"url", TASK_FULLSCRAPE_TPB_URLENCODED}, {"txt", TASK_FULLSCRAPE_TPB_ASCII}, 274 {"url", TASK_FULLSCRAPE_TPB_URLENCODED}, {"txt", TASK_FULLSCRAPE_TPB_ASCII},
264 {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}}; 275 {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}};
265 276
266 int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
267
268#ifdef WANT_RESTRICT_STATS
269 struct http_data *cookie = io_getcookie(sock); 277 struct http_data *cookie = io_getcookie(sock);
278 int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
279
280 /* A socket without one is a dead socket, which is what http_sendiovecdata
281 already answers 500 to. */
282 if (!cookie)
283 HTTPERROR_500;
270 284
271 if (!cookie || !accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_STAT)) 285#ifdef WANT_RESTRICT_STATS
286 if (!accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_STAT))
272 HTTPERROR_403_IP; 287 HTTPERROR_403_IP;
273#endif 288#endif
274 289
@@ -302,10 +317,9 @@ static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, cha
302 } 317 }
303 318
304 if (mode == TASK_STATS_TPB) { 319 if (mode == TASK_STATS_TPB) {
305 struct http_data *cookie = io_getcookie(sock); 320 tai6464 t;
306 tai6464 t;
307#ifdef WANT_COMPRESSION_GZIP 321#ifdef WANT_COMPRESSION_GZIP
308 ws->request[ws->request_size] = 0; 322 ws->request[ws->request_size - 1] = 0;
309#ifndef WANT_COMPRESSION_GZIP_ALWAYS 323#ifndef WANT_COMPRESSION_GZIP_ALWAYS
310 if (strstr(read_ptr - 1, "gzip")) { 324 if (strstr(read_ptr - 1, "gzip")) {
311#endif 325#endif
@@ -330,6 +344,9 @@ static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, cha
330 /* default format for now */ 344 /* default format for now */
331 if ((mode & TASK_CLASS_MASK) == TASK_STATS) { 345 if ((mode & TASK_CLASS_MASK) == TASK_STATS) {
332 tai6464 t; 346 tai6464 t;
347
348 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;
349
333 /* Complex stats also include expensive memory debugging tools */ 350 /* Complex stats also include expensive memory debugging tools */
334 taia_uint(&t, 0); 351 taia_uint(&t, 0);
335 io_timeout(sock, t); 352 io_timeout(sock, t);
@@ -351,7 +368,7 @@ typedef struct {
351#endif 368#endif
352 369
353#ifdef WANT_FULLSCRAPE 370#ifdef WANT_FULLSCRAPE
354static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws) { 371static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *ws) {
355 struct http_data *cookie = io_getcookie(sock); 372 struct http_data *cookie = io_getcookie(sock);
356 int format = 0; 373 int format = 0;
357 tai6464 t; 374 tai6464 t;
@@ -421,7 +438,7 @@ static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws
421} 438}
422#endif 439#endif
423 440
424static ssize_t http_handle_scrape(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { 441static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) {
425 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; 442 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}};
426 443
427 ot_hash *multiscrape_buf = (ot_hash *)ws->request; 444 ot_hash *multiscrape_buf = (ot_hash *)ws->request;
@@ -500,7 +517,7 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event",
500#endif 517#endif
501 {"peer_id", 9}, {NULL, -3}}; 518 {"peer_id", 9}, {NULL, -3}};
502static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; 519static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}};
503static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { 520static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) {
504 size_t numwant; 521 size_t numwant;
505 int tmp, scanon; 522 int tmp, scanon;
506 unsigned short port = 0; 523 unsigned short port = 0;
@@ -521,7 +538,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *
521 if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) { 538 if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) {
522 ot_ip6 proxied_ip; 539 ot_ip6 proxied_ip;
523 char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for"); 540 char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for");
524 if (fwd && scan_ip6(fwd, proxied_ip)) { 541 if (fwd && ip_scan(fwd, proxied_ip)) {
525 OT_SETIP(ws->peer, proxied_ip); 542 OT_SETIP(ws->peer, proxied_ip);
526 } else 543 } else
527 OT_SETIP(ws->peer, cookie->ip); 544 OT_SETIP(ws->peer, cookie->ip);
@@ -607,7 +624,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *
607 char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; 624 char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16;
608 len = scan_urlencoded_query(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); 625 len = scan_urlencoded_query(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE);
609 tmp_buf2[len] = 0; 626 tmp_buf2[len] = 0;
610 if ((len <= 0) || !scan_ip6(tmp_buf2, tmp_buf1)) 627 if ((len <= 0) || !ip_scan(tmp_buf2, tmp_buf1))
611 HTTPERROR_400_PARAM; 628 HTTPERROR_400_PARAM;
612 OT_SETIP(&ws->peer, tmp_buf1); 629 OT_SETIP(&ws->peer, tmp_buf1);
613 } break; 630 } break;
@@ -629,7 +646,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *
629 loglist_reset(); 646 loglist_reset();
630 return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n"); 647 return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n");
631 } 648 }
632 parsed = scan_ip6(tmp_buf, net.address); 649 parsed = ip_scan(tmp_buf, net.address);
633 if (!parsed) 650 if (!parsed)
634 HTTPERROR_400_PARAM; 651 HTTPERROR_400_PARAM;
635 if (tmp_buf[parsed++] != '/') 652 if (tmp_buf[parsed++] != '/')
@@ -639,7 +656,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *
639 if (!parsed) 656 if (!parsed)
640 HTTPERROR_400_PARAM; 657 HTTPERROR_400_PARAM;
641 bits = (signed short)value; 658 bits = (signed short)value;
642 if (ip6_isv4mapped(net.address)) 659 if (ip_is_v4mapped(net.address))
643 bits += 96; 660 bits += 96;
644 } 661 }
645 net.bits = bits; 662 net.bits = bits;
@@ -678,7 +695,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *
678 return ws->reply_size; 695 return ws->reply_size;
679} 696}
680 697
681ssize_t http_handle_request(const int64 sock, struct ot_workstruct *ws) { 698ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) {
682 ssize_t reply_off, len; 699 ssize_t reply_off, len;
683 char *read_ptr = ws->request, *write_ptr; 700 char *read_ptr = ws->request, *write_ptr;
684 701