summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opentracker.c66
-rw-r--r--ot_http.c111
-rw-r--r--ot_http.h14
3 files changed, 92 insertions, 99 deletions
diff --git a/opentracker.c b/opentracker.c
index c1fe945..57eca12 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -143,10 +143,8 @@ static size_t header_complete( char * request, ssize_t byte_count ) {
143static void handle_dead( const int64 sock ) { 143static void handle_dead( const int64 sock ) {
144 struct http_data* cookie=io_getcookie( sock ); 144 struct http_data* cookie=io_getcookie( sock );
145 if( cookie ) { 145 if( cookie ) {
146 if( cookie->flag & STRUCT_HTTP_FLAG_IOB_USED ) 146 iob_reset( &cookie->batch );
147 iob_reset( &cookie->data.batch ); 147 array_reset( &cookie->request );
148 if( cookie->flag & STRUCT_HTTP_FLAG_ARRAY_USED )
149 array_reset( &cookie->data.request );
150 if( cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK ) 148 if( cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK )
151 mutex_workqueue_canceltask( sock ); 149 mutex_workqueue_canceltask( sock );
152 free( cookie ); 150 free( cookie );
@@ -154,46 +152,42 @@ static void handle_dead( const int64 sock ) {
154 io_close( sock ); 152 io_close( sock );
155} 153}
156 154
157static ssize_t handle_read( const int64 sock, struct ot_workstruct *ws ) { 155static void handle_read( const int64 sock, struct ot_workstruct *ws ) {
158 struct http_data* cookie = io_getcookie( sock ); 156 struct http_data* cookie = io_getcookie( sock );
159 ssize_t byte_count; 157 ssize_t byte_count;
160 158
161 if( ( byte_count = io_tryread( sock, ws->inbuf, G_INBUF_SIZE ) ) <= 0 ) { 159 if( ( byte_count = io_tryread( sock, ws->inbuf, G_INBUF_SIZE ) ) <= 0 ) {
162 handle_dead( sock ); 160 handle_dead( sock );
163 return 0; 161 return;
164 } 162 }
165 163
166 /* If we get the whole request in one packet, handle it without copying */ 164 /* If we get the whole request in one packet, handle it without copying */
167 if( !array_start( &cookie->data.request ) ) { 165 if( !array_start( &cookie->request ) ) {
168 if( memchr( ws->inbuf, '\n', byte_count ) ) { 166 if( ( ws->header_size = header_complete( ws->inbuf, byte_count ) ) ) {
169 ws->request = ws->inbuf; 167 ws->request = ws->inbuf;
170 ws->request_size = byte_count; 168 ws->request_size = byte_count;
171 return http_handle_request( sock, ws ); 169 http_handle_request( sock, ws );
172 } 170 } else
173 171 array_catb( &cookie->request, ws->inbuf, byte_count );
174 /* ... else take a copy */ 172 return;
175 cookie->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
176 array_catb( &cookie->data.request, ws->inbuf, byte_count );
177 return 0;
178 } 173 }
179 174
180 array_catb( &cookie->data.request, ws->inbuf, byte_count ); 175 array_catb( &cookie->request, ws->inbuf, byte_count );
181 176 if( array_failed( &cookie->request ) || array_bytes( &cookie->request ) > 8192 ) {
182 if( array_failed( &cookie->data.request ) || 177 http_issue_error( sock, ws, CODE_HTTPERROR_500 );
183 array_bytes( &cookie->data.request ) > 8192 ) 178 return;
184 return http_issue_error( sock, ws, CODE_HTTPERROR_500 ); 179 }
185
186 if( !memchr( array_start( &cookie->data.request ), '\n', array_bytes( &cookie->data.request ) ) )
187 return 0;
188 180
189 ws->request = array_start( &cookie->data.request ); 181 while( ( ws->header_size = header_complete( array_start( &cookie->request ), array_bytes( &cookie->request ) ) ) ) {
190 ws->request_size = array_bytes( &cookie->data.request ); 182 ws->request = array_start( &cookie->request );
191 return http_handle_request( sock, ws ); 183 ws->request_size = array_bytes( &cookie->request );
184 http_handle_request( sock, ws );
185 }
192} 186}
193 187
194static void handle_write( const int64 sock ) { 188static void handle_write( const int64 sock ) {
195 struct http_data* cookie=io_getcookie( sock ); 189 struct http_data* cookie=io_getcookie( sock );
196 if( !cookie || ( iob_send( sock, &cookie->data.batch ) <= 0 ) ) 190 if( !cookie || ( iob_send( sock, &cookie->batch ) <= 0 ) )
197 handle_dead( sock ); 191 handle_dead( sock );
198} 192}
199 193
@@ -214,12 +208,12 @@ static void handle_accept( const int64 serversocket ) {
214 io_close( sock ); 208 io_close( sock );
215 continue; 209 continue;
216 } 210 }
217 io_setcookie( sock, cookie );
218 io_wantread( sock );
219
220 memset(cookie, 0, sizeof( struct http_data ) ); 211 memset(cookie, 0, sizeof( struct http_data ) );
221 memcpy(cookie->ip,ip,sizeof(ot_ip6)); 212 memcpy(cookie->ip,ip,sizeof(ot_ip6));
222 213
214 io_setcookie( sock, cookie );
215 io_wantread( sock );
216
223 stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 217 stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
224 218
225 /* That breaks taia encapsulation. But there is no way to take system 219 /* That breaks taia encapsulation. But there is no way to take system
@@ -228,17 +222,16 @@ static void handle_accept( const int64 serversocket ) {
228 tai_unix( &(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT) ); 222 tai_unix( &(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT) );
229 io_timeout( sock, t ); 223 io_timeout( sock, t );
230 } 224 }
231
232 if( errno == EAGAIN )
233 io_eagain( serversocket );
234} 225}
235 226
236static void server_mainloop( ) { 227static void * server_mainloop( void * args ) {
237 struct ot_workstruct ws; 228 struct ot_workstruct ws;
238 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 229 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
239 struct iovec *iovector; 230 struct iovec *iovector;
240 int iovec_entries; 231 int iovec_entries;
241 232
233 (void)args;
234
242 /* Initialize our "thread local storage" */ 235 /* Initialize our "thread local storage" */
243 ws.inbuf = malloc( G_INBUF_SIZE ); 236 ws.inbuf = malloc( G_INBUF_SIZE );
244 ws.outbuf = malloc( G_OUTBUF_SIZE ); 237 ws.outbuf = malloc( G_OUTBUF_SIZE );
@@ -282,6 +275,7 @@ static void server_mainloop( ) {
282 /* Enforce setting the clock */ 275 /* Enforce setting the clock */
283 signal_handler( SIGALRM ); 276 signal_handler( SIGALRM );
284 } 277 }
278 return 0;
285} 279}
286 280
287static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) { 281static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) {
@@ -475,7 +469,7 @@ void load_state(const char * const state_filename ) {
475 if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue; 469 if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue;
476 add_torrent_from_saved_state( infohash, base, downcount ); 470 add_torrent_from_saved_state( infohash, base, downcount );
477 } 471 }
478 472
479 fclose( state_filehandle ); 473 fclose( state_filehandle );
480} 474}
481 475
@@ -606,7 +600,7 @@ int main( int argc, char **argv ) {
606 /* Kick off our initial clock setting alarm */ 600 /* Kick off our initial clock setting alarm */
607 alarm(5); 601 alarm(5);
608 602
609 server_mainloop( ); 603 server_mainloop( 0 );
610 604
611 return 0; 605 return 0;
612} 606}
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';
diff --git a/ot_http.h b/ot_http.h
index 84da0c2..7e367ed 100644
--- a/ot_http.h
+++ b/ot_http.h
@@ -7,18 +7,14 @@
7#define __OT_HTTP_H__ 7#define __OT_HTTP_H__
8 8
9typedef enum { 9typedef enum {
10 STRUCT_HTTP_FLAG_ARRAY_USED = 1, 10 STRUCT_HTTP_FLAG_WAITINGFORTASK = 1,
11 STRUCT_HTTP_FLAG_IOB_USED = 2, 11 STRUCT_HTTP_FLAG_GZIP = 2,
12 STRUCT_HTTP_FLAG_WAITINGFORTASK = 4, 12 STRUCT_HTTP_FLAG_BZIP2 = 4
13 STRUCT_HTTP_FLAG_GZIP = 8,
14 STRUCT_HTTP_FLAG_BZIP2 = 16
15} STRUCT_HTTP_FLAG; 13} STRUCT_HTTP_FLAG;
16 14
17struct http_data { 15struct http_data {
18 union { 16 array request;
19 array request; 17 io_batch batch;
20 io_batch batch;
21 } data;
22 ot_ip6 ip; 18 ot_ip6 ip;
23 STRUCT_HTTP_FLAG flag; 19 STRUCT_HTTP_FLAG flag;
24}; 20};