diff options
Diffstat (limited to 'ot_http.c')
| -rw-r--r-- | ot_http.c | 454 | 
1 files changed, 186 insertions, 268 deletions
| @@ -27,26 +27,19 @@ | |||
| 27 | #include "ot_accesslist.h" | 27 | #include "ot_accesslist.h" | 
| 28 | 28 | ||
| 29 | #define OT_MAXMULTISCRAPE_COUNT 64 | 29 | #define OT_MAXMULTISCRAPE_COUNT 64 | 
| 30 | static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT]; | ||
| 31 | extern char *g_redirecturl; | 30 | extern char *g_redirecturl; | 
| 32 | 31 | ||
| 33 | enum { | 32 | enum { | 
| 34 | SUCCESS_HTTP_HEADER_LENGTH = 80, | 33 | SUCCESS_HTTP_HEADER_LENGTH = 80, | 
| 35 | SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING = 32, | 34 | SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING = 32, | 
| 36 | SUCCESS_HTTP_SIZE_OFF = 17 }; | 35 | SUCCESS_HTTP_SIZE_OFF = 17 }; | 
| 37 | 36 | ||
| 38 | /* Our static output buffer */ | ||
| 39 | static char static_outbuf[8192]; | ||
| 40 | #ifdef _DEBUG_HTTPERROR | ||
| 41 | static char debug_request[8192]; | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #ifdef _DEBUG_PEERID | 37 | #ifdef _DEBUG_PEERID | 
| 45 | size_t g_this_peerid_len = 0; | 38 | size_t g_this_peerid_len = 0; | 
| 46 | char *g_this_peerid_data = NULL; | 39 | char *g_this_peerid_data = NULL; | 
| 47 | #endif | 40 | #endif | 
| 48 | 41 | ||
| 49 | static void http_senddata( const int64 client_socket, char *buffer, size_t size ) { | 42 | static void http_senddata( const int64 client_socket, struct ot_workstruct *ws ) { | 
| 50 | struct http_data *h = io_getcookie( client_socket ); | 43 | struct http_data *h = io_getcookie( client_socket ); | 
| 51 | ssize_t written_size; | 44 | ssize_t written_size; | 
| 52 | 45 | ||
| @@ -56,22 +49,22 @@ static void http_senddata( const int64 client_socket, char *buffer, size_t size | |||
| 56 | array_reset( &h->data.request ); | 49 | array_reset( &h->data.request ); | 
| 57 | } | 50 | } | 
| 58 | 51 | ||
| 59 | written_size = write( client_socket, buffer, size ); | 52 | written_size = write( client_socket, ws->reply, ws->reply_size ); | 
| 60 | if( ( written_size < 0 ) || ( (size_t)written_size == size ) ) { | 53 | if( ( written_size < 0 ) || ( written_size == ws->reply_size ) ) { | 
| 61 | free( h ); io_close( client_socket ); | 54 | free( h ); io_close( client_socket ); | 
| 62 | } else { | 55 | } else { | 
| 63 | char * outbuf; | 56 | char * outbuf; | 
| 64 | tai6464 t; | 57 | tai6464 t; | 
| 65 | 58 | ||
| 66 | if( !h ) return; | 59 | if( !h ) return; | 
| 67 | if( !( outbuf = malloc( size - written_size ) ) ) { | 60 | if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) { | 
| 68 | free(h); io_close( client_socket ); | 61 | free(h); io_close( client_socket ); | 
| 69 | return; | 62 | return; | 
| 70 | } | 63 | } | 
| 71 | 64 | ||
| 72 | iob_reset( &h->data.batch ); | 65 | iob_reset( &h->data.batch ); | 
| 73 | memmove( outbuf, buffer + written_size, size - written_size ); | 66 | memmove( outbuf, ws->reply + written_size, ws->reply_size - written_size ); | 
| 74 | iob_addbuf_free( &h->data.batch, outbuf, size - written_size ); | 67 | iob_addbuf_free( &h->data.batch, outbuf, ws->reply_size - written_size ); | 
| 75 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; | 68 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; | 
| 76 | 69 | ||
| 77 | /* writeable short data sockets just have a tcp timeout */ | 70 | /* writeable short data sockets just have a tcp timeout */ | 
| @@ -81,33 +74,34 @@ static void http_senddata( const int64 client_socket, char *buffer, size_t size | |||
| 81 | } | 74 | } | 
| 82 | } | 75 | } | 
| 83 | 76 | ||
| 84 | #define HTTPERROR_302 return http_issue_error( client_socket, CODE_HTTPERROR_302 ) | 77 | #define HTTPERROR_302 return http_issue_error( client_socket, ws, CODE_HTTPERROR_302 ) | 
| 85 | #define HTTPERROR_400 return http_issue_error( client_socket, CODE_HTTPERROR_400 ) | 78 | #define HTTPERROR_400 return http_issue_error( client_socket, ws, CODE_HTTPERROR_400 ) | 
| 86 | #define HTTPERROR_400_PARAM return http_issue_error( client_socket, CODE_HTTPERROR_400_PARAM ) | 79 | #define HTTPERROR_400_PARAM return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_PARAM ) | 
| 87 | #define HTTPERROR_400_COMPACT return http_issue_error( client_socket, CODE_HTTPERROR_400_COMPACT ) | 80 | #define HTTPERROR_400_COMPACT return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_COMPACT ) | 
| 88 | #define HTTPERROR_403_IP return http_issue_error( client_socket, CODE_HTTPERROR_403_IP ) | 81 | #define HTTPERROR_400_DOUBLEHASH return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_PARAM ) | 
| 89 | #define HTTPERROR_404 return http_issue_error( client_socket, CODE_HTTPERROR_404 ) | 82 | #define HTTPERROR_403_IP return http_issue_error( client_socket, ws, CODE_HTTPERROR_403_IP ) | 
| 90 | #define HTTPERROR_500 return http_issue_error( client_socket, CODE_HTTPERROR_500 ) | 83 | #define HTTPERROR_404 return http_issue_error( client_socket, ws, CODE_HTTPERROR_404 ) | 
| 91 | ssize_t http_issue_error( const int64 client_socket, int code ) { | 84 | #define HTTPERROR_500 return http_issue_error( client_socket, ws, CODE_HTTPERROR_500 ) | 
| 85 | ssize_t http_issue_error( const int64 client_socket, struct ot_workstruct *ws, int code ) { | ||
| 92 | char *error_code[] = { "302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", | 86 | char *error_code[] = { "302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", | 
| 93 | "403 Access Denied", "404 Not Found", "500 Internal Server Error" }; | 87 | "403 Access Denied", "404 Not Found", "500 Internal Server Error" }; | 
| 94 | char *title = error_code[code]; | 88 | char *title = error_code[code]; | 
| 95 | size_t reply_size; | ||
| 96 | 89 | ||
| 90 | ws->reply = ws->outbuf; | ||
| 97 | if( code == CODE_HTTPERROR_302 ) | 91 | if( code == CODE_HTTPERROR_302 ) | 
| 98 | reply_size = sprintf( static_outbuf, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl ); | 92 | ws->reply_size = snprintf( ws->reply, ws->outbuf_size, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl ); | 
| 99 | else | 93 | else | 
| 100 | reply_size = sprintf( static_outbuf, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", title, strlen(title)+16-4,title+4); | 94 | ws->reply_size = snprintf( ws->reply, ws->outbuf_size, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", title, strlen(title)+16-4,title+4); | 
| 101 | 95 | ||
| 102 | #ifdef _DEBUG_HTTPERROR | 96 | #ifdef _DEBUG_HTTPERROR | 
| 103 | fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); | 97 | fprintf( stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf ); | 
| 104 | #endif | 98 | #endif | 
| 105 | stats_issue_event( EVENT_FAILED, FLAG_TCP, code ); | 99 | stats_issue_event( EVENT_FAILED, FLAG_TCP, code ); | 
| 106 | http_senddata( client_socket, static_outbuf, reply_size); | 100 | http_senddata( client_socket, ws ); | 
| 107 | return -2; | 101 | return ws->reply_size = -2; | 
| 108 | } | 102 | } | 
| 109 | 103 | ||
| 110 | ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct iovec *iovector ) { | 104 | ssize_t http_sendiovecdata( const int64 client_socket, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector ) { | 
| 111 | struct http_data *h = io_getcookie( client_socket ); | 105 | struct http_data *h = io_getcookie( client_socket ); | 
| 112 | char *header; | 106 | char *header; | 
| 113 | int i; | 107 | int i; | 
| @@ -136,7 +130,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct | |||
| 136 | } | 130 | } | 
| 137 | 131 | ||
| 138 | /* Prepare space for http header */ | 132 | /* Prepare space for http header */ | 
| 139 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING ); | 133 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING ); | 
| 140 | if( !header ) { | 134 | if( !header ) { | 
| 141 | iovec_free( &iovec_entries, &iovector ); | 135 | iovec_free( &iovec_entries, &iovector ); | 
| 142 | HTTPERROR_500; | 136 | HTTPERROR_500; | 
| @@ -159,7 +153,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct | |||
| 159 | 153 | ||
| 160 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; | 154 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; | 
| 161 | 155 | ||
| 162 | /* writeable sockets timeout after 10 minutes) */ | 156 | /* writeable sockets timeout after 10 minutes */ | 
| 163 | taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND ); | 157 | taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND ); | 
| 164 | io_timeout( client_socket, t ); | 158 | io_timeout( client_socket, t ); | 
| 165 | io_dontwantread( client_socket ); | 159 | io_dontwantread( client_socket ); | 
| @@ -167,9 +161,21 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct | |||
| 167 | return 0; | 161 | return 0; | 
| 168 | } | 162 | } | 
| 169 | 163 | ||
| 170 | static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) { | 164 | static ssize_t http_handle_stats( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) { | 
| 171 | char *c = data; | 165 | static const ot_keywords keywords_main[] = | 
| 166 | { { "mode", 1 }, {"format", 2 }, { NULL, -3 } }; | ||
| 167 | static const ot_keywords keywords_mode[] = | ||
| 168 | { { "peer", TASK_STATS_PEERS }, { "conn", TASK_STATS_CONNS }, { "scrp", TASK_STATS_SCRAPE }, { "udp4", TASK_STATS_UDP }, | ||
| 169 | { "busy", TASK_STATS_BUSY_NETWORKS }, { "torr", TASK_STATS_TORRENTS }, { "fscr", TASK_STATS_FULLSCRAPE }, | ||
| 170 | { "s24s", TASK_STATS_SLASH24S }, { "tpbs", TASK_STATS_TPB }, { "herr", TASK_STATS_HTTPERRORS }, | ||
| 171 | { "top10", TASK_STATS_TOP10 }, { "renew", TASK_STATS_RENEW }, { "syncs", TASK_STATS_SYNCS }, { "version", TASK_STATS_VERSION }, | ||
| 172 | { "startstop", TASK_STATS_STARTSTOP }, { "toraddrem", TASK_STATS_TORADDREM }, { NULL, -3 } }; | ||
| 173 | static const ot_keywords keywords_format[] = | ||
| 174 | { { "bin", TASK_FULLSCRAPE_TPB_BINARY }, { "ben", TASK_FULLSCRAPE }, { "url", TASK_FULLSCRAPE_TPB_URLENCODED }, | ||
| 175 | { "txt", TASK_FULLSCRAPE_TPB_ASCII }, { NULL, -3 } }; | ||
| 176 | |||
| 172 | int mode = TASK_STATS_PEERS, scanon = 1, format = 0; | 177 | int mode = TASK_STATS_PEERS, scanon = 1, format = 0; | 
| 178 | |||
| 173 | #ifdef WANT_RESTRICT_STATS | 179 | #ifdef WANT_RESTRICT_STATS | 
| 174 | struct http_data *h = io_getcookie( client_socket ); | 180 | struct http_data *h = io_getcookie( client_socket ); | 
| 175 | 181 | ||
| @@ -178,97 +184,26 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d | |||
| 178 | #endif | 184 | #endif | 
| 179 | 185 | ||
| 180 | while( scanon ) { | 186 | while( scanon ) { | 
| 181 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 187 | switch( scan_find_keywords( keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { | 
| 182 | case -2: scanon = 0; break; /* TERMINATOR */ | 188 | case -2: scanon = 0; break; /* TERMINATOR */ | 
| 183 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 189 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 
| 184 | default: scan_urlencoded_skipvalue( &c ); break; | 190 | case -3: scan_urlencoded_skipvalue( &read_ptr ); break; | 
| 185 | case 4: | 191 | case 1: /* matched "mode" */ | 
| 186 | if( byte_diff(data,4,"mode")) { | 192 | if( ( mode = scan_find_keywords( keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; | 
| 187 | scan_urlencoded_skipvalue( &c ); | ||
| 188 | continue; | ||
| 189 | } | ||
| 190 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { | ||
| 191 | case 4: | ||
| 192 | if( !byte_diff(data,4,"peer")) | ||
| 193 | mode = TASK_STATS_PEERS; | ||
| 194 | else if( !byte_diff(data,4,"conn")) | ||
| 195 | mode = TASK_STATS_CONNS; | ||
| 196 | else if( !byte_diff(data,4,"scrp")) | ||
| 197 | mode = TASK_STATS_SCRAPE; | ||
| 198 | else if( !byte_diff(data,4,"tcp4")) | ||
| 199 | mode = TASK_STATS_TCP; | ||
| 200 | else if( !byte_diff(data,4,"udp4")) | ||
| 201 | mode = TASK_STATS_UDP; | ||
| 202 | else if( !byte_diff(data,4,"busy")) | ||
| 203 | mode = TASK_STATS_BUSY_NETWORKS; | ||
| 204 | else if( !byte_diff(data,4,"torr")) | ||
| 205 | mode = TASK_STATS_TORRENTS; | ||
| 206 | else if( !byte_diff(data,4,"fscr")) | ||
| 207 | mode = TASK_STATS_FULLSCRAPE; | ||
| 208 | else if( !byte_diff(data,4,"s24s")) | ||
| 209 | mode = TASK_STATS_SLASH24S; | ||
| 210 | else if( !byte_diff(data,4,"tpbs")) | ||
| 211 | mode = TASK_STATS_TPB; | ||
| 212 | else if( !byte_diff(data,4,"herr")) | ||
| 213 | mode = TASK_STATS_HTTPERRORS; | ||
| 214 | else | ||
| 215 | HTTPERROR_400_PARAM; | ||
| 216 | break; | ||
| 217 | case 5: | ||
| 218 | if( !byte_diff(data,5,"top10")) | ||
| 219 | mode = TASK_STATS_TOP10; | ||
| 220 | else if( !byte_diff(data,5,"renew")) | ||
| 221 | mode = TASK_STATS_RENEW; | ||
| 222 | else if( !byte_diff(data,5,"syncs")) | ||
| 223 | mode = TASK_STATS_SYNCS; | ||
| 224 | else | ||
| 225 | HTTPERROR_400_PARAM; | ||
| 226 | break; | ||
| 227 | case 7: | ||
| 228 | if( !byte_diff(data,7,"version")) | ||
| 229 | mode = TASK_STATS_VERSION; | ||
| 230 | else | ||
| 231 | HTTPERROR_400_PARAM; | ||
| 232 | break; | ||
| 233 | case 9: | ||
| 234 | if( !byte_diff(data,9,"startstop")) | ||
| 235 | mode = TASK_STATS_STARTSTOP; | ||
| 236 | else if( !byte_diff(data,9,"toraddrem")) | ||
| 237 | mode = TASK_STATS_TORADDREM; | ||
| 238 | else | ||
| 239 | HTTPERROR_400_PARAM; | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | break; | 193 | break; | 
| 243 | case 6: | 194 | case 2: /* matched "format" */ | 
| 244 | if( byte_diff(data,6,"format")) { | 195 | if( ( format = scan_find_keywords( keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; | 
| 245 | scan_urlencoded_skipvalue( &c ); | ||
| 246 | continue; | ||
| 247 | } | ||
| 248 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 3 ) HTTPERROR_400_PARAM; | ||
| 249 | if( !byte_diff(data,3,"bin")) | ||
| 250 | format = TASK_FULLSCRAPE_TPB_BINARY; | ||
| 251 | else if( !byte_diff(data,3,"ben")) | ||
| 252 | format = TASK_FULLSCRAPE; | ||
| 253 | else if( !byte_diff(data,3,"url")) | ||
| 254 | format = TASK_FULLSCRAPE_TPB_URLENCODED; | ||
| 255 | else if( !byte_diff(data,3,"txt")) | ||
| 256 | format = TASK_FULLSCRAPE_TPB_ASCII; | ||
| 257 | else | ||
| 258 | HTTPERROR_400_PARAM; | ||
| 259 | break; | 196 | break; | 
| 260 | } | 197 | } | 
| 261 | } | 198 | } | 
| 262 | 199 | ||
| 263 | /* Touch variable */ | ||
| 264 | d=d; | ||
| 265 | #ifdef WANT_FULLSCRAPE | 200 | #ifdef WANT_FULLSCRAPE | 
| 266 | if( mode == TASK_STATS_TPB ) { | 201 | if( mode == TASK_STATS_TPB ) { | 
| 267 | struct http_data* h = io_getcookie( client_socket ); | 202 | struct http_data* h = io_getcookie( client_socket ); | 
| 268 | tai6464 t; | 203 | tai6464 t; | 
| 269 | #ifdef WANT_COMPRESSION_GZIP | 204 | #ifdef WANT_COMPRESSION_GZIP | 
| 270 | d[l-1] = 0; | 205 | ws->request[ws->request_size] = 0; | 
| 271 | if( strstr( d, "gzip" ) ) { | 206 | if( strstr( read_ptr - 1, "gzip" ) ) { | 
| 272 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | 207 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | 
| 273 | format |= TASK_FLAG_GZIP; | 208 | format |= TASK_FLAG_GZIP; | 
| 274 | } | 209 | } | 
| @@ -280,7 +215,7 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d | |||
| 280 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 215 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 
| 281 | fullscrape_deliver( client_socket, format ); | 216 | fullscrape_deliver( client_socket, format ); | 
| 282 | io_dontwantread( client_socket ); | 217 | io_dontwantread( client_socket ); | 
| 283 | return -2; | 218 | return ws->reply_size = -2; | 
| 284 | } | 219 | } | 
| 285 | #endif | 220 | #endif | 
| 286 | 221 | ||
| @@ -290,27 +225,24 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d | |||
| 290 | /* Complex stats also include expensive memory debugging tools */ | 225 | /* Complex stats also include expensive memory debugging tools */ | 
| 291 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 226 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 
| 292 | stats_deliver( client_socket, mode ); | 227 | stats_deliver( client_socket, mode ); | 
| 293 | return -2; | 228 | return ws->reply_size = -2; | 
| 294 | } | 229 | } | 
| 295 | 230 | ||
| 296 | /* Simple stats can be answerred immediately */ | 231 | /* Simple stats can be answerred immediately */ | 
| 297 | if( !( l = return_stats_for_tracker( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, mode, 0 ) ) ) HTTPERROR_500; | 232 | if( !( ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 ) ) ) HTTPERROR_500; | 
| 298 | 233 | ||
| 299 | return l; | 234 | return ws->reply_size; | 
| 300 | } | 235 | } | 
| 301 | 236 | ||
| 302 | #ifdef WANT_FULLSCRAPE | 237 | #ifdef WANT_FULLSCRAPE | 
| 303 | static ssize_t http_handle_fullscrape( const int64 client_socket, char *d, size_t l ) { | 238 | static ssize_t http_handle_fullscrape( const int64 client_socket, struct ot_workstruct *ws ) { | 
| 304 | struct http_data* h = io_getcookie( client_socket ); | 239 | struct http_data* h = io_getcookie( client_socket ); | 
| 305 | int format = 0; | 240 | int format = 0; | 
| 306 | tai6464 t; | 241 | tai6464 t; | 
| 307 | 242 | ||
| 308 | /* Touch variables */ | ||
| 309 | d=d;l=l; | ||
| 310 | |||
| 311 | #ifdef WANT_COMPRESSION_GZIP | 243 | #ifdef WANT_COMPRESSION_GZIP | 
| 312 | d[l-1] = 0; | 244 | ws->request[ws->request_size-1] = 0; | 
| 313 | if( strstr( d, "gzip" ) ) { | 245 | if( strstr( ws->request, "gzip" ) ) { | 
| 314 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | 246 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | 
| 315 | format = TASK_FLAG_GZIP; | 247 | format = TASK_FLAG_GZIP; | 
| 316 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST_GZIP, *(int*)h->ip, 0 ); | 248 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST_GZIP, *(int*)h->ip, 0 ); | 
| @@ -319,7 +251,7 @@ static ssize_t http_handle_fullscrape( const int64 client_socket, char *d, size_ | |||
| 319 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST, *(int*)h->ip, 0 ); | 251 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST, *(int*)h->ip, 0 ); | 
| 320 | 252 | ||
| 321 | #ifdef _DEBUG_HTTPERROR | 253 | #ifdef _DEBUG_HTTPERROR | 
| 322 | write( 2, debug_request, l ); | 254 | write( 2, ws->debugbuf, ws->debugbuf_size ); | 
| 323 | #endif | 255 | #endif | 
| 324 | 256 | ||
| 325 | /* Pass this task to the worker thread */ | 257 | /* Pass this task to the worker thread */ | 
| @@ -328,72 +260,70 @@ write( 2, debug_request, l ); | |||
| 328 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 260 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 
| 329 | fullscrape_deliver( client_socket, TASK_FULLSCRAPE | format ); | 261 | fullscrape_deliver( client_socket, TASK_FULLSCRAPE | format ); | 
| 330 | io_dontwantread( client_socket ); | 262 | io_dontwantread( client_socket ); | 
| 331 | return -2; | 263 | return ws->reply_size = -2; | 
| 332 | } | 264 | } | 
| 333 | #endif | 265 | #endif | 
| 266 | static ssize_t http_handle_scrape( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) { | ||
| 267 | static const ot_keywords keywords_scrape[] = { { "info_hash", 1 }, { NULL, -3 } }; | ||
| 334 | 268 | ||
| 335 | static ssize_t http_handle_scrape( const int64 client_socket, char *data ) { | 269 | ot_hash * multiscrape_buf = (ot_hash*)ws->request; | 
| 336 | int scanon = 1, numwant = 0; | 270 | int scanon = 1, numwant = 0; | 
| 337 | char *c = data; | ||
| 338 | size_t l; | ||
| 339 | 271 | ||
| 340 | /* This is to hack around stupid clients that send "scrape ?info_hash" */ | 272 | /* This is to hack around stupid clients that send "scrape ?info_hash" */ | 
| 341 | if( c[-1] != '?' ) { | 273 | if( read_ptr[-1] != '?' ) { | 
| 342 | while( ( *c != '?' ) && ( *c != '\n' ) ) ++c; | 274 | while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; | 
| 343 | if( *c == '\n' ) HTTPERROR_400_PARAM; | 275 | if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; | 
| 344 | ++c; | 276 | ++read_ptr; | 
| 345 | } | 277 | } | 
| 346 | 278 | ||
| 347 | while( scanon ) { | 279 | while( scanon ) { | 
| 348 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 280 | switch( scan_find_keywords( keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { | 
| 349 | case -2: scanon = 0; break; /* TERMINATOR */ | 281 | case -2: scanon = 0; break; /* TERMINATOR */ | 
| 350 | case -1: | 282 | default: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 
| 351 | if( numwant ) | 283 | case -3: scan_urlencoded_skipvalue( &read_ptr ); break; | 
| 352 | goto UTORRENT1600_WORKAROUND; | 284 | case 1: /* matched "info_hash" */ | 
| 353 | HTTPERROR_400_PARAM; /* PARSE ERROR */ | ||
| 354 | default: scan_urlencoded_skipvalue( &c ); break; | ||
| 355 | case 9: | ||
| 356 | if(byte_diff(data,9,"info_hash")) { | ||
| 357 | scan_urlencoded_skipvalue( &c ); | ||
| 358 | continue; | ||
| 359 | } | ||
| 360 | /* ignore this, when we have less than 20 bytes */ | 285 | /* ignore this, when we have less than 20 bytes */ | 
| 361 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) ) { | 286 | if( scan_urlencoded_query( &read_ptr, (char*)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) ) | 
| 362 | #ifdef WANT_UTORRENT1600_WORKAROUND | ||
| 363 | if( data[20] != '?' ) | ||
| 364 | #endif | ||
| 365 | HTTPERROR_400_PARAM; | 287 | HTTPERROR_400_PARAM; | 
| 366 | } | ||
| 367 | if( numwant < OT_MAXMULTISCRAPE_COUNT ) | ||
| 368 | memmove( multiscrape_buf + numwant++, data, sizeof(ot_hash) ); | ||
| 369 | break; | 288 | break; | 
| 370 | } | 289 | } | 
| 371 | } | 290 | } | 
| 372 | 291 | ||
| 373 | UTORRENT1600_WORKAROUND: | ||
| 374 | |||
| 375 | /* No info_hash found? Inform user */ | 292 | /* No info_hash found? Inform user */ | 
| 376 | if( !numwant ) HTTPERROR_400_PARAM; | 293 | if( !numwant ) HTTPERROR_400_PARAM; | 
| 294 | |||
| 295 | /* Limit number of hashes to process */ | ||
| 296 | if( numwant > OT_MAXMULTISCRAPE_COUNT ) | ||
| 297 | numwant = OT_MAXMULTISCRAPE_COUNT; | ||
| 377 | 298 | ||
| 378 | /* Enough for http header + whole scrape string */ | 299 | /* Enough for http header + whole scrape string */ | 
| 379 | if( !( l = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf ) ) ) HTTPERROR_500; | 300 | if( !( ws->reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, ws->reply ) ) ) HTTPERROR_500; | 
| 380 | stats_issue_event( EVENT_SCRAPE, FLAG_TCP, l ); | 301 | stats_issue_event( EVENT_SCRAPE, FLAG_TCP, ws->reply_size ); | 
| 381 | return l; | 302 | return ws->reply_size; | 
| 382 | } | 303 | } | 
| 383 | 304 | ||
| 384 | static ssize_t http_handle_announce( const int64 client_socket, char *data ) { | 305 | static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "event", 3 }, { "numwant", 4 }, { "compact", 5 }, { "info_hash", 6 }, | 
| 385 | char *c = data; | 306 | #ifdef WANT_IP_FROM_QUERY_STRING | 
| 386 | int numwant, tmp, scanon; | 307 | { "ip", 7 }, | 
| 387 | ot_peer peer; | 308 | #endif | 
| 388 | ot_hash *hash = NULL; | 309 | #ifdef _DEBUG_PEERID | 
| 310 | { "peer_id", 8 }, | ||
| 311 | #endif | ||
| 312 | { NULL, -3 } }; | ||
| 313 | static ot_keywords keywords_announce_event[] = { { "completed", 1 }, { "stopped", 2 }, { NULL, -3 } }; | ||
| 314 | static ssize_t http_handle_announce( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) { | ||
| 315 | int numwant, tmp, scanon; | ||
| 316 | ot_peer peer; | ||
| 317 | ot_hash *hash = NULL; | ||
| 389 | unsigned short port = htons(6881); | 318 | unsigned short port = htons(6881); | 
| 390 | ssize_t len; | 319 | char *write_ptr; | 
| 391 | 320 | ssize_t len; | |
| 321 | |||
| 392 | /* This is to hack around stupid clients that send "announce ?info_hash" */ | 322 | /* This is to hack around stupid clients that send "announce ?info_hash" */ | 
| 393 | if( c[-1] != '?' ) { | 323 | if( read_ptr[-1] != '?' ) { | 
| 394 | while( ( *c != '?' ) && ( *c != '\n' ) ) ++c; | 324 | while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; | 
| 395 | if( *c == '\n' ) HTTPERROR_400_PARAM; | 325 | if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; | 
| 396 | ++c; | 326 | ++read_ptr; | 
| 397 | } | 327 | } | 
| 398 | 328 | ||
| 399 | OT_SETIP( &peer, ((struct http_data*)io_getcookie( client_socket ) )->ip ); | 329 | OT_SETIP( &peer, ((struct http_data*)io_getcookie( client_socket ) )->ip ); | 
| @@ -403,168 +333,156 @@ static ssize_t http_handle_announce( const int64 client_socket, char *data ) { | |||
| 403 | scanon = 1; | 333 | scanon = 1; | 
| 404 | 334 | ||
| 405 | #ifdef _DEBUG_PEERID | 335 | #ifdef _DEBUG_PEERID | 
| 406 | g_this_peerid_data = NULL; | 336 | ws->peer_id = NULL; | 
| 407 | #endif | 337 | #endif | 
| 408 | 338 | ||
| 409 | while( scanon ) { | 339 | while( scanon ) { | 
| 410 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 340 | switch( scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { | 
| 411 | case -2: scanon = 0; break; /* TERMINATOR */ | 341 | case -2: scanon = 0; break; /* TERMINATOR */ | 
| 412 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 342 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 
| 413 | default: scan_urlencoded_skipvalue( &c ); break; | 343 | case -3: scan_urlencoded_skipvalue( &read_ptr ); break; | 
| 414 | #ifdef WANT_IP_FROM_QUERY_STRING | 344 | case 1: /* matched "port" */ | 
| 415 | case 2: | 345 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | 
| 416 | if(!byte_diff(data,2,"ip")) { | 346 | if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; | 
| 417 | unsigned char ip[4]; | 347 | port = htons( tmp ); OT_SETPORT( &peer, &port ); | 
| 418 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
| 419 | if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) HTTPERROR_400_PARAM; | ||
| 420 | OT_SETIP( &peer, ip ); | ||
| 421 | } else | ||
| 422 | scan_urlencoded_skipvalue( &c ); | ||
| 423 | break; | ||
| 424 | #endif | ||
| 425 | case 4: | ||
| 426 | if( !byte_diff( data, 4, "port" ) ) { | ||
| 427 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
| 428 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; | ||
| 429 | port = htons( tmp ); OT_SETPORT( &peer, &port ); | ||
| 430 | } else if( !byte_diff( data, 4, "left" ) ) { | ||
| 431 | if( ( len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; | ||
| 432 | if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; | ||
| 433 | if( !tmp ) OT_PEERFLAG( &peer ) |= PEER_FLAG_SEEDING; | ||
| 434 | } else | ||
| 435 | scan_urlencoded_skipvalue( &c ); | ||
| 436 | break; | 348 | break; | 
| 437 | case 5: | 349 | case 2: /* matched "left" */ | 
| 438 | if( byte_diff( data, 5, "event" ) ) | 350 | if( ( len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; | 
| 439 | scan_urlencoded_skipvalue( &c ); | 351 | if( scan_fixed_int( write_ptr, len, &tmp ) ) tmp = 0; | 
| 440 | else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { | 352 | if( !tmp ) OT_PEERFLAG( &peer ) |= PEER_FLAG_SEEDING; | 
| 441 | case -1: | 353 | break; | 
| 442 | HTTPERROR_400_PARAM; | 354 | case 3: /* matched "event" */ | 
| 443 | case 7: | 355 | switch( scan_find_keywords( keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) { | 
| 444 | if( !byte_diff( data, 7, "stopped" ) ) OT_PEERFLAG( &peer ) |= PEER_FLAG_STOPPED; | 356 | case -1: HTTPERROR_400_PARAM; | 
| 445 | break; | 357 | case 1: /* matched "completed" */ | 
| 446 | case 9: | 358 | OT_PEERFLAG( &peer ) |= PEER_FLAG_COMPLETED; | 
| 447 | if( !byte_diff( data, 9, "completed" ) ) OT_PEERFLAG( &peer ) |= PEER_FLAG_COMPLETED; | 359 | break; | 
| 448 | default: /* Fall through intended */ | 360 | case 2: /* matched "stopped" */ | 
| 449 | break; | 361 | OT_PEERFLAG( &peer ) |= PEER_FLAG_STOPPED; | 
| 362 | break; | ||
| 363 | default: | ||
| 364 | break; | ||
| 450 | } | 365 | } | 
| 451 | break; | 366 | break; | 
| 452 | case 7: | 367 | case 4: /* matched "numwant" */ | 
| 453 | if(!byte_diff(data,7,"numwant")) { | 368 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | 
| 454 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 369 | if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &numwant ) ) HTTPERROR_400_PARAM; | 
| 455 | if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) HTTPERROR_400_PARAM; | 370 | if( numwant < 0 ) numwant = 50; | 
| 456 | if( numwant < 0 ) numwant = 50; | 371 | if( numwant > 200 ) numwant = 200; | 
| 457 | if( numwant > 200 ) numwant = 200; | ||
| 458 | } else if(!byte_diff(data,7,"compact")) { | ||
| 459 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
| 460 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) HTTPERROR_400_PARAM; | ||
| 461 | if( !tmp ) HTTPERROR_400_COMPACT; | ||
| 462 | } else | ||
| 463 | #ifdef _DEBUG_PEERID | ||
| 464 | if(!byte_diff(data,7,"peer_id")) { | ||
| 465 | g_this_peerid_len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
| 466 | g_this_peerid_data = g_this_peerid_len > 0 ? data : 0; | ||
| 467 | } else | ||
| 468 | #endif | ||
| 469 | scan_urlencoded_skipvalue( &c ); | ||
| 470 | break; | 372 | break; | 
| 471 | case 9: | 373 | case 5: /* matched "compact" */ | 
| 472 | if(byte_diff(data,9,"info_hash")) { | 374 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | 
| 473 | scan_urlencoded_skipvalue( &c ); | 375 | if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) ) HTTPERROR_400_PARAM; | 
| 474 | continue; | 376 | if( !tmp ) HTTPERROR_400_COMPACT; | 
| 475 | } | 377 | break; | 
| 378 | case 6: /* matched "info_hash" */ | ||
| 379 | if( hash ) HTTPERROR_400_DOUBLEHASH; | ||
| 476 | /* ignore this, when we have less than 20 bytes */ | 380 | /* ignore this, when we have less than 20 bytes */ | 
| 477 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; | 381 | if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; | 
| 478 | hash = (ot_hash*)data; | 382 | hash = (ot_hash*)write_ptr; | 
| 383 | break; | ||
| 384 | #ifdef WANT_IP_FROM_QUERY_STRING | ||
| 385 | case 7: /* matched "ip" */ | ||
| 386 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | ||
| 387 | if( ( len <= 0 ) || scan_fixed_ip( write_ptr, len, (unsigned char*)/*tmp*/ws->reply ) ) HTTPERROR_400_PARAM; | ||
| 388 | OT_SETIP( &peer, /*tmp*/ws->reply ); | ||
| 479 | break; | 389 | break; | 
| 390 | #endif | ||
| 391 | #ifdef _DEBUG_PEERID | ||
| 392 | case 8: /* matched "peer_id" */ | ||
| 393 | ws->peer_id_size = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | ||
| 394 | ws->peer_id = ws->peer_id_size > 0 ? write_ptr : 0; | ||
| 395 | break; | ||
| 396 | #endif | ||
| 480 | } | 397 | } | 
| 481 | } | 398 | } | 
| 482 | 399 | ||
| 483 | /* Scanned whole query string */ | 400 | /* Scanned whole query string */ | 
| 484 | if( !hash ) | 401 | if( !hash ) | 
| 485 | return sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" ); | 402 | 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" ); | 
| 486 | 403 | ||
| 487 | if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) | 404 | if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) | 
| 488 | len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP ); | 405 | ws->reply_size = remove_peer_from_torrent( hash, &peer, ws->reply, FLAG_TCP ); | 
| 489 | else | 406 | else | 
| 490 | len = add_peer_to_torrent_and_return_peers(hash, &peer, FLAG_TCP, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf); | 407 | ws->reply_size = add_peer_to_torrent_and_return_peers(hash, &peer, FLAG_TCP, numwant, ws->reply ); | 
| 491 | 408 | ||
| 492 | if( !len ) HTTPERROR_500; | 409 | if( !ws->reply_size ) HTTPERROR_500; | 
| 493 | 410 | ||
| 494 | stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, len); | 411 | stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size); | 
| 495 | return len; | 412 | return ws->reply_size; | 
| 496 | } | 413 | } | 
| 497 | 414 | ||
| 498 | ssize_t http_handle_request( const int64 client_socket, char *data, size_t recv_length ) { | 415 | ssize_t http_handle_request( const int64 client_socket, struct ot_workstruct *ws ) { | 
| 499 | char *c, *recv_header=data; | 416 | ssize_t reply_off, len; | 
| 500 | ssize_t reply_size = 0, reply_off, len; | 417 | char *read_ptr = ws->request, *write_ptr; | 
| 501 | 418 | ||
| 502 | #ifdef _DEBUG_HTTPERROR | 419 | #ifdef _DEBUG_HTTPERROR | 
| 503 | if( recv_length >= sizeof( debug_request ) ) | 420 | reply_off = ws->request_size; | 
| 504 | recv_length = sizeof( debug_request) - 1; | 421 | if( ws->request_size >= (ssize_t)ws->debugbuf_size ) | 
| 505 | memmove( debug_request, recv_header, recv_length ); | 422 | reply_off = ws->debugbuf_size - 1; | 
| 506 | debug_request[ recv_length ] = 0; | 423 | memmove( ws->debugbuf, ws->request, reply_off ); | 
| 424 | ws->debugbuf[ reply_off ] = 0; | ||
| 507 | #endif | 425 | #endif | 
| 508 | 426 | ||
| 427 | /* Tell subroutines where to put reply data */ | ||
| 428 | ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH; | ||
| 429 | |||
| 509 | /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */ | 430 | /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */ | 
| 510 | if( byte_diff( data, 5, "GET /") ) HTTPERROR_400; | 431 | if( memcmp( read_ptr, "GET /", 5) ) HTTPERROR_400; | 
| 511 | 432 | ||
| 512 | /* Skip leading '/' */ | 433 | /* Skip leading '/' */ | 
| 513 | for( c = data+4; *c == '/'; ++c); | 434 | for( read_ptr+=4; *read_ptr == '/'; ++read_ptr); | 
| 514 | 435 | ||
| 515 | /* Try to parse the request. | 436 | /* Try to parse the request. | 
| 516 | In reality we abandoned requiring the url to be correct. This now | 437 | In reality we abandoned requiring the url to be correct. This now | 
| 517 | only decodes url encoded characters, we check for announces and | 438 | only decodes url encoded characters, we check for announces and | 
| 518 | scrapes by looking for "a*" or "sc" */ | 439 | scrapes by looking for "a*" or "sc" */ | 
| 519 | len = scan_urlencoded_query( &c, data = c, SCAN_PATH ); | 440 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_PATH ); | 
| 520 | 441 | ||
| 521 | /* If parsing returned an error, leave with not found */ | 442 | /* If parsing returned an error, leave with not found */ | 
| 522 | if( g_redirecturl && ( len == -2 ) ) HTTPERROR_302; | 443 | if( g_redirecturl && ( len == -2 ) ) HTTPERROR_302; | 
| 523 | if( len <= 0 ) HTTPERROR_404; | 444 | if( len <= 0 ) HTTPERROR_404; | 
| 524 | 445 | ||
| 525 | /* This is the hardcore match for announce*/ | 446 | /* This is the hardcore match for announce*/ | 
| 526 | if( ( *data == 'a' ) || ( *data == '?' ) ) | 447 | if( ( *write_ptr == 'a' ) || ( *write_ptr == '?' ) ) | 
| 527 | reply_size = http_handle_announce( client_socket, c ); | 448 | http_handle_announce( client_socket, ws, read_ptr ); | 
| 528 | #ifdef WANT_FULLSCRAPE | 449 | #ifdef WANT_FULLSCRAPE | 
| 529 | else if( !byte_diff( data, 12, "scrape HTTP/" ) ) | 450 | else if( !memcmp( write_ptr, "scrape HTTP/", 12 ) ) | 
| 530 | reply_size = http_handle_fullscrape( client_socket, recv_header, recv_length ); | 451 | http_handle_fullscrape( client_socket, ws ); | 
| 531 | #endif | 452 | #endif | 
| 532 | /* This is the hardcore match for scrape */ | 453 | /* This is the hardcore match for scrape */ | 
| 533 | else if( !byte_diff( data, 2, "sc" ) ) | 454 | else if( !memcmp( write_ptr, "sc", 2 ) ) | 
| 534 | reply_size = http_handle_scrape( client_socket, c ); | 455 | http_handle_scrape( client_socket, ws, read_ptr ); | 
| 535 | /* All the rest is matched the standard way */ | 456 | /* All the rest is matched the standard way */ | 
| 536 | else switch( len ) { | 457 | else if( !memcmp( write_ptr, "stats", 5) ) | 
| 537 | case 5: /* stats ? */ | 458 | http_handle_stats( client_socket, ws, read_ptr ); | 
| 538 | if( byte_diff( data, 5, "stats") ) HTTPERROR_404; | 459 | else | 
| 539 | reply_size = http_handle_stats( client_socket, c, recv_header, recv_length ); | ||
| 540 | break; | ||
| 541 | default: | ||
| 542 | HTTPERROR_404; | 460 | HTTPERROR_404; | 
| 543 | } | ||
| 544 | 461 | ||
| 545 | /* If routines handled sending themselves, just return */ | 462 | /* If routines handled sending themselves, just return */ | 
| 546 | if( reply_size == -2 ) return 0; | 463 | if( ws->reply_size == -2 ) return 0; | 
| 547 | /* If routine failed, let http error take over */ | 464 | /* If routine failed, let http error take over */ | 
| 548 | if( reply_size == -1 ) HTTPERROR_500; | 465 | if( ws->reply_size == -1 ) HTTPERROR_500; | 
| 549 | 466 | ||
| 550 | /* This one is rather ugly, so I take you step by step through it. | 467 | /* This one is rather ugly, so I take you step by step through it. | 
| 551 | 468 | ||
| 552 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to | 469 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to | 
| 553 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string | 470 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our work buffer, which is enough for the static string | 
| 554 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate | 471 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate | 
| 555 | the space NOT needed to expand in reply_off | 472 | the space NOT needed to expand in reply_off | 
| 556 | */ | 473 | */ | 
| 557 | reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_outbuf, 0, "%zd", reply_size ); | 474 | reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( ws->outbuf, 0, "%zd", ws->reply_size ); | 
| 558 | 475 | ws->reply = ws->outbuf + reply_off; | |
| 476 | |||
| 559 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete | 477 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete | 
| 560 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ | 478 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ | 
| 561 | reply_size += 1 + sprintf( static_outbuf + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); | 479 | ws->reply_size += 1 + sprintf( ws->reply, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", ws->reply_size ); | 
| 562 | 480 | ||
| 563 | /* 3. Finally we join both blocks neatly */ | 481 | /* 3. Finally we join both blocks neatly */ | 
| 564 | static_outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; | 482 | ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; | 
| 565 | 483 | ||
| 566 | http_senddata( client_socket, static_outbuf + reply_off, reply_size ); | 484 | http_senddata( client_socket, ws ); | 
| 567 | return reply_size; | 485 | return ws->reply_size; | 
| 568 | } | 486 | } | 
| 569 | 487 | ||
| 570 | const char *g_version_http_c = "$Source$: $Revision$\n"; | 488 | const char *g_version_http_c = "$Source$: $Revision$\n"; | 
