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