summaryrefslogtreecommitdiff
path: root/ot_http.c
diff options
context:
space:
mode:
authorerdgeist <>2009-11-18 04:00:26 +0000
committererdgeist <>2009-11-18 04:00:26 +0000
commitf3c0359876b59aa8fc2f03fa61363ede9d2edc2f (patch)
treea7924f5d8ed72ac8f7c4d5f68987f2aea04f3450 /ot_http.c
parent90e7262d9d79b4098cbc52df549e138b77add193 (diff)
Make header parsing more efficient, prepare multithreading and keep-alive.
Diffstat (limited to 'ot_http.c')
-rw-r--r--ot_http.c111
1 files changed, 57 insertions, 54 deletions
diff --git a/ot_http.c b/ot_http.c
index 72e8c57..9c9fb0f 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -18,6 +18,7 @@
18#include "iob.h" 18#include "iob.h"
19#include "ip6.h" 19#include "ip6.h"
20#include "scan.h" 20#include "scan.h"
21#include "case.h"
21 22
22/* Opentracker */ 23/* Opentracker */
23#include "trackerlogic.h" 24#include "trackerlogic.h"
@@ -44,33 +45,42 @@ static void http_senddata( const int64 sock, struct ot_workstruct *ws ) {
44 struct http_data *cookie = io_getcookie( sock ); 45 struct http_data *cookie = io_getcookie( sock );
45 ssize_t written_size; 46 ssize_t written_size;
46 47
48 if( !cookie ) { io_close(sock); return; }
49
47 /* whoever sends data is not interested in its input-array */ 50 /* whoever sends data is not interested in its input-array */
48 if( cookie && ( cookie->flag & STRUCT_HTTP_FLAG_ARRAY_USED ) ) { 51 if( ws->keep_alive && ws->header_size != ws->request_size ) {
49 cookie->flag &= ~STRUCT_HTTP_FLAG_ARRAY_USED; 52 size_t rest = ws->request_size - ws->header_size;
50 array_reset( &cookie->data.request ); 53 if( array_start(&cookie->request) ) {
51 } 54 memmove( array_start(&cookie->request), ws->request + ws->header_size, rest );
55 array_truncate( &cookie->request, 1, rest );
56 } else
57 array_catb(&cookie->request, ws->request + ws->header_size, rest );
58 } else
59 array_reset( &cookie->request );
52 60
53 written_size = write( sock, ws->reply, ws->reply_size ); 61 written_size = write( sock, ws->reply, ws->reply_size );
54 if( ( written_size < 0 ) || ( written_size == ws->reply_size ) ) { 62 if( ( written_size < 0 ) || ( ( written_size == ws->reply_size ) && !ws->keep_alive ) ) {
55 free( cookie ); io_close( sock ); 63 array_reset( &cookie->request );
56 } else { 64 free( cookie ); io_close( sock ); return;
65 }
66
67 if( written_size < ws->reply_size ) {
57 char * outbuf; 68 char * outbuf;
58 tai6464 t; 69 tai6464 t;
59 70
60 if( !cookie ) return; 71 if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) {
61 if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) {
62 free(cookie); io_close( sock ); 72 free(cookie); io_close( sock );
63 return; 73 return;
64 } 74 }
65 75
66 iob_reset( &cookie->data.batch );
67 memcpy( outbuf, ws->reply + written_size, ws->reply_size - written_size ); 76 memcpy( outbuf, ws->reply + written_size, ws->reply_size - written_size );
68 iob_addbuf_free( &cookie->data.batch, outbuf, ws->reply_size - written_size ); 77 iob_addbuf_free( &cookie->batch, outbuf, ws->reply_size - written_size );
69 cookie->flag |= STRUCT_HTTP_FLAG_IOB_USED;
70 78
71 /* writeable short data sockets just have a tcp timeout */ 79 /* writeable short data sockets just have a tcp timeout */
72 taia_uint( &t, 0 ); io_timeout( sock, t ); 80 if( !ws->keep_alive ) {
73 io_dontwantread( sock ); 81 taia_uint( &t, 0 ); io_timeout( sock, t );
82 io_dontwantread( sock );
83 }
74 io_wantwrite( sock ); 84 io_wantwrite( sock );
75 } 85 }
76} 86}
@@ -93,7 +103,7 @@ ssize_t http_issue_error( const int64 sock, struct ot_workstruct *ws, int code )
93 if( code == CODE_HTTPERROR_302 ) 103 if( code == CODE_HTTPERROR_302 )
94 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 ); 104 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 );
95 else 105 else
96 ws->reply_size = snprintf( ws->reply, G_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); 106 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);
97 107
98#ifdef _DEBUG_HTTPERROR 108#ifdef _DEBUG_HTTPERROR
99 fprintf( stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf ); 109 fprintf( stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf );
@@ -116,12 +126,8 @@ ssize_t http_sendiovecdata( const int64 sock, struct ot_workstruct *ws, int iove
116 HTTPERROR_500; 126 HTTPERROR_500;
117 } 127 }
118 128
119 /* If this socket collected request in a buffer, 129 /* If this socket collected request in a buffer, free it now */
120 free it now */ 130 array_reset( &cookie->request );
121 if( cookie->flag & STRUCT_HTTP_FLAG_ARRAY_USED ) {
122 cookie->flag &= ~STRUCT_HTTP_FLAG_ARRAY_USED;
123 array_reset( &cookie->data.request );
124 }
125 131
126 /* If we came here, wait for the answer is over */ 132 /* If we came here, wait for the answer is over */
127 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; 133 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK;
@@ -145,16 +151,14 @@ ssize_t http_sendiovecdata( const int64 sock, struct ot_workstruct *ws, int iove
145 else 151 else
146 header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); 152 header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size );
147 153
148 iob_reset( &cookie->data.batch ); 154 iob_reset( &cookie->batch );
149 iob_addbuf_free( &cookie->data.batch, header, header_size ); 155 iob_addbuf_free( &cookie->batch, header, header_size );
150 156
151 /* Will move to ot_iovec.c */ 157 /* Will move to ot_iovec.c */
152 for( i=0; i<iovec_entries; ++i ) 158 for( i=0; i<iovec_entries; ++i )
153 iob_addbuf_munmap( &cookie->data.batch, iovector[i].iov_base, iovector[i].iov_len ); 159 iob_addbuf_munmap( &cookie->batch, iovector[i].iov_base, iovector[i].iov_len );
154 free( iovector ); 160 free( iovector );
155 161
156 cookie->flag |= STRUCT_HTTP_FLAG_IOB_USED;
157
158 /* writeable sockets timeout after 10 minutes */ 162 /* writeable sockets timeout after 10 minutes */
159 taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND ); 163 taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND );
160 io_timeout( sock, t ); 164 io_timeout( sock, t );
@@ -240,9 +244,7 @@ static const ot_keywords keywords_format[] =
240 } 244 }
241 245
242 /* Simple stats can be answerred immediately */ 246 /* Simple stats can be answerred immediately */
243 if( !( ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 ) ) ) HTTPERROR_500; 247 return ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 );
244
245 return ws->reply_size;
246} 248}
247 249
248#ifdef WANT_MODEST_FULLSCRAPES 250#ifdef WANT_MODEST_FULLSCRAPES
@@ -336,7 +338,7 @@ static ssize_t http_handle_scrape( const int64 sock, struct ot_workstruct *ws, c
336 numwant = OT_MAXMULTISCRAPE_COUNT; 338 numwant = OT_MAXMULTISCRAPE_COUNT;
337 339
338 /* Enough for http header + whole scrape string */ 340 /* Enough for http header + whole scrape string */
339 if( !( ws->reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, ws->reply ) ) ) HTTPERROR_500; 341 ws->reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, ws->reply );
340 stats_issue_event( EVENT_SCRAPE, FLAG_TCP, ws->reply_size ); 342 stats_issue_event( EVENT_SCRAPE, FLAG_TCP, ws->reply_size );
341 return ws->reply_size; 343 return ws->reply_size;
342} 344}
@@ -345,6 +347,19 @@ static ssize_t http_handle_scrape( const int64 sock, struct ot_workstruct *ws, c
345 unsigned long long numwants[201]; 347 unsigned long long numwants[201];
346#endif 348#endif
347 349
350static char* http_header( char *data, size_t byte_count, char *header ) {
351 size_t i;
352 long sl = strlen( header );
353 for( i = 0; i + sl + 2 < byte_count; ++i ) {
354 if( data[i] != '\n' || data[ i + sl + 1] != ':' ) continue;
355 if( !case_equalb( data + i + 1, sl, header ) ) continue;
356 data += i + sl + 2;
357 while( *data == ' ' || *data == '\t' ) ++data;
358 return data;
359 }
360 return 0;
361}
362
348static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "event", 3 }, { "numwant", 4 }, { "compact", 5 }, { "compact6", 5 }, { "info_hash", 6 }, 363static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "event", 3 }, { "numwant", 4 }, { "compact", 5 }, { "compact6", 5 }, { "info_hash", 6 },
349#ifdef WANT_IP_FROM_QUERY_STRING 364#ifdef WANT_IP_FROM_QUERY_STRING
350{ "ip", 7 }, 365{ "ip", 7 },
@@ -373,29 +388,12 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
373#ifdef WANT_IP_FROM_PROXY 388#ifdef WANT_IP_FROM_PROXY
374 if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_PROXY ) ) { 389 if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_PROXY ) ) {
375 ot_ip6 proxied_ip; 390 ot_ip6 proxied_ip;
376 char *fwd, *fwd_new = ws->request; 391 char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" );
377
378 /* Zero terminate for string routines. Normally we'd only overwrite bollocks */
379 ws->request[ws->request_size-1] = 0;
380
381 /* Find last occurence of the forwarded header */
382 do {
383 fwd = fwd_new;
384 fwd_new += 16;
385 fwd_new = strcasestr( fwd_new, "\nX-Forwarded-For:" );
386 } while( fwd_new );
387
388 /* Skip spaces between : and the ip address */
389 if( fwd ) {
390 fwd += 18; /* sizeof( "\nX-Forwarded-For:" ) */
391 while( *fwd == ' ' ) ++fwd;
392 }
393
394 if( fwd && scan_ip6( fwd, proxied_ip ) ) 392 if( fwd && scan_ip6( fwd, proxied_ip ) )
395 OT_SETIP( &peer, proxied_ip ); 393 OT_SETIP( &peer, proxied_ip );
396 else 394 else
397 OT_SETIP( &peer, cookie->ip ); 395 OT_SETIP( &peer, cookie->ip );
398 } 396 } else
399#endif 397#endif
400 OT_SETIP( &peer, cookie->ip ); 398 OT_SETIP( &peer, cookie->ip );
401 OT_SETPORT( &peer, &port ); 399 OT_SETPORT( &peer, &port );
@@ -509,8 +507,6 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
509 else 507 else
510 ws->reply_size = add_peer_to_torrent_and_return_peers( *hash, &peer, FLAG_TCP, numwant, ws->reply ); 508 ws->reply_size = add_peer_to_torrent_and_return_peers( *hash, &peer, FLAG_TCP, numwant, ws->reply );
511 509
512 if( !ws->reply_size ) HTTPERROR_500;
513
514 stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size); 510 stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size);
515 return ws->reply_size; 511 return ws->reply_size;
516} 512}
@@ -586,10 +582,17 @@ ssize_t http_handle_request( const int64 sock, struct ot_workstruct *ws ) {
586 else 582 else
587 HTTPERROR_404; 583 HTTPERROR_404;
588 584
585 /* Find out if the client wants to keep this connection alive */
586 ws->keep_alive = 0;
587#ifdef WANT_KEEPALIVE
588 read_ptr=http_header( ws->request, ws->header_size, "connection");
589 if( read_ptr && ( *read_ptr == 'K' || *read_ptr == 'k' ) ) ws->keep_alive = 1;
590#endif
591
589 /* If routines handled sending themselves, just return */ 592 /* If routines handled sending themselves, just return */
590 if( ws->reply_size == -2 ) return 0; 593 if( ws->reply_size == -2 ) return 0;
591 /* If routine failed, let http error take over */ 594 /* If routine failed, let http error take over */
592 if( ws->reply_size == -1 ) HTTPERROR_500; 595 if( ws->reply_size <= 0 ) HTTPERROR_500;
593 596
594 /* This one is rather ugly, so I take you step by step through it. 597 /* This one is rather ugly, so I take you step by step through it.
595 598
@@ -602,8 +605,8 @@ ssize_t http_handle_request( const int64 sock, struct ot_workstruct *ws ) {
602 ws->reply = ws->outbuf + reply_off; 605 ws->reply = ws->outbuf + reply_off;
603 606
604 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete 607 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete
605 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ 608 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */
606 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 ); 609 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 );
607 610
608 /* 3. Finally we join both blocks neatly */ 611 /* 3. Finally we join both blocks neatly */
609 ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; 612 ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';