summaryrefslogtreecommitdiff
path: root/ot_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_http.c')
-rw-r--r--ot_http.c834
1 files changed, 494 insertions, 340 deletions
diff --git a/ot_http.c b/ot_http.c
index 0e3cc29..e4486fc 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -4,506 +4,655 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#include <sys/types.h> 7#define _GNU_SOURCE
8#include <arpa/inet.h> 8#include <arpa/inet.h>
9#include <stdlib.h> 9#include <pthread.h>
10#include <stdio.h> 10#include <stdio.h>
11#include <stdlib.h>
11#include <string.h> 12#include <string.h>
13#include <sys/types.h>
12#include <unistd.h> 14#include <unistd.h>
13#include <pthread.h>
14 15
15/* Libowfat */ 16/* Libowfat */
16#include "byte.h"
17#include "array.h" 17#include "array.h"
18#include "byte.h"
19#include "case.h"
18#include "iob.h" 20#include "iob.h"
19#include "ip6.h" 21#include "ip6.h"
20#include "scan.h" 22#include "scan.h"
21#include "case.h"
22 23
23/* Opentracker */ 24/* Opentracker */
24#include "trackerlogic.h" 25#include "ot_accesslist.h"
25#include "ot_mutex.h" 26#include "ot_fullscrape.h"
26#include "ot_http.h" 27#include "ot_http.h"
27#include "ot_iovec.h" 28#include "ot_iovec.h"
28#include "scan_urlencoded_query.h" 29#include "ot_mutex.h"
29#include "ot_fullscrape.h"
30#include "ot_stats.h" 30#include "ot_stats.h"
31#include "ot_accesslist.h" 31#include "scan_urlencoded_query.h"
32#include "trackerlogic.h"
33
34#ifdef WANT_NO_AUTO_FREE
35#define OT_IOB_INIT(B) (bzero(B, sizeof(io_batch)), 0)
36#else
37#define OT_IOB_INIT(B) iob_init_autofree(B, 0)
38#endif
32 39
33#define OT_MAXMULTISCRAPE_COUNT 64 40#define OT_MAXMULTISCRAPE_COUNT 64
41#define OT_BATCH_LIMIT (1024 * 1024 * 16)
34extern char *g_redirecturl; 42extern char *g_redirecturl;
35 43
36char *g_stats_path; 44char *g_stats_path;
37ssize_t g_stats_path_len; 45ssize_t g_stats_path_len;
38 46
39enum { 47enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 };
40 SUCCESS_HTTP_HEADER_LENGTH = 80,
41 SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING = 32,
42 SUCCESS_HTTP_SIZE_OFF = 17 };
43 48
44static void http_senddata( const int64 sock, struct ot_workstruct *ws ) { 49static void http_senddata(const int64 sock, struct ot_workstruct *ws) {
45 struct http_data *cookie = io_getcookie( sock ); 50 struct http_data *cookie = io_getcookie(sock);
46 ssize_t written_size; 51 ssize_t written_size;
47 52
48 if( !cookie ) { io_close(sock); return; } 53 if (!cookie) {
54 io_close(sock);
55 return;
56 }
49 57
50 /* whoever sends data is not interested in its input-array */ 58 /* whoever sends data is not interested in its input-array */
51 if( ws->keep_alive && ws->header_size != ws->request_size ) { 59 if (ws->keep_alive && ws->header_size != ws->request_size) {
52 size_t rest = ws->request_size - ws->header_size; 60 size_t rest = ws->request_size - ws->header_size;
53 if( array_start(&cookie->request) ) { 61 if (array_start(&cookie->request)) {
54 memmove( array_start(&cookie->request), ws->request + ws->header_size, rest ); 62 memmove(array_start(&cookie->request), ws->request + ws->header_size, rest);
55 array_truncate( &cookie->request, 1, rest ); 63 array_truncate(&cookie->request, 1, rest);
56 } else 64 } else
57 array_catb(&cookie->request, ws->request + ws->header_size, rest ); 65 array_catb(&cookie->request, ws->request + ws->header_size, rest);
58 } else 66 } else
59 array_reset( &cookie->request ); 67 array_reset(&cookie->request);
60 68
61 written_size = write( sock, ws->reply, ws->reply_size ); 69 written_size = write(sock, ws->reply, ws->reply_size);
62 if( ( written_size < 0 ) || ( ( written_size == ws->reply_size ) && !ws->keep_alive ) ) { 70 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) {
63 array_reset( &cookie->request ); 71 array_reset(&cookie->request);
64 free( cookie ); io_close( sock ); return; 72 free(cookie);
73 io_close(sock);
74 return;
65 } 75 }
66 76
67 if( written_size < ws->reply_size ) { 77 if (written_size < ws->reply_size) {
68 char * outbuf; 78 char *outbuf;
69 tai6464 t; 79 tai6464 t;
70 80
71 if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) { 81 if (!(outbuf = malloc(ws->reply_size - written_size))) {
72 array_reset( &cookie->request ); 82 array_reset(&cookie->request);
73 free(cookie); io_close( sock ); 83 free(cookie);
84 io_close(sock);
74 return; 85 return;
75 } 86 }
76 87
77 memcpy( outbuf, ws->reply + written_size, ws->reply_size - written_size ); 88 memcpy(outbuf, ws->reply + written_size, ws->reply_size - written_size);
78 iob_addbuf_free( &cookie->batch, outbuf, ws->reply_size - written_size ); 89 if (!cookie->batch) {
90 cookie->batch = malloc(sizeof(io_batch));
91 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) {
92 free(cookie->batch);
93 free(outbuf);
94 array_reset(&cookie->request);
95 free(cookie);
96 io_close(sock);
97 return;
98 }
99
100 cookie->batches = 1;
101 }
102
103 iob_addbuf_free(cookie->batch, outbuf, ws->reply_size - written_size);
79 104
80 /* writeable short data sockets just have a tcp timeout */ 105 /* writeable short data sockets just have a tcp timeout */
81 if( !ws->keep_alive ) { 106 if (!ws->keep_alive) {
82 taia_uint( &t, 0 ); io_timeout( sock, t ); 107 taia_uint(&t, 0);
83 io_dontwantread( sock ); 108 io_timeout(sock, t);
109 io_dontwantread(sock);
84 } 110 }
85 io_wantwrite( sock ); 111 io_wantwrite(sock);
86 } 112 }
87} 113}
88 114
89#define HTTPERROR_302 return http_issue_error( sock, ws, CODE_HTTPERROR_302 ) 115#define HTTPERROR_302 return http_issue_error(sock, ws, CODE_HTTPERROR_302)
90#define HTTPERROR_400 return http_issue_error( sock, ws, CODE_HTTPERROR_400 ) 116#define HTTPERROR_400 return http_issue_error(sock, ws, CODE_HTTPERROR_400)
91#define HTTPERROR_400_PARAM return http_issue_error( sock, ws, CODE_HTTPERROR_400_PARAM ) 117#define HTTPERROR_400_PARAM return http_issue_error(sock, ws, CODE_HTTPERROR_400_PARAM)
92#define HTTPERROR_400_COMPACT return http_issue_error( sock, ws, CODE_HTTPERROR_400_COMPACT ) 118#define HTTPERROR_400_COMPACT return http_issue_error(sock, ws, CODE_HTTPERROR_400_COMPACT)
93#define HTTPERROR_400_DOUBLEHASH return http_issue_error( sock, ws, CODE_HTTPERROR_400_PARAM ) 119#define HTTPERROR_400_DOUBLEHASH return http_issue_error(sock, ws, CODE_HTTPERROR_400_PARAM)
94#define HTTPERROR_402_NOTMODEST return http_issue_error( sock, ws, CODE_HTTPERROR_402_NOTMODEST ) 120#define HTTPERROR_402_NOTMODEST return http_issue_error(sock, ws, CODE_HTTPERROR_402_NOTMODEST)
95#define HTTPERROR_403_IP return http_issue_error( sock, ws, CODE_HTTPERROR_403_IP ) 121#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP)
96#define HTTPERROR_404 return http_issue_error( sock, ws, CODE_HTTPERROR_404 ) 122#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404)
97#define HTTPERROR_500 return http_issue_error( sock, ws, CODE_HTTPERROR_500 ) 123#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500)
98ssize_t http_issue_error( const int64 sock, struct ot_workstruct *ws, int code ) { 124ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) {
99 char *error_code[] = { "302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", 125 char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required",
100 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error" }; 126 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"};
101 char *title = error_code[code]; 127 char *title = error_code[code];
102 128
103 ws->reply = ws->outbuf; 129 ws->reply = ws->outbuf;
104 if( code == CODE_HTTPERROR_302 ) 130 if (code == CODE_HTTPERROR_302)
105 ws->reply_size = snprintf( ws->reply, G_OUTBUF_SIZE, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl ); 131 ws->reply_size = snprintf(ws->reply, G_OUTBUF_SIZE, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl);
106 else 132 else
107 ws->reply_size = snprintf( ws->reply, G_OUTBUF_SIZE, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", title, strlen(title)+16-4,title+4); 133 ws->reply_size = snprintf(ws->reply, G_OUTBUF_SIZE, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", title,
134 strlen(title) + 16 - 4, title + 4);
108 135
109#ifdef _DEBUG_HTTPERROR 136#ifdef _DEBUG_HTTPERROR
110 fprintf( stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf ); 137 fprintf(stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf);
111#endif 138#endif
112 stats_issue_event( EVENT_FAILED, FLAG_TCP, code ); 139 stats_issue_event(EVENT_FAILED, FLAG_TCP, code);
113 http_senddata( sock, ws ); 140 http_senddata(sock, ws);
114 return ws->reply_size = -2; 141 return ws->reply_size = -2;
115} 142}
116 143
117ssize_t http_sendiovecdata( const int64 sock, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector ) { 144ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) {
118 struct http_data *cookie = io_getcookie( sock ); 145 struct http_data *cookie = io_getcookie(sock);
119 char *header; 146 io_batch *current;
120 int i; 147 char *header;
121 size_t header_size, size = iovec_length( &iovec_entries, &iovector ); 148 const char *encoding = "";
122 tai6464 t; 149 size_t i, header_size, size = iovec_length(&iovec_entries, (const struct iovec **)&iovector);
150 tai6464 t;
123 151
124 /* No cookie? Bad socket. Leave. */ 152 /* No cookie? Bad socket. Leave. */
125 if( !cookie ) { 153 if (!cookie) {
126 iovec_free( &iovec_entries, &iovector ); 154 iovec_free(&iovec_entries, &iovector);
127 HTTPERROR_500; 155 HTTPERROR_500;
128 } 156 }
129 157
130 /* If this socket collected request in a buffer, free it now */ 158 /* If this socket collected request in a buffer, free it now */
131 array_reset( &cookie->request ); 159 array_reset(&cookie->request);
132 160
133 /* If we came here, wait for the answer is over */ 161 /* If we came here, wait for the answer is over */
134 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; 162 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) {
135 163 io_dontwantread(sock);
136 /* Our answers never are 0 vectors. Return an error. */ 164 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK;
137 if( !iovec_entries ) {
138 HTTPERROR_500;
139 }
140
141 /* Prepare space for http header */
142 header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING );
143 if( !header ) {
144 iovec_free( &iovec_entries, &iovector );
145 HTTPERROR_500;
146 } 165 }
147 166
148 if( cookie->flag & STRUCT_HTTP_FLAG_GZIP ) 167 if (iovec_entries) {
149 header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Encoding: gzip\r\nContent-Length: %zd\r\n\r\n", size ); 168
150 else if( cookie->flag & STRUCT_HTTP_FLAG_BZIP2 ) 169 if (cookie->flag & STRUCT_HTTP_FLAG_ZSTD)
151 header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Encoding: bzip2\r\nContent-Length: %zd\r\n\r\n", size ); 170 encoding = "Content-Encoding: zstd\r\n";
152 else 171 else if (cookie->flag & STRUCT_HTTP_FLAG_GZIP)
153 header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); 172 encoding = "Content-Encoding: gzip\r\n";
173 else if (cookie->flag & STRUCT_HTTP_FLAG_BZIP2)
174 encoding = "Content-Encoding: bzip2\r\n";
175
176 if (!(cookie->flag & STRUCT_HTTP_FLAG_CHUNKED))
177 header_size = asprintf(&header, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n%sContent-Length: %zd\r\n\r\n", encoding, size);
178 else {
179 if (!(cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) {
180 header_size =
181 asprintf(&header, "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\n%sTransfer-Encoding: chunked\r\n\r\n%zx\r\n", encoding, size);
182 cookie->flag |= STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER;
183 } else
184 header_size = asprintf(&header, "%zx\r\n", size);
185 }
186 if (!header) {
187 iovec_free(&iovec_entries, &iovector);
188 HTTPERROR_500;
189 }
154 190
155 iob_reset( &cookie->batch ); 191 if (!cookie->batch) {
156 iob_addbuf_free( &cookie->batch, header, header_size ); 192 cookie->batch = malloc(sizeof(io_batch));
193 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) {
194 free(cookie->batch);
195 free(header);
196 iovec_free(&iovec_entries, &iovector);
197 HTTPERROR_500;
198 }
199 cookie->batches = 1;
200 }
201 current = cookie->batch + cookie->batches - 1;
202 iob_addbuf_free(current, header, header_size);
203
204 /* Split huge iovectors into separate io_batches */
205 for (i = 0; i < (size_t)iovec_entries; ++i) {
206 /* If the current batch's limit is reached, try to reallocate a new batch to work on */
207 if (current->bytesleft > OT_BATCH_LIMIT) {
208 io_batch *new_batch = realloc(cookie->batch, (cookie->batches + 1) * sizeof(io_batch));
209 if (new_batch) {
210 cookie->batch = new_batch;
211 if (OT_IOB_INIT(current) != -1)
212 current = cookie->batch + cookie->batches++;
213 }
214 }
215 iob_addbuf_free(current, iovector[i].iov_base, iovector[i].iov_len);
216 }
217 free(iovector);
218 if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)
219 iob_addbuf(current, "\r\n", 2);
220 }
157 221
158 /* Will move to ot_iovec.c */ 222 if ((cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) && cookie->batch && !is_partial) {
159 for( i=0; i<iovec_entries; ++i ) 223 current = cookie->batch + cookie->batches - 1;
160 iob_addbuf_munmap( &cookie->batch, iovector[i].iov_base, iovector[i].iov_len ); 224 iob_addbuf(current, "0\r\n\r\n", 5);
161 free( iovector ); 225 cookie->flag &= ~STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER;
226 }
162 227
163 /* writeable sockets timeout after 10 minutes */ 228 /* writeable sockets timeout after 10 minutes */
164 taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND ); 229 taia_now(&t);
165 io_timeout( sock, t ); 230 taia_addsec(&t, &t, OT_CLIENT_TIMEOUT_SEND);
166 io_dontwantread( sock ); 231 io_timeout(sock, t);
167 io_wantwrite( sock ); 232 io_wantwrite(sock);
168 return 0; 233 return 0;
169} 234}
170 235
171static ssize_t http_handle_stats( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) { 236static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, char *read_ptr) {
172static const ot_keywords keywords_main[] = 237 static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}};
173 { { "mode", 1 }, {"format", 2 }, { NULL, -3 } }; 238 static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS},
174static const ot_keywords keywords_mode[] = 239 {"conn", TASK_STATS_CONNS},
175 { { "peer", TASK_STATS_PEERS }, { "conn", TASK_STATS_CONNS }, { "scrp", TASK_STATS_SCRAPE }, { "udp4", TASK_STATS_UDP }, { "tcp4", TASK_STATS_TCP }, 240 {"scrp", TASK_STATS_SCRAPE},
176 { "busy", TASK_STATS_BUSY_NETWORKS }, { "torr", TASK_STATS_TORRENTS }, { "fscr", TASK_STATS_FULLSCRAPE }, 241 {"udp4", TASK_STATS_UDP},
177 { "s24s", TASK_STATS_SLASH24S }, { "tpbs", TASK_STATS_TPB }, { "herr", TASK_STATS_HTTPERRORS }, { "completed", TASK_STATS_COMPLETED }, 242 {"tcp4", TASK_STATS_TCP},
178 { "top100", TASK_STATS_TOP100 }, { "top10", TASK_STATS_TOP10 }, { "renew", TASK_STATS_RENEW }, { "syncs", TASK_STATS_SYNCS }, { "version", TASK_STATS_VERSION }, 243 {"busy", TASK_STATS_BUSY_NETWORKS},
179 { "everything", TASK_STATS_EVERYTHING }, { "statedump", TASK_FULLSCRAPE_TRACKERSTATE }, { "fulllog", TASK_STATS_FULLLOG }, 244 {"torr", TASK_STATS_TORRENTS},
180 { "woodpeckers", TASK_STATS_WOODPECKERS}, 245 {"fscr", TASK_STATS_FULLSCRAPE},
246 {"s24s", TASK_STATS_SLASH24S},
247 {"tpbs", TASK_STATS_TPB},
248 {"herr", TASK_STATS_HTTPERRORS},
249 {"completed", TASK_STATS_COMPLETED},
250 {"top100", TASK_STATS_TOP100},
251 {"top10", TASK_STATS_TOP10},
252 {"renew", TASK_STATS_RENEW},
253 {"syncs", TASK_STATS_SYNCS},
254 {"version", TASK_STATS_VERSION},
255 {"everything", TASK_STATS_EVERYTHING},
256 {"statedump", TASK_FULLSCRAPE_TRACKERSTATE},
257 {"fulllog", TASK_STATS_FULLLOG},
258 {"woodpeckers", TASK_STATS_WOODPECKERS},
181#ifdef WANT_LOG_NUMWANT 259#ifdef WANT_LOG_NUMWANT
182 { "numwants", TASK_STATS_NUMWANTS}, 260 {"numwants", TASK_STATS_NUMWANTS},
183#endif 261#endif
184 { NULL, -3 } }; 262 {NULL, -3}};
185static const ot_keywords keywords_format[] = 263 static const ot_keywords keywords_format[] = {{"bin", TASK_FULLSCRAPE_TPB_BINARY}, {"ben", TASK_FULLSCRAPE},
186 { { "bin", TASK_FULLSCRAPE_TPB_BINARY }, { "ben", TASK_FULLSCRAPE }, { "url", TASK_FULLSCRAPE_TPB_URLENCODED }, 264 {"url", TASK_FULLSCRAPE_TPB_URLENCODED}, {"txt", TASK_FULLSCRAPE_TPB_ASCII},
187 { "txt", TASK_FULLSCRAPE_TPB_ASCII }, { "txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS }, { NULL, -3 } }; 265 {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}};
188 266
189 int mode = TASK_STATS_PEERS, scanon = 1, format = 0; 267 int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
190 268
191#ifdef WANT_RESTRICT_STATS 269#ifdef WANT_RESTRICT_STATS
192 struct http_data *cookie = io_getcookie( sock ); 270 struct http_data *cookie = io_getcookie(sock);
193 271
194 if( !cookie || !accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_STAT ) ) 272 if (!cookie || !accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_STAT))
195 HTTPERROR_403_IP; 273 HTTPERROR_403_IP;
196#endif 274#endif
197 275
198 while( scanon ) { 276 while (scanon) {
199 switch( scan_find_keywords( keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { 277 switch (scan_find_keywords(keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM)) {
200 case -2: scanon = 0; break; /* TERMINATOR */ 278 case -2:
201 case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ 279 scanon = 0;
202 case -3: scan_urlencoded_skipvalue( &read_ptr ); break; 280 break; /* TERMINATOR */
203 case 1: /* matched "mode" */ 281 case -1:
204 if( ( mode = scan_find_keywords( keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; 282 HTTPERROR_400_PARAM; /* PARSE ERROR */
283 case -3:
284 scan_urlencoded_skipvalue(&read_ptr);
285 break;
286 case 1: /* matched "mode" */
287 if ((mode = scan_find_keywords(keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0)
288 HTTPERROR_400_PARAM;
205 break; 289 break;
206 case 2: /* matched "format" */ 290 case 2: /* matched "format" */
207 if( ( format = scan_find_keywords( keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; 291 if ((format = scan_find_keywords(keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0)
292 HTTPERROR_400_PARAM;
208 break; 293 break;
294 case 3:
295 HTTPERROR_400_PARAM; /* If the stats URL was mistakenly added as announce URL, return a 400 */
209 } 296 }
210 } 297 }
211 298
212#ifdef WANT_FULLSCRAPE 299#ifdef WANT_FULLSCRAPE
213 if( mode == TASK_FULLSCRAPE_TRACKERSTATE ) { 300 if (mode == TASK_FULLSCRAPE_TRACKERSTATE) {
214 format = mode; mode = TASK_STATS_TPB; 301 format = mode;
302 mode = TASK_STATS_TPB;
215 } 303 }
216 304
217 if( mode == TASK_STATS_TPB ) { 305 if (mode == TASK_STATS_TPB) {
218 struct http_data* cookie = io_getcookie( sock ); 306 struct http_data *cookie = io_getcookie(sock);
219 tai6464 t; 307 tai6464 t;
220#ifdef WANT_COMPRESSION_GZIP 308#ifdef WANT_COMPRESSION_GZIP
221 ws->request[ws->request_size] = 0; 309 ws->request[ws->request_size] = 0;
222#ifdef WANT_COMPRESSION_GZIP_ALWAYS 310#ifndef WANT_COMPRESSION_GZIP_ALWAYS
223 if( strstr( read_ptr - 1, "gzip" ) ) { 311 if (strstr(read_ptr - 1, "gzip")) {
224#endif 312#endif
225 cookie->flag |= STRUCT_HTTP_FLAG_GZIP; 313 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
226 format |= TASK_FLAG_GZIP; 314 format |= TASK_FLAG_GZIP;
227#ifdef WANT_COMPRESSION_GZIP_ALWAYS 315#ifndef WANT_COMPRESSION_GZIP_ALWAYS
228 } 316 }
229#endif 317#endif
230#endif 318#endif
231 /* Pass this task to the worker thread */ 319 /* Pass this task to the worker thread */
232 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; 320 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED;
233 321
234 /* Clients waiting for us should not easily timeout */ 322 /* Clients waiting for us should not easily timeout */
235 taia_uint( &t, 0 ); io_timeout( sock, t ); 323 taia_uint(&t, 0);
236 fullscrape_deliver( sock, format ); 324 io_timeout(sock, t);
237 io_dontwantread( sock ); 325 fullscrape_deliver(sock, format);
326 io_dontwantread(sock);
238 return ws->reply_size = -2; 327 return ws->reply_size = -2;
239 } 328 }
240#endif 329#endif
241 330
242 /* default format for now */ 331 /* default format for now */
243 if( ( mode & TASK_CLASS_MASK ) == TASK_STATS ) { 332 if ((mode & TASK_CLASS_MASK) == TASK_STATS) {
244 tai6464 t; 333 tai6464 t;
245 /* Complex stats also include expensive memory debugging tools */ 334 /* Complex stats also include expensive memory debugging tools */
246 taia_uint( &t, 0 ); io_timeout( sock, t ); 335 taia_uint(&t, 0);
247 stats_deliver( sock, mode ); 336 io_timeout(sock, t);
337 stats_deliver(sock, mode);
248 return ws->reply_size = -2; 338 return ws->reply_size = -2;
249 } 339 }
250 340
251 /* Simple stats can be answerred immediately */ 341 /* Simple stats can be answerred immediately */
252 return ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 ); 342 return ws->reply_size = return_stats_for_tracker(ws->reply, mode, 0);
253} 343}
254 344
255#ifdef WANT_MODEST_FULLSCRAPES 345#ifdef WANT_MODEST_FULLSCRAPES
256static pthread_mutex_t g_modest_fullscrape_mutex = PTHREAD_MUTEX_INITIALIZER; 346static pthread_mutex_t g_modest_fullscrape_mutex = PTHREAD_MUTEX_INITIALIZER;
257static ot_vector g_modest_fullscrape_timeouts; 347static ot_vector g_modest_fullscrape_timeouts;
258typedef struct { ot_ip6 ip; ot_time last_fullscrape; } ot_scrape_log; 348typedef struct {
349 ot_ip6 ip;
350 ot_time last_fullscrape;
351} ot_scrape_log;
259#endif 352#endif
260 353
261#ifdef WANT_FULLSCRAPE 354#ifdef WANT_FULLSCRAPE
262static ssize_t http_handle_fullscrape( const int64 sock, struct ot_workstruct *ws ) { 355static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws) {
263 struct http_data* cookie = io_getcookie( sock ); 356 struct http_data *cookie = io_getcookie(sock);
264 int format = 0; 357 int format = 0;
265 tai6464 t; 358 tai6464 t;
266 359
267#ifdef WANT_MODEST_FULLSCRAPES 360#ifdef WANT_MODEST_FULLSCRAPES
268 { 361 {
269 ot_scrape_log this_peer, *new_peer; 362 ot_scrape_log this_peer, *new_peer;
270 int exactmatch; 363 int exactmatch;
271 memcpy( this_peer.ip, cookie->ip, sizeof(ot_ip6)); 364 memcpy(this_peer.ip, cookie->ip, sizeof(ot_ip6));
272 this_peer.last_fullscrape = g_now_seconds; 365 this_peer.last_fullscrape = g_now_seconds;
273 pthread_mutex_lock(&g_modest_fullscrape_mutex); 366 pthread_mutex_lock(&g_modest_fullscrape_mutex);
274 new_peer = vector_find_or_insert( &g_modest_fullscrape_timeouts, &this_peer, sizeof(ot_scrape_log), sizeof(ot_ip6), &exactmatch ); 367 new_peer = vector_find_or_insert(&g_modest_fullscrape_timeouts, &this_peer, sizeof(ot_scrape_log), sizeof(ot_ip6), &exactmatch);
275 if( !new_peer ) { 368 if (!new_peer) {
276 pthread_mutex_unlock(&g_modest_fullscrape_mutex); 369 pthread_mutex_unlock(&g_modest_fullscrape_mutex);
277 HTTPERROR_500; 370 HTTPERROR_500;
278 } 371 }
279 if( exactmatch && ( this_peer.last_fullscrape - new_peer->last_fullscrape ) < OT_MODEST_PEER_TIMEOUT ) { 372 if (exactmatch && (this_peer.last_fullscrape - new_peer->last_fullscrape) < OT_MODEST_PEER_TIMEOUT) {
280 pthread_mutex_unlock(&g_modest_fullscrape_mutex); 373 pthread_mutex_unlock(&g_modest_fullscrape_mutex);
281 HTTPERROR_402_NOTMODEST; 374 HTTPERROR_402_NOTMODEST;
282 } 375 }
283 memcpy( new_peer, &this_peer, sizeof(ot_scrape_log)); 376 memcpy(new_peer, &this_peer, sizeof(ot_scrape_log));
284 pthread_mutex_unlock(&g_modest_fullscrape_mutex); 377 pthread_mutex_unlock(&g_modest_fullscrape_mutex);
285 } 378 }
286#endif 379#endif
287 380
381
382#if defined(WANT_COMPRESSION_GZIP) || defined(WANT_COMPRESSION_ZSTD)
383 ws->request[ws->request_size - 1] = 0;
288#ifdef WANT_COMPRESSION_GZIP 384#ifdef WANT_COMPRESSION_GZIP
289 ws->request[ws->request_size-1] = 0; 385 if (strstr(ws->request, "gzip")) {
290 if( strstr( ws->request, "gzip" ) ) {
291 cookie->flag |= STRUCT_HTTP_FLAG_GZIP; 386 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
292 format = TASK_FLAG_GZIP; 387 format |= TASK_FLAG_GZIP;
293 stats_issue_event( EVENT_FULLSCRAPE_REQUEST_GZIP, 0, (uintptr_t)cookie->ip ); 388 }
294 } else 389#endif
390#ifdef WANT_COMPRESSION_ZSTD
391 if (strstr(ws->request, "zstd")) {
392 cookie->flag |= STRUCT_HTTP_FLAG_ZSTD;
393 format |= TASK_FLAG_ZSTD;
394 }
395#endif
396
397#if defined(WANT_COMPRESSION_ZSTD) && defined(WANT_COMPRESSION_ZSTD_ALWAYS)
398 cookie->flag |= STRUCT_HTTP_FLAG_ZSTD;
399 format |= TASK_FLAG_ZSTD;
400#endif
401
402#if defined(WANT_COMPRESSION_GZIP) && defined(WANT_COMPRESSION_GZIP_ALWAYS)
403 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
404 format |= TASK_FLAG_GZIP;
295#endif 405#endif
296 stats_issue_event( EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip ); 406#endif
407
408 stats_issue_event(EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip);
297 409
298#ifdef _DEBUG_HTTPERROR 410#ifdef _DEBUG_HTTPERROR
299 fprintf( stderr, "%s", ws->debugbuf ); 411 fprintf(stderr, "%s", ws->debugbuf);
300#endif 412#endif
301 413
302 /* Pass this task to the worker thread */ 414 /* Pass this task to the worker thread */
303 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; 415 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED;
304 /* Clients waiting for us should not easily timeout */ 416 /* Clients waiting for us should not easily timeout */
305 taia_uint( &t, 0 ); io_timeout( sock, t ); 417 taia_uint(&t, 0);
306 fullscrape_deliver( sock, TASK_FULLSCRAPE | format ); 418 io_timeout(sock, t);
307 io_dontwantread( sock ); 419 fullscrape_deliver(sock, TASK_FULLSCRAPE | format);
420 io_dontwantread(sock);
308 return ws->reply_size = -2; 421 return ws->reply_size = -2;
309} 422}
310#endif 423#endif
311 424
312static ssize_t http_handle_scrape( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) { 425static ssize_t http_handle_scrape(const int64 sock, struct ot_workstruct *ws, char *read_ptr) {
313 static const ot_keywords keywords_scrape[] = { { "info_hash", 1 }, { NULL, -3 } }; 426 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}};
314 427
315 ot_hash * multiscrape_buf = (ot_hash*)ws->request; 428 ot_hash *multiscrape_buf = (ot_hash *)ws->request;
316 int scanon = 1, numwant = 0; 429 int scanon = 1;
430 size_t numwant = 0;
317 431
318 /* This is to hack around stupid clients that send "scrape ?info_hash" */ 432 /* This is to hack around stupid clients that send "scrape ?info_hash" */
319 if( read_ptr[-1] != '?' ) { 433 if (read_ptr[-1] != '?') {
320 while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; 434 while ((*read_ptr != '?') && (*read_ptr != '\n'))
321 if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; 435 ++read_ptr;
436 if (*read_ptr == '\n')
437 HTTPERROR_400_PARAM;
322 ++read_ptr; 438 ++read_ptr;
323 } 439 }
324 440
325 while( scanon ) { 441 while (scanon) {
326 switch( scan_find_keywords( keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { 442 switch (scan_find_keywords(keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM)) {
327 case -2: scanon = 0; break; /* TERMINATOR */ 443 case -2:
328 default: HTTPERROR_400_PARAM; /* PARSE ERROR */ 444 scanon = 0;
329 case -3: scan_urlencoded_skipvalue( &read_ptr ); break; 445 break; /* TERMINATOR */
330 case 1: /* matched "info_hash" */ 446 default:
447 HTTPERROR_400_PARAM; /* PARSE ERROR */
448 case -3:
449 scan_urlencoded_skipvalue(&read_ptr);
450 break;
451 case 1: /* matched "info_hash" */
331 /* ignore this, when we have less than 20 bytes */ 452 /* ignore this, when we have less than 20 bytes */
332 if( scan_urlencoded_query( &read_ptr, (char*)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) ) 453 if (scan_urlencoded_query(&read_ptr, (char *)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE) != (ssize_t)sizeof(ot_hash))
333 HTTPERROR_400_PARAM; 454 HTTPERROR_400_PARAM;
334 break; 455 break;
335 } 456 }
336 } 457 }
337 458
338 /* No info_hash found? Inform user */ 459 /* No info_hash found? Inform user */
339 if( !numwant ) HTTPERROR_400_PARAM; 460 if (!numwant)
461 HTTPERROR_400_PARAM;
340 462
341 /* Limit number of hashes to process */ 463 /* Limit number of hashes to process */
342 if( numwant > OT_MAXMULTISCRAPE_COUNT ) 464 if (numwant > OT_MAXMULTISCRAPE_COUNT)
343 numwant = OT_MAXMULTISCRAPE_COUNT; 465 numwant = OT_MAXMULTISCRAPE_COUNT;
344 466
345 /* Enough for http header + whole scrape string */ 467 /* Enough for http header + whole scrape string */
346 ws->reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, ws->reply ); 468 ws->reply_size = return_tcp_scrape_for_torrent((const ot_hash *)multiscrape_buf, numwant, ws->reply);
347 stats_issue_event( EVENT_SCRAPE, FLAG_TCP, ws->reply_size ); 469 stats_issue_event(EVENT_SCRAPE, FLAG_TCP, ws->reply_size);
348 return ws->reply_size; 470 return ws->reply_size;
349} 471}
350 472
351#ifdef WANT_LOG_NUMWANT 473#ifdef WANT_LOG_NUMWANT
352 unsigned long long numwants[201]; 474unsigned long long numwants[201];
353#endif 475#endif
354 476
355#if defined( WANT_KEEPALIVE ) || defined( WANT_IP_FROM_PROXY ) 477#if defined(WANT_KEEPALIVE) || defined(WANT_IP_FROM_PROXY)
356static char* http_header( char *data, size_t byte_count, char *header ) { 478static char *http_header(char *data, size_t byte_count, char *header) {
357 size_t i; 479 size_t i;
358 long sl = strlen( header ); 480 long sl = strlen(header);
359 for( i = 0; i + sl + 2 < byte_count; ++i ) { 481 for (i = 0; i + sl + 2 < byte_count; ++i) {
360 if( data[i] != '\n' || data[ i + sl + 1] != ':' ) continue; 482 if (data[i] != '\n' || data[i + sl + 1] != ':')
361 if( !case_equalb( data + i + 1, sl, header ) ) continue; 483 continue;
484 if (!case_equalb(data + i + 1, sl, header))
485 continue;
362 data += i + sl + 2; 486 data += i + sl + 2;
363 while( *data == ' ' || *data == '\t' ) ++data; 487 while (*data == ' ' || *data == '\t')
488 ++data;
364 return data; 489 return data;
365 } 490 }
366 return 0; 491 return 0;
367} 492}
368#endif 493#endif
369 494
370static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "event", 3 }, { "numwant", 4 }, { "compact", 5 }, { "compact6", 5 }, { "info_hash", 6 }, 495static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event", 3}, {"numwant", 4}, {"compact", 5}, {"compact6", 5}, {"info_hash", 6},
371#ifdef WANT_IP_FROM_QUERY_STRING 496#ifdef WANT_IP_FROM_QUERY_STRING
372{ "ip", 7 }, 497 {"ip", 7},
373#endif 498#endif
374#ifdef WANT_FULLLOG_NETWORKS 499#ifdef WANT_FULLLOG_NETWORKS
375{ "lognet", 8 }, 500 {"lognet", 8},
376#endif 501#endif
377{ "peer_id", 9 }, 502 {"peer_id", 9}, {NULL, -3}};
378{ NULL, -3 } }; 503static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}};
379static ot_keywords keywords_announce_event[] = { { "completed", 1 }, { "stopped", 2 }, { NULL, -3 } }; 504static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *ws, char *read_ptr) {
380static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) { 505 size_t numwant;
381 int numwant, tmp, scanon; 506 int tmp, scanon;
382 unsigned short port = 0; 507 unsigned short port = 0;
383 char *write_ptr; 508 char *write_ptr;
384 ssize_t len; 509 ssize_t len;
385 struct http_data *cookie = io_getcookie( sock ); 510 struct http_data *cookie = io_getcookie(sock);
386 511
387 /* This is to hack around stupid clients that send "announce ?info_hash" */ 512 /* This is to hack around stupid clients that send "announce ?info_hash" */
388 if( read_ptr[-1] != '?' ) { 513 if (read_ptr[-1] != '?') {
389 while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; 514 while ((*read_ptr != '?') && (*read_ptr != '\n'))
390 if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; 515 ++read_ptr;
516 if (*read_ptr == '\n')
517 HTTPERROR_400_PARAM;
391 ++read_ptr; 518 ++read_ptr;
392 } 519 }
393 520
394#ifdef WANT_IP_FROM_PROXY 521#ifdef WANT_IP_FROM_PROXY
395 if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_PROXY ) ) { 522 if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) {
396 ot_ip6 proxied_ip; 523 ot_ip6 proxied_ip;
397 char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" ); 524 char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for");
398 if( fwd && scan_ip6( fwd, proxied_ip ) ) 525 if (fwd && scan_ip6(fwd, proxied_ip)) {
399 OT_SETIP( &ws->peer, proxied_ip ); 526 OT_SETIP(ws->peer, proxied_ip);
400 else 527 } else
401 OT_SETIP( &ws->peer, cookie->ip ); 528 OT_SETIP(ws->peer, cookie->ip);
402 } else 529 } else
403#endif 530#endif
404 OT_SETIP( &ws->peer, cookie->ip ); 531 OT_SETIP(ws->peer, cookie->ip);
405 532
406 ws->peer_id = NULL; 533 ws->peer_id = NULL;
407 ws->hash = NULL; 534 ws->hash = NULL;
408 535
409 OT_SETPORT( &ws->peer, &port ); 536 OT_SETPORT(ws->peer, &port);
410 OT_PEERFLAG( &ws->peer ) = 0; 537 OT_PEERFLAG(ws->peer) = 0;
411 numwant = 50; 538 numwant = 50;
412 scanon = 1; 539 scanon = 1;
413 540
414 while( scanon ) { 541 while (scanon) {
415 switch( scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { 542 switch (scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM)) {
416 case -2: scanon = 0; break; /* TERMINATOR */ 543 case -2:
417 case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ 544 scanon = 0;
418 case -3: scan_urlencoded_skipvalue( &read_ptr ); break; 545 break; /* TERMINATOR */
546 case -1:
547 HTTPERROR_400_PARAM; /* PARSE ERROR */
548 case -3:
549 scan_urlencoded_skipvalue(&read_ptr);
550 break;
419 case 1: /* matched "port" */ 551 case 1: /* matched "port" */
420 len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); 552 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
421 if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; 553 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp) || (tmp > 0xffff))
422 port = htons( tmp ); OT_SETPORT( &ws->peer, &port ); 554 HTTPERROR_400_PARAM;
555 port = htons(tmp);
556 OT_SETPORT(&ws->peer, &port);
423 break; 557 break;
424 case 2: /* matched "left" */ 558 case 2: /* matched "left" */
425 if( ( len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; 559 if ((len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0)
426 if( scan_fixed_int( write_ptr, len, &tmp ) ) tmp = 0; 560 HTTPERROR_400_PARAM;
427 if( !tmp ) OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING; 561 if (scan_fixed_int(write_ptr, len, &tmp))
562 tmp = 0;
563 if (!tmp)
564 OT_PEERFLAG(&ws->peer) |= PEER_FLAG_SEEDING;
428 break; 565 break;
429 case 3: /* matched "event" */ 566 case 3: /* matched "event" */
430 switch( scan_find_keywords( keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) { 567 switch (scan_find_keywords(keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE)) {
431 case -1: HTTPERROR_400_PARAM; 568 case -1:
432 case 1: /* matched "completed" */ 569 HTTPERROR_400_PARAM;
433 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; 570 case 1: /* matched "completed" */
434 break; 571 OT_PEERFLAG(&ws->peer) |= PEER_FLAG_COMPLETED;
435 case 2: /* matched "stopped" */ 572 break;
436 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; 573 case 2: /* matched "stopped" */
437 break; 574 OT_PEERFLAG(&ws->peer) |= PEER_FLAG_STOPPED;
438 default: 575 break;
439 break; 576 default:
577 break;
440 } 578 }
441 break; 579 break;
442 case 4: /* matched "numwant" */ 580 case 4: /* matched "numwant" */
443 len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); 581 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
444 if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &numwant ) ) HTTPERROR_400_PARAM; 582 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp))
445 if( numwant < 0 ) numwant = 50; 583 HTTPERROR_400_PARAM;
446 if( numwant > 200 ) numwant = 200; 584 if (tmp < 0)
585 tmp = 50;
586 if (tmp > 200)
587 tmp = 200;
588 numwant = tmp;
447 break; 589 break;
448 case 5: /* matched "compact" */ 590 case 5: /* matched "compact" */
449 len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); 591 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
450 if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) ) HTTPERROR_400_PARAM; 592 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp))
451 if( !tmp ) HTTPERROR_400_COMPACT; 593 HTTPERROR_400_PARAM;
594 if (!tmp)
595 HTTPERROR_400_COMPACT;
452 break; 596 break;
453 case 6: /* matched "info_hash" */ 597 case 6: /* matched "info_hash" */
454 if( ws->hash ) HTTPERROR_400_DOUBLEHASH; 598 if (ws->hash)
599 HTTPERROR_400_DOUBLEHASH;
455 /* ignore this, when we have less than 20 bytes */ 600 /* ignore this, when we have less than 20 bytes */
456 if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; 601 if (scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20)
457 ws->hash = (ot_hash*)write_ptr; 602 HTTPERROR_400_PARAM;
603 ws->hash = (ot_hash *)write_ptr;
458 break; 604 break;
459#ifdef WANT_IP_FROM_QUERY_STRING 605#ifdef WANT_IP_FROM_QUERY_STRING
460 case 7: /* matched "ip" */ 606 case 7: /* matched "ip" */
461 { 607 {
462 char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply+16; 608 char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16;
463 len = scan_urlencoded_query( &read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE ); 609 len = scan_urlencoded_query(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE);
464 tmp_buf2[len] = 0; 610 tmp_buf2[len] = 0;
465 if( ( len <= 0 ) || !scan_ip6( tmp_buf2, tmp_buf1 ) ) HTTPERROR_400_PARAM; 611 if ((len <= 0) || !scan_ip6(tmp_buf2, tmp_buf1))
466 OT_SETIP( &ws->peer, tmp_buf1 ); 612 HTTPERROR_400_PARAM;
467 } 613 OT_SETIP(&ws->peer, tmp_buf1);
468 break; 614 } break;
469#endif 615#endif
470#ifdef WANT_FULLLOG_NETWORKS 616#ifdef WANT_FULLLOG_NETWORKS
471 case 8: /* matched "lognet" */ 617 case 8: /* matched "lognet" */
472 { 618 {
473 //if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_STAT ) ) { 619 // if( accesslist_is_blessed( cookie->ip, OT_PERMISSION_MAY_STAT ) ) {
474 char *tmp_buf = ws->reply; 620 char *tmp_buf = ws->reply;
475 ot_net net; 621 ot_net net;
476 signed short parsed, bits; 622 signed short parsed, bits;
477 623
478 len = scan_urlencoded_query( &read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE ); 624 len = scan_urlencoded_query(&read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE);
479 tmp_buf[len] = 0; 625 tmp_buf[len] = 0;
480 if( len <= 0 ) HTTPERROR_400_PARAM; 626 if (len <= 0)
481 if( *tmp_buf == '-' ) { 627 HTTPERROR_400_PARAM;
482 loglist_reset( ); 628 if (*tmp_buf == '-') {
483 return ws->reply_size = sprintf( ws->reply, "Successfully removed.\n" ); 629 loglist_reset();
484 } 630 return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n");
485 parsed = scan_ip6( tmp_buf, net.address );
486 if( !parsed ) HTTPERROR_400_PARAM;
487 if( tmp_buf[parsed++] != '/' )
488 bits = 128;
489 else {
490 parsed = scan_short( tmp_buf + parsed, &bits );
491 if( !parsed ) HTTPERROR_400_PARAM;
492 if( ip6_isv4mapped( net.address ) )
493 bits += 96;
494 }
495 net.bits = bits;
496 loglist_add_network( &net );
497 return ws->reply_size = sprintf( ws->reply, "Successfully added.\n" );
498 //}
499 } 631 }
632 parsed = scan_ip6(tmp_buf, net.address);
633 if (!parsed)
634 HTTPERROR_400_PARAM;
635 if (tmp_buf[parsed++] != '/')
636 bits = 128;
637 else {
638 parsed = scan_short(tmp_buf + parsed, &bits);
639 if (!parsed)
640 HTTPERROR_400_PARAM;
641 if (ip6_isv4mapped(net.address))
642 bits += 96;
643 }
644 net.bits = bits;
645 loglist_add_network(&net);
646 return ws->reply_size = sprintf(ws->reply, "Successfully added.\n");
647 //}
648 } break;
500#endif 649#endif
501 break; 650 case 9: /* matched "peer_id" */
502 case 9: /* matched "peer_id" */ 651 /* ignore this, when we have less than 20 bytes */
503 /* ignore this, when we have less than 20 bytes */ 652 if (scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20)
504 if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; 653 HTTPERROR_400_PARAM;
505 ws->peer_id = write_ptr; 654 ws->peer_id = write_ptr;
506 break; 655 break;
507 } 656 }
508 } 657 }
509 658
@@ -516,100 +665,107 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
516 */ 665 */
517 666
518 /* Scanned whole query string */ 667 /* Scanned whole query string */
519 if( !ws->hash ) 668 if (!ws->hash)
520 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" ); 669 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");
521 670
522 if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED ) 671 if (OT_PEERFLAG(&ws->peer) & PEER_FLAG_STOPPED)
523 ws->reply_size = remove_peer_from_torrent( FLAG_TCP, ws ); 672 ws->reply_size = remove_peer_from_torrent(FLAG_TCP, ws);
524 else 673 else
525 ws->reply_size = add_peer_to_torrent_and_return_peers( FLAG_TCP, ws, numwant ); 674 ws->reply_size = add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, numwant);
526 675
527 stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size); 676 stats_issue_event(EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size);
528 return ws->reply_size; 677 return ws->reply_size;
529} 678}
530 679
531ssize_t http_handle_request( const int64 sock, struct ot_workstruct *ws ) { 680ssize_t http_handle_request(const int64 sock, struct ot_workstruct *ws) {
532 ssize_t reply_off, len; 681 ssize_t reply_off, len;
533 char *read_ptr = ws->request, *write_ptr; 682 char *read_ptr = ws->request, *write_ptr;
534 683
535#ifdef WANT_FULLLOG_NETWORKS 684#ifdef WANT_FULLLOG_NETWORKS
536 struct http_data *cookie = io_getcookie( sock ); 685 struct http_data *cookie = io_getcookie(sock);
537 if( loglist_check_address( cookie->ip ) ) { 686 if (loglist_check_address(cookie->ip)) {
538 ot_log *log = malloc( sizeof( ot_log ) ); 687 ot_log *log = malloc(sizeof(ot_log));
539 if( log ) { 688 if (log) {
540 log->size = ws->request_size; 689 log->size = ws->request_size;
541 log->data = malloc( ws->request_size ); 690 log->data = malloc(ws->request_size);
542 log->next = 0; 691 log->next = 0;
543 log->time = g_now_seconds; 692 log->time = g_now_seconds;
544 memcpy( log->ip, cookie->ip, sizeof(ot_ip6)); 693 memcpy(log->ip, cookie->ip, sizeof(ot_ip6));
545 if( log->data ) { 694 if (log->data) {
546 memcpy( log->data, ws->request, ws->request_size ); 695 memcpy(log->data, ws->request, ws->request_size);
547 if( !g_logchain_first ) 696 if (!g_logchain_first)
548 g_logchain_first = g_logchain_last = log; 697 g_logchain_first = g_logchain_last = log;
549 else { 698 else {
550 g_logchain_last->next = log; 699 g_logchain_last->next = log;
551 g_logchain_last = log; 700 g_logchain_last = log;
552 } 701 }
553 } else 702 } else
554 free( log ); 703 free(log);
555 } 704 }
556 } 705 }
557#endif 706#endif
558 707
559#ifdef _DEBUG_HTTPERROR 708#ifdef _DEBUG_HTTPERROR
560 reply_off = ws->request_size; 709 reply_off = ws->request_size;
561 if( ws->request_size >= G_DEBUGBUF_SIZE ) 710 if (ws->request_size >= G_DEBUGBUF_SIZE)
562 reply_off = G_DEBUGBUF_SIZE - 1; 711 reply_off = G_DEBUGBUF_SIZE - 1;
563 memcpy( ws->debugbuf, ws->request, reply_off ); 712 memcpy(ws->debugbuf, ws->request, reply_off);
564 ws->debugbuf[ reply_off ] = 0; 713 ws->debugbuf[reply_off] = 0;
565#endif 714#endif
566 715
567 /* Tell subroutines where to put reply data */ 716 /* Tell subroutines where to put reply data */
568 ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH; 717 ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH;
569 718
570 /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */ 719 /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */
571 if( memcmp( read_ptr, "GET /", 5) ) HTTPERROR_400; 720 if (memcmp(read_ptr, "GET /", 5))
721 HTTPERROR_400;
572 722
573 /* Skip leading '/' */ 723 /* Skip leading '/' */
574 for( read_ptr+=4; *read_ptr == '/'; ++read_ptr); 724 for (read_ptr += 4; *read_ptr == '/'; ++read_ptr)
725 ;
575 726
576 /* Try to parse the request. 727 /* Try to parse the request.
577 In reality we abandoned requiring the url to be correct. This now 728 In reality we abandoned requiring the url to be correct. This now
578 only decodes url encoded characters, we check for announces and 729 only decodes url encoded characters, we check for announces and
579 scrapes by looking for "a*" or "sc" */ 730 scrapes by looking for "a*" or "sc" */
580 len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_PATH ); 731 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_PATH);
581 732
582 /* If parsing returned an error, leave with not found */ 733 /* If parsing returned an error, leave with not found */
583 if( g_redirecturl && ( len == -2 ) ) HTTPERROR_302; 734 if (g_redirecturl && (len == -2))
584 if( len <= 0 ) HTTPERROR_404; 735 HTTPERROR_302;
736 if (len <= 0)
737 HTTPERROR_404;
585 738
586 /* This is the hardcore match for announce*/ 739 /* This is the hardcore match for announce*/
587 if( ( *write_ptr == 'a' ) || ( *write_ptr == '?' ) ) 740 if ((*write_ptr == 'a') || (*write_ptr == '?'))
588 http_handle_announce( sock, ws, read_ptr ); 741 http_handle_announce(sock, ws, read_ptr);
589#ifdef WANT_FULLSCRAPE 742#ifdef WANT_FULLSCRAPE
590 else if( !memcmp( write_ptr, "scrape HTTP/", 12 ) ) 743 else if (!memcmp(write_ptr, "scrape HTTP/", 12))
591 http_handle_fullscrape( sock, ws ); 744 http_handle_fullscrape(sock, ws);
592#endif 745#endif
593 /* This is the hardcore match for scrape */ 746 /* This is the hardcore match for scrape */
594 else if( !memcmp( write_ptr, "sc", 2 ) ) 747 else if (!memcmp(write_ptr, "sc", 2))
595 http_handle_scrape( sock, ws, read_ptr ); 748 http_handle_scrape(sock, ws, read_ptr);
596 /* All the rest is matched the standard way */ 749 /* All the rest is matched the standard way */
597 else if( len == g_stats_path_len && !memcmp( write_ptr, g_stats_path, len ) ) 750 else if (len == g_stats_path_len && !memcmp(write_ptr, g_stats_path, len))
598 http_handle_stats( sock, ws, read_ptr ); 751 http_handle_stats(sock, ws, read_ptr);
599 else 752 else
600 HTTPERROR_404; 753 HTTPERROR_404;
601 754
602 /* Find out if the client wants to keep this connection alive */ 755 /* Find out if the client wants to keep this connection alive */
603 ws->keep_alive = 0; 756 ws->keep_alive = 0;
604#ifdef WANT_KEEPALIVE 757#ifdef WANT_KEEPALIVE
605 read_ptr=http_header( ws->request, ws->header_size, "connection"); 758 read_ptr = http_header(ws->request, ws->header_size, "connection");
606 if( read_ptr && ( *read_ptr == 'K' || *read_ptr == 'k' ) ) ws->keep_alive = 1; 759 if (read_ptr && (*read_ptr == 'K' || *read_ptr == 'k'))
760 ws->keep_alive = 1;
607#endif 761#endif
608 762
609 /* If routines handled sending themselves, just return */ 763 /* If routines handled sending themselves, just return */
610 if( ws->reply_size == -2 ) return 0; 764 if (ws->reply_size == -2)
765 return 0;
611 /* If routine failed, let http error take over */ 766 /* If routine failed, let http error take over */
612 if( ws->reply_size <= 0 ) HTTPERROR_500; 767 if (ws->reply_size <= 0)
768 HTTPERROR_500;
613 769
614 /* This one is rather ugly, so I take you step by step through it. 770 /* This one is rather ugly, so I take you step by step through it.
615 771
@@ -618,18 +774,16 @@ ssize_t http_handle_request( const int64 sock, struct ot_workstruct *ws ) {
618 plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate 774 plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate
619 the space NOT needed to expand in reply_off 775 the space NOT needed to expand in reply_off
620 */ 776 */
621 reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( ws->outbuf, 0, "%zd", ws->reply_size ); 777 reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf(ws->outbuf, 0, "%zd", ws->reply_size);
622 ws->reply = ws->outbuf + reply_off; 778 ws->reply = ws->outbuf + reply_off;
623 779
624 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete 780 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete
625 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ 781 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */
626 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 ); 782 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);
627 783
628 /* 3. Finally we join both blocks neatly */ 784 /* 3. Finally we join both blocks neatly */
629 ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; 785 ws->outbuf[SUCCESS_HTTP_HEADER_LENGTH - 1] = '\n';
630 786
631 http_senddata( sock, ws ); 787 http_senddata(sock, ws);
632 return ws->reply_size; 788 return ws->reply_size;
633} 789}
634
635const char *g_version_http_c = "$Source$: $Revision$\n";