Branch data Line data Source code
1 : : // $Id: HTTP.cc 7073 2010-09-13 00:45:02Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include <ctype.h>
8 : : #include <math.h>
9 : : #include <stdlib.h>
10 : :
11 : : #include "NetVar.h"
12 : : #include "HTTP.h"
13 : : #include "Event.h"
14 : : #include "MIME.h"
15 : : #include "TCP_Rewriter.h"
16 : :
17 : : const bool DEBUG_http = false;
18 : :
19 : : enum {
20 : : EXPECT_REQUEST_LINE,
21 : : EXPECT_REQUEST_MESSAGE,
22 : : EXPECT_REQUEST_TRAILER,
23 : : };
24 : :
25 : : enum {
26 : : EXPECT_REPLY_LINE,
27 : : EXPECT_REPLY_MESSAGE,
28 : : EXPECT_REPLY_TRAILER,
29 : : };
30 : :
31 : 881 : HTTP_Entity::HTTP_Entity(HTTP_Message *arg_message, MIME_Entity* parent_entity, int arg_expect_body)
32 : 881 : :MIME_Entity(arg_message, parent_entity)
33 : : {
34 : 881 : http_message = arg_message;
35 : 881 : expect_body = arg_expect_body;
36 : 881 : chunked_transfer_state = NON_CHUNKED_TRANSFER;
37 : 881 : content_length = -1; // unspecified
38 : 881 : expect_data_length = 0;
39 : 881 : body_length = 0;
40 : 881 : header_length = 0;
41 : 881 : deliver_body = (http_entity_data != 0);
42 : 881 : encoding = IDENTITY;
43 : : #ifdef HAVE_LIBZ
44 : 881 : zip = 0;
45 : : #endif
46 : 881 : }
47 : :
48 : 1745 : void HTTP_Entity::EndOfData()
49 : : {
50 : : if ( DEBUG_http )
51 : : DEBUG_MSG("%.6f: end of data\n", network_time);
52 : :
53 : : #ifdef HAVE_LIBZ
54 [ + + ]: 1745 : if ( zip )
55 : : {
56 : 111 : zip->Done();
57 [ + - ]: 111 : delete zip;
58 : 111 : zip = 0;
59 : 111 : encoding = IDENTITY;
60 : : }
61 : : #endif
62 : :
63 [ + + ]: 1745 : if ( body_length )
64 : : http_message->MyHTTP_Analyzer()->
65 : 765 : ForwardEndOfData(http_message->IsOrig());
66 : :
67 : 1745 : MIME_Entity::EndOfData();
68 : 1745 : }
69 : :
70 : 11277 : void HTTP_Entity::Deliver(int len, const char* data, int trailing_CRLF)
71 : : {
72 : : if ( DEBUG_http )
73 : : {
74 : : DEBUG_MSG("%.6f HTTP_Entity::Deliver len=%d, in_header=%d\n",
75 : : network_time, len, in_header);
76 : : }
77 : :
78 [ + + ]: 11277 : if ( end_of_data )
79 : : {
80 : : // Multipart entities may have trailers
81 [ + - ]: 4 : if ( content_type != CONTENT_TYPE_MULTIPART )
82 : 4 : IllegalFormat("data trailing the end of entity");
83 : 4 : return;
84 : : }
85 : :
86 [ + + ]: 11273 : if ( in_header )
87 : : {
88 [ - + ]: 8883 : ASSERT(trailing_CRLF);
89 : 8883 : header_length += len;
90 : 8883 : MIME_Entity::Deliver(len, data, trailing_CRLF);
91 : 8883 : return;
92 : : }
93 : :
94 : : // Entity body.
95 [ + + ][ - + ]: 2436 : if ( content_type == CONTENT_TYPE_MULTIPART ||
96 : : content_type == CONTENT_TYPE_MESSAGE )
97 : 46 : DeliverBody(len, data, trailing_CRLF);
98 : :
99 [ + + ]: 2344 : else if ( chunked_transfer_state != NON_CHUNKED_TRANSFER )
100 : : {
101 [ + + + - ]: 495 : switch ( chunked_transfer_state ) {
102 : : case EXPECT_CHUNK_SIZE:
103 [ - + ]: 129 : ASSERT(trailing_CRLF);
104 [ - + ]: 129 : if ( ! atoi_n(len, data, 0, 16, expect_data_length) )
105 : : {
106 : 0 : http_message->Weird("HTTP_bad_chunk_size");
107 : 0 : expect_data_length = 0;
108 : : }
109 : :
110 [ + + ]: 129 : if ( expect_data_length > 0 )
111 : : {
112 : 99 : chunked_transfer_state = EXPECT_CHUNK_DATA;
113 : 99 : SetPlainDelivery(expect_data_length);
114 : : }
115 : : else
116 : : {
117 : : // This is the last chunk
118 : 30 : in_header = 1;
119 : 30 : chunked_transfer_state = EXPECT_CHUNK_TRAILER;
120 : : }
121 : 129 : break;
122 : :
123 : : case EXPECT_CHUNK_DATA:
124 [ - + ]: 268 : ASSERT(! trailing_CRLF);
125 [ - + ]: 268 : ASSERT(len <= expect_data_length);
126 : 268 : expect_data_length -= len;
127 [ + + ]: 268 : if ( expect_data_length <= 0 )
128 : : {
129 : 98 : SetPlainDelivery(0);
130 : 98 : chunked_transfer_state = EXPECT_CHUNK_DATA_CRLF;
131 : : }
132 : 268 : DeliverBody(len, data, 0);
133 : 268 : break;
134 : :
135 : : case EXPECT_CHUNK_DATA_CRLF:
136 [ - + ]: 98 : ASSERT(trailing_CRLF);
137 [ - + ]: 98 : if ( len > 0 )
138 : 0 : IllegalFormat("inaccurate chunk size: data before <CR><LF>");
139 : 495 : chunked_transfer_state = EXPECT_CHUNK_SIZE;
140 : : break;
141 : : }
142 : : }
143 : :
144 [ + + ]: 1849 : else if ( content_length >= 0 )
145 : : {
146 [ - + ]: 1798 : ASSERT(! trailing_CRLF);
147 [ - + ]: 1798 : ASSERT(len <= expect_data_length);
148 : :
149 : 1798 : DeliverBody(len, data, 0);
150 : :
151 : 1798 : expect_data_length -= len;
152 [ + + ]: 1798 : if ( expect_data_length <= 0 )
153 : : {
154 : 335 : SetPlainDelivery(0);
155 : 1798 : EndOfData();
156 : : }
157 : : }
158 : :
159 : : else
160 : 11277 : DeliverBody(len, data, trailing_CRLF);
161 : : }
162 : :
163 : : class HTTP_Entity::UncompressedOutput : public Analyzer::OutputHandler {
164 : : public:
165 : 111 : UncompressedOutput(HTTP_Entity* e) { entity = e; }
166 [ + - ][ # # ]: 111 : virtual ~UncompressedOutput() { }
167 : 888 : virtual void DeliverStream(int len, const u_char* data, bool orig)
168 : : {
169 : 888 : entity->DeliverBodyClear(len, (char*) data, false);
170 : 888 : }
171 : : private:
172 : : HTTP_Entity* entity;
173 : : };
174 : :
175 : 2163 : void HTTP_Entity::DeliverBody(int len, const char* data, int trailing_CRLF)
176 : : {
177 : : #ifdef HAVE_LIBZ
178 [ + + ][ - + ]: 2839 : if ( encoding == GZIP || encoding == DEFLATE )
179 : : {
180 : : ZIP_Analyzer::Method method =
181 : : encoding == GZIP ?
182 [ - + ]: 676 : ZIP_Analyzer::GZIP : ZIP_Analyzer::DEFLATE;
183 : :
184 [ + + ]: 676 : if ( ! zip )
185 : : {
186 : : // We don't care about the direction here.
187 : : zip = new ZIP_Analyzer(
188 : : http_message->MyHTTP_Analyzer()->Conn(),
189 : 111 : false, method);
190 : 111 : zip->SetOutputHandler(new UncompressedOutput(this));
191 : : }
192 : :
193 : 676 : zip->NextStream(len, (const u_char*) data, false);
194 : : }
195 : : else
196 : : #endif
197 : 1487 : DeliverBodyClear(len, data, trailing_CRLF);
198 : 2163 : }
199 : :
200 : 2375 : void HTTP_Entity::DeliverBodyClear(int len, const char* data, int trailing_CRLF)
201 : : {
202 : 2375 : bool new_data = (body_length == 0);
203 : :
204 : 2375 : body_length += len;
205 [ + + ]: 2375 : if ( trailing_CRLF )
206 : 46 : body_length += 2;
207 : :
208 [ - + ]: 2375 : if ( deliver_body )
209 : 0 : MIME_Entity::Deliver(len, data, trailing_CRLF);
210 : :
211 : : Rule::PatternType rule =
212 : : http_message->IsOrig() ?
213 [ + + ]: 2375 : Rule::HTTP_REQUEST_BODY : Rule::HTTP_REPLY_BODY;
214 : :
215 : : http_message->MyHTTP_Analyzer()->Conn()->
216 : : Match(rule, (const u_char*) data, len,
217 : 2375 : http_message->IsOrig(), new_data, false, new_data);
218 : :
219 : : // FIXME: buffer data for forwarding (matcher might match later).
220 : : http_message->MyHTTP_Analyzer()->ForwardStream(len, (const u_char *) data,
221 : 2375 : http_message->IsOrig());
222 : 2375 : }
223 : :
224 : : // Returns 1 if the undelivered bytes are completely within the body,
225 : : // otherwise returns 0.
226 : 99 : int HTTP_Entity::Undelivered(int len)
227 : : {
228 : : if ( DEBUG_http )
229 : : {
230 : : DEBUG_MSG("Content gap %d, expect_data_length %d\n",
231 : : len, expect_data_length);
232 : : }
233 : :
234 [ + + ][ - + ]: 99 : if ( end_of_data && in_header )
235 : 0 : return 0;
236 : :
237 [ + + ]: 99 : if ( chunked_transfer_state != NON_CHUNKED_TRANSFER )
238 : : {
239 [ + - ][ + + ]: 3 : if ( chunked_transfer_state == EXPECT_CHUNK_DATA &&
240 : : expect_data_length >= len )
241 : : {
242 : 1 : body_length += len;
243 : 1 : expect_data_length -= len;
244 : :
245 : 1 : SetPlainDelivery(expect_data_length);
246 [ - + ]: 1 : if ( expect_data_length == 0 )
247 : 0 : chunked_transfer_state = EXPECT_CHUNK_DATA_CRLF;
248 : :
249 : 1 : return 1;
250 : : }
251 : : else
252 : 2 : return 0;
253 : : }
254 : :
255 [ + + ]: 96 : else if ( content_length >= 0 )
256 : : {
257 [ + + ]: 53 : if ( expect_data_length >= len )
258 : : {
259 : 35 : body_length += len;
260 : 35 : expect_data_length -= len;
261 : :
262 : 35 : SetPlainDelivery(expect_data_length);
263 : :
264 [ + + ]: 35 : if ( expect_data_length <= 0 )
265 : 10 : EndOfData();
266 : :
267 : 35 : return 1;
268 : : }
269 : :
270 : : else
271 : 18 : return 0;
272 : : }
273 : :
274 : 99 : return 0;
275 : : }
276 : :
277 : 0 : void HTTP_Entity::SubmitData(int len, const char* buf)
278 : : {
279 [ # # ]: 0 : if ( deliver_body )
280 : 0 : MIME_Entity::SubmitData(len, buf);
281 : 0 : }
282 : :
283 : 927 : void HTTP_Entity::SetPlainDelivery(int length)
284 : : {
285 [ - + ]: 927 : ASSERT(length >= 0);
286 [ + + ][ - + ]: 927 : ASSERT(length == 0 || ! in_header);
[ - + ]
287 : :
288 : 927 : http_message->SetPlainDelivery(length);
289 : :
290 : : // If we skip HTTP data, the skipped part will appear as
291 : : // 'undelivered' data, so we do not need to adjust
292 : : // expect_data_length.
293 : 927 : }
294 : :
295 : 7984 : void HTTP_Entity::SubmitHeader(MIME_Header* h)
296 : : {
297 [ + + ]: 7984 : if ( strcasecmp_n(h->get_name(), "content-length") == 0 )
298 : : {
299 : 365 : data_chunk_t vt = h->get_value_token();
300 [ + - ]: 365 : if ( ! is_null_data_chunk(vt) )
301 : : {
302 : : int n;
303 [ + - ]: 365 : if ( atoi_n(vt.length, vt.data, 0, 10, n) )
304 : 365 : content_length = n;
305 : : else
306 : 365 : content_length = 0;
307 : : }
308 : : }
309 : :
310 [ + + ]: 7619 : else if ( strcasecmp_n(h->get_name(), "transfer-encoding") == 0 )
311 : : {
312 : 31 : data_chunk_t vt = h->get_value_token();
313 [ + - ]: 31 : if ( strcasecmp_n(vt, "chunked") == 0 )
314 : 31 : chunked_transfer_state = BEFORE_CHUNK;
315 : : }
316 : :
317 [ + + ]: 7588 : else if ( strcasecmp_n(h->get_name(), "content-encoding") == 0 )
318 : : {
319 : 111 : data_chunk_t vt = h->get_value_token();
320 [ + - ]: 111 : if ( strcasecmp_n(vt, "gzip") == 0 )
321 : 111 : encoding = GZIP;
322 [ - + ]: 111 : if ( strcasecmp_n(vt, "deflate") == 0 )
323 : 0 : encoding = DEFLATE;
324 : : }
325 : :
326 : 7984 : MIME_Entity::SubmitHeader(h);
327 : 7984 : }
328 : :
329 : 911 : void HTTP_Entity::SubmitAllHeaders()
330 : : {
331 : : // in_header should be set to false when SubmitAllHeaders() is called.
332 [ - + ]: 911 : ASSERT(! in_header);
333 : :
334 : : if ( DEBUG_http )
335 : : DEBUG_MSG("%.6f end of headers\n", network_time);
336 : :
337 : : // The presence of a message-body in a request is signaled by
338 : : // the inclusion of a Content-Length or Transfer-Encoding
339 : : // header field in the request's message-headers.
340 [ + + ]: 911 : if ( chunked_transfer_state == EXPECT_CHUNK_TRAILER )
341 : : {
342 : 30 : http_message->SubmitTrailingHeaders(headers);
343 : 30 : chunked_transfer_state = EXPECT_NOTHING;
344 : 30 : EndOfData();
345 : 30 : return;
346 : : }
347 : :
348 : 881 : MIME_Entity::SubmitAllHeaders();
349 : :
350 [ + + ]: 881 : if ( expect_body == HTTP_BODY_NOT_EXPECTED )
351 : : {
352 : 59 : EndOfData();
353 : 59 : return;
354 : : }
355 : :
356 [ + + ][ - + ]: 824 : if ( content_type == CONTENT_TYPE_MULTIPART ||
357 : : content_type == CONTENT_TYPE_MESSAGE )
358 : : {
359 : : // Do nothing.
360 : : // Make sure that we check for multiple/message contents first,
361 : : // because we do not have to turn on .
362 [ - + ]: 2 : if ( chunked_transfer_state != NON_CHUNKED_TRANSFER )
363 : : {
364 : : http_message->Weird(
365 : 0 : "HTTP_chunked_transfer_for_multipart_message");
366 : : }
367 : : }
368 : :
369 [ + + ]: 820 : else if ( chunked_transfer_state != NON_CHUNKED_TRANSFER )
370 : 31 : chunked_transfer_state = EXPECT_CHUNK_SIZE;
371 : :
372 [ + + ]: 789 : else if ( content_length >= 0 )
373 : : {
374 [ + + ]: 361 : if ( content_length > 0 )
375 : : {
376 : 349 : expect_data_length = content_length;
377 : 349 : SetPlainDelivery(content_length);
378 : : }
379 : : else
380 : 361 : EndOfData(); // handle the case that content-length = 0
381 : : }
382 : :
383 : : // Turn plain delivery on permanently for compressed bodies without
384 : : // content-length headers or if connection is to be closed afterwards
385 : : // anyway.
386 [ + + ][ + - ]: 428 : else if ( http_message->MyHTTP_Analyzer()->IsConnectionClose ()
[ - + ][ + + ]
387 : : #ifdef HAVE_LIBZ
388 : : || encoding == GZIP || encoding == DEFLATE
389 : : #endif
390 : : )
391 : : {
392 : : // FIXME: Using INT_MAX is kind of a hack here. Better
393 : : // would be to make -1 as special value interpreted as
394 : : // "until the end of the connection".
395 : 10 : expect_data_length = INT_MAX;
396 : 10 : SetPlainDelivery(INT_MAX);
397 : : }
398 : :
399 : : else
400 : : {
401 [ + - ]: 418 : if ( expect_body != HTTP_BODY_EXPECTED )
402 : : // there is no body
403 : 911 : EndOfData();
404 : : }
405 : : }
406 : :
407 : : HTTP_Message::HTTP_Message(HTTP_Analyzer* arg_analyzer,
408 : : ContentLine_Analyzer* arg_cl, bool arg_is_orig,
409 : 881 : int expect_body, int init_header_length)
410 : 881 : : MIME_Message (arg_analyzer)
411 : : {
412 : 881 : analyzer = arg_analyzer;
413 : 881 : content_line = arg_cl;
414 : 881 : is_orig = arg_is_orig;
415 : :
416 : 881 : current_entity = 0;
417 : 881 : top_level = new HTTP_Entity(this, 0, expect_body);
418 : 881 : BeginEntity(top_level);
419 : :
420 : 881 : data_buffer = 0;
421 : 881 : total_buffer_size = 0;
422 : :
423 : 881 : start_time = network_time;
424 : 881 : body_length = 0;
425 : 881 : content_gap_length = 0;
426 : 881 : header_length = init_header_length;
427 : 881 : }
428 : :
429 : 881 : HTTP_Message::~HTTP_Message()
430 : : {
431 [ + - ][ # # ]: 881 : delete top_level;
[ # # ]
432 [ + - ][ # # ]: 881 : }
[ # # ]
433 : :
434 : 881 : Val* HTTP_Message::BuildMessageStat(const int interrupted, const char* msg)
435 : : {
436 : 881 : RecordVal* stat = new RecordVal(http_message_stat);
437 : 881 : int field = 0;
438 : 881 : stat->Assign(field++, new Val(start_time, TYPE_TIME));
439 : 881 : stat->Assign(field++, new Val(interrupted, TYPE_BOOL));
440 : 881 : stat->Assign(field++, new StringVal(msg));
441 : 881 : stat->Assign(field++, new Val(body_length, TYPE_COUNT));
442 : 881 : stat->Assign(field++, new Val(content_gap_length, TYPE_COUNT));
443 : 881 : stat->Assign(field++, new Val(header_length, TYPE_COUNT));
444 : 881 : return stat;
445 : : }
446 : :
447 : 1762 : void HTTP_Message::Done(const int interrupted, const char* detail)
448 : : {
449 [ + + ]: 1762 : if ( finished )
450 : 881 : return;
451 : :
452 : 881 : MIME_Message::Done();
453 : :
454 : : // DEBUG_MSG("%.6f HTTP message done.\n", network_time);
455 : 881 : top_level->EndOfData();
456 : :
457 [ + - ]: 881 : if ( http_message_done )
458 : : {
459 : 881 : val_list* vl = new val_list;
460 : 881 : vl->append(analyzer->BuildConnVal());
461 : 881 : vl->append(new Val(is_orig, TYPE_BOOL));
462 : 881 : vl->append(BuildMessageStat(interrupted, detail));
463 : 881 : GetAnalyzer()->ConnectionEvent(http_message_done, vl);
464 : : }
465 : :
466 : 881 : MyHTTP_Analyzer()->HTTP_MessageDone(is_orig, this);
467 : :
468 : 881 : delete_strings(buffers);
469 : :
470 [ - + ]: 881 : if ( data_buffer )
471 : : {
472 [ # # ]: 0 : delete data_buffer;
473 : 1762 : data_buffer = 0;
474 : : }
475 : : }
476 : :
477 : 99 : int HTTP_Message::Undelivered(int len)
478 : : {
479 [ - + ]: 99 : if ( ! top_level )
480 : 0 : return 0;
481 : :
482 [ + + ]: 99 : if ( ((HTTP_Entity*) top_level)->Undelivered(len) )
483 : : {
484 : 36 : content_gap_length += len;
485 : 36 : return 1;
486 : : }
487 : :
488 : 99 : return 0;
489 : : }
490 : :
491 : 881 : void HTTP_Message::BeginEntity(MIME_Entity* entity)
492 : : {
493 : : if ( DEBUG_http )
494 : : DEBUG_MSG("%.6f: begin entity (%d)\n", network_time, is_orig);
495 : :
496 : 881 : current_entity = (HTTP_Entity*) entity;
497 : :
498 [ + - ]: 881 : if ( http_begin_entity )
499 : : {
500 : 881 : val_list* vl = new val_list();
501 : 881 : vl->append(analyzer->BuildConnVal());
502 : 881 : vl->append(new Val(is_orig, TYPE_BOOL));
503 : 881 : analyzer->ConnectionEvent(http_begin_entity, vl);
504 : : }
505 : 881 : }
506 : :
507 : 881 : void HTTP_Message::EndEntity(MIME_Entity* entity)
508 : : {
509 : : if ( DEBUG_http )
510 : : DEBUG_MSG("%.6f: end entity (%d)\n", network_time, is_orig);
511 : :
512 : 881 : body_length += ((HTTP_Entity*) entity)->BodyLength();
513 : 881 : header_length += ((HTTP_Entity*) entity)->HeaderLength();
514 : :
515 : 881 : DeliverEntityData();
516 : :
517 [ + - ]: 881 : if ( http_end_entity )
518 : : {
519 : 881 : val_list* vl = new val_list();
520 : 881 : vl->append(analyzer->BuildConnVal());
521 : 881 : vl->append(new Val(is_orig, TYPE_BOOL));
522 : 881 : analyzer->ConnectionEvent(http_end_entity, vl);
523 : : }
524 : :
525 : 881 : current_entity = (HTTP_Entity*) entity->Parent();
526 : :
527 : : // It is necessary to call Done when EndEntity is triggered by
528 : : // SubmitAllHeaders (through EndOfData).
529 [ + - ]: 881 : if ( entity == top_level )
530 : 881 : Done();
531 : 881 : }
532 : :
533 : 7984 : void HTTP_Message::SubmitHeader(MIME_Header* h)
534 : : {
535 : 7984 : MyHTTP_Analyzer()->HTTP_Header(is_orig, h);
536 : 7984 : }
537 : :
538 : 881 : void HTTP_Message::SubmitAllHeaders(MIME_HeaderList& hlist)
539 : : {
540 [ - + ]: 881 : if ( http_all_headers )
541 : : {
542 : 0 : val_list* vl = new val_list();
543 : 0 : vl->append(analyzer->BuildConnVal());
544 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
545 : 0 : vl->append(BuildHeaderTable(hlist));
546 : 0 : analyzer->ConnectionEvent(http_all_headers, vl);
547 : : }
548 : :
549 [ - + ]: 881 : if ( http_content_type )
550 : : {
551 : 0 : StringVal* ty = current_entity->ContentType();
552 : 0 : StringVal* subty = current_entity->ContentSubType();
553 : 0 : ty->Ref();
554 : 0 : subty->Ref();
555 : :
556 : 0 : val_list* vl = new val_list();
557 : 0 : vl->append(analyzer->BuildConnVal());
558 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
559 : 0 : vl->append(ty);
560 : 0 : vl->append(subty);
561 : 0 : analyzer->ConnectionEvent(http_content_type, vl);
562 : : }
563 : 881 : }
564 : :
565 : 30 : void HTTP_Message::SubmitTrailingHeaders(MIME_HeaderList& /* hlist */)
566 : : {
567 : : // Do nothing for now.
568 : 30 : }
569 : :
570 : 0 : void HTTP_Message::SubmitData(int len, const char* buf)
571 : : {
572 [ # # ][ # # ]: 0 : if ( buf != (const char*) data_buffer->Bytes() + buffer_offset ||
[ # # ]
573 : : buffer_offset + len > buffer_size )
574 : 0 : internal_error("buffer misalignment");
575 : :
576 : 0 : buffer_offset += len;
577 [ # # ]: 0 : if ( buffer_offset >= buffer_size )
578 : : {
579 : 0 : buffers.push_back(data_buffer);
580 : 0 : data_buffer = 0;
581 : : }
582 : 0 : }
583 : :
584 : 0 : int HTTP_Message::RequestBuffer(int* plen, char** pbuf)
585 : : {
586 [ # # ]: 0 : if ( ! http_entity_data )
587 : 0 : return 0;
588 : :
589 [ # # ]: 0 : if ( ! data_buffer )
590 [ # # ]: 0 : if ( ! InitBuffer(mime_segment_length) )
591 : 0 : return 0;
592 : :
593 : 0 : *plen = data_buffer->Len() - buffer_offset;
594 : 0 : *pbuf = (char*) data_buffer->Bytes() + buffer_offset;
595 : :
596 : 0 : return 1;
597 : : }
598 : :
599 : 0 : void HTTP_Message::SubmitAllData()
600 : : {
601 : : // This marks the end of message
602 : 0 : }
603 : :
604 : 115 : void HTTP_Message::SubmitEvent(int event_type, const char* detail)
605 : : {
606 : 115 : const char* category = "";
607 : :
608 [ + - + - ]: 115 : switch ( event_type ) {
609 : : case MIME_EVENT_ILLEGAL_FORMAT:
610 : 16 : category = "illegal format";
611 : 16 : break;
612 : :
613 : : case MIME_EVENT_ILLEGAL_ENCODING:
614 : 0 : category = "illegal encoding";
615 : 0 : break;
616 : :
617 : : case MIME_EVENT_CONTENT_GAP:
618 : 99 : category = "content gap";
619 : 99 : break;
620 : :
621 : : default:
622 : 0 : internal_error("unrecognized HTTP message event");
623 : : }
624 : :
625 : 115 : MyHTTP_Analyzer()->HTTP_Event(category, detail);
626 : 115 : }
627 : :
628 : 927 : void HTTP_Message::SetPlainDelivery(int length)
629 : : {
630 : 927 : content_line->SetPlainDelivery(length);
631 : :
632 [ + + - + ]: 927 : if ( length > 0 && skip_http_data )
633 : 0 : content_line->SkipBytesAfterThisLine(length);
634 : :
635 [ + + ]: 927 : if ( ! data_buffer )
636 : 391 : InitBuffer(length);
637 : 927 : }
638 : :
639 : 0 : void HTTP_Message::SkipEntityData()
640 : : {
641 [ # # ]: 0 : if ( current_entity )
642 : 0 : current_entity->SkipBody();
643 : 0 : }
644 : :
645 : 881 : void HTTP_Message::DeliverEntityData()
646 : : {
647 [ - + ]: 881 : if ( http_entity_data )
648 : : {
649 : 0 : const BroString* entity_data = 0;
650 : :
651 [ # # ][ # # ]: 0 : if ( data_buffer && buffer_offset > 0 )
652 : : {
653 [ # # ]: 0 : if ( buffer_offset < buffer_size )
654 : : {
655 : 0 : entity_data = new BroString(data_buffer->Bytes(), buffer_offset, 0);
656 [ # # ]: 0 : delete data_buffer;
657 : : }
658 : : else
659 : 0 : entity_data = data_buffer;
660 : :
661 : 0 : data_buffer = 0;
662 : :
663 [ # # ]: 0 : if ( buffers.empty() )
664 : : MyHTTP_Analyzer()->HTTP_EntityData(is_orig,
665 : 0 : entity_data);
666 : : else
667 : 0 : buffers.push_back(entity_data);
668 : :
669 : 0 : entity_data = 0;
670 : : }
671 : :
672 [ # # ]: 0 : if ( ! buffers.empty() )
673 : : {
674 [ # # ]: 0 : if ( buffers.size() == 1 )
675 : : {
676 : 0 : entity_data = buffers[0];
677 : 0 : buffers.clear();
678 : : }
679 : : else
680 : : {
681 : 0 : entity_data = concatenate(buffers);
682 : 0 : delete_strings(buffers);
683 : : }
684 : :
685 : 0 : MyHTTP_Analyzer()->HTTP_EntityData(is_orig, entity_data);
686 : : }
687 : : }
688 : : else
689 : : {
690 : 881 : delete_strings(buffers);
691 : :
692 [ + + ]: 881 : if ( data_buffer )
693 [ + - ]: 390 : delete data_buffer;
694 : :
695 : 881 : data_buffer = 0;
696 : : }
697 : :
698 : 881 : total_buffer_size = 0;
699 : 881 : }
700 : :
701 : 391 : int HTTP_Message::InitBuffer(int length)
702 : : {
703 [ - + ]: 391 : if ( length <= 0 )
704 : 0 : return 0;
705 : :
706 [ - + ]: 391 : if ( total_buffer_size >= http_entity_data_delivery_size )
707 : 0 : DeliverEntityData();
708 : :
709 [ + + ]: 391 : if ( total_buffer_size + length > http_entity_data_delivery_size )
710 : : {
711 : 223 : length = http_entity_data_delivery_size - total_buffer_size;
712 [ - + ]: 223 : if ( length <= 0 )
713 : 0 : return 0;
714 : : }
715 : :
716 : 391 : u_char* b = new u_char[length];
717 : 782 : data_buffer = new BroString(0, b, length);
718 : :
719 : 391 : buffer_size = length;
720 : 391 : total_buffer_size += length;
721 : 391 : buffer_offset = 0;
722 : :
723 : 391 : return 1;
724 : : }
725 : :
726 : 0 : void HTTP_Message::Weird(const char* msg)
727 : : {
728 : 0 : analyzer->Weird(msg);
729 : 0 : }
730 : :
731 : 684 : HTTP_Analyzer::HTTP_Analyzer(Connection* conn)
732 : 684 : : TCP_ApplicationAnalyzer(AnalyzerTag::HTTP, conn)
733 : : {
734 : 684 : num_requests = num_replies = 0;
735 : 684 : num_request_lines = num_reply_lines = 0;
736 : 684 : request_version = reply_version = 0.0; // unknown version
737 : 684 : keep_alive = 0;
738 : 684 : connection_close = 0;
739 : :
740 : 684 : request_message = reply_message = 0;
741 : 684 : request_state = EXPECT_REQUEST_LINE;
742 : 684 : reply_state = EXPECT_REPLY_LINE;
743 : :
744 : 684 : request_ongoing = 0;
745 : 684 : request_method = request_URI = 0;
746 : 684 : unescaped_URI = 0;
747 : :
748 : 684 : reply_ongoing = 0;
749 : 684 : reply_code = 0;
750 : 684 : reply_reason_phrase = 0;
751 : :
752 : 684 : content_line_orig = new ContentLine_Analyzer(conn, true);
753 : 684 : AddSupportAnalyzer(content_line_orig);
754 : :
755 : 684 : content_line_resp = new ContentLine_Analyzer(conn, false);
756 : 684 : content_line_resp->SetSkipPartial(true);
757 : 684 : AddSupportAnalyzer(content_line_resp);
758 : 684 : }
759 : :
760 : 684 : HTTP_Analyzer::~HTTP_Analyzer()
761 : : {
762 : 684 : Unref(request_method);
763 : 684 : Unref(request_URI);
764 : 684 : Unref(unescaped_URI);
765 : 684 : Unref(reply_reason_phrase);
766 [ + - ][ # # ]: 684 : }
[ # # ]
767 : :
768 : 684 : void HTTP_Analyzer::Done()
769 : : {
770 [ - + ]: 684 : if ( IsFinished() )
771 : 0 : return;
772 : :
773 : 684 : TCP_ApplicationAnalyzer::Done();
774 : :
775 : 684 : RequestMade(1, "message interrupted when connection done");
776 : 684 : ReplyMade(1, "message interrupted when connection done");
777 : :
778 [ + + ]: 684 : delete request_message;
779 : 684 : request_message = 0;
780 : :
781 [ + + ]: 684 : delete reply_message;
782 : 684 : reply_message = 0;
783 : :
784 : 684 : GenStats();
785 : :
786 [ + + ]: 732 : while ( ! unanswered_requests.empty() )
787 : : {
788 : 48 : Unref(unanswered_requests.front());
789 : 48 : unanswered_requests.pop();
790 : : }
791 : : }
792 : :
793 : 13485 : void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
794 : : {
795 : 13485 : TCP_ApplicationAnalyzer::DeliverStream(len, data, is_orig);
796 : :
797 [ + - + + ]: 13485 : if ( TCP() && TCP()->IsPartial() )
[ + + ]
798 : 1327 : return;
799 : :
800 : 12158 : const char* line = reinterpret_cast<const char*>(data);
801 : 12158 : const char* end_of_line = line + len;
802 : :
803 : : ContentLine_Analyzer* content_line =
804 [ + + ]: 12158 : is_orig ? content_line_orig : content_line_resp;
805 : :
806 [ + + ]: 12158 : if ( content_line->IsPlainDelivery() )
807 : : {
808 [ + + ]: 2121 : if ( is_orig )
809 : : {
810 [ + - ]: 69 : if ( request_message )
811 : 69 : request_message->Deliver(len, line, 0);
812 : : else
813 : 69 : Weird("unexpected_client_HTTP_data");
814 : : }
815 : : else
816 : : {
817 [ + - ]: 2052 : if ( reply_message )
818 : 2052 : reply_message->Deliver(len, line, 0);
819 : : else
820 : 0 : Weird("unexpected_server_HTTP_data");
821 : : }
822 : 2121 : return;
823 : : }
824 : :
825 : : // HTTP_Event("HTTP line", new_string_val(length, line));
826 : :
827 [ + + ]: 10037 : if ( is_orig )
828 : : {
829 : 4989 : ++num_request_lines;
830 : :
831 [ + + - ]: 4989 : switch ( request_state ) {
832 : : case EXPECT_REQUEST_LINE:
833 [ + - ]: 437 : if ( HTTP_RequestLine(line, end_of_line) )
834 : : {
835 : 437 : ++num_requests;
836 : :
837 [ - + ][ # # ]: 437 : if ( ! keep_alive && num_requests > 1 )
838 : 0 : Weird("unexpected_multiple_HTTP_requests");
839 : :
840 : 437 : request_state = EXPECT_REQUEST_MESSAGE;
841 : 437 : request_ongoing = 1;
842 : 437 : unanswered_requests.push(request_method->Ref());
843 : 437 : HTTP_Request();
844 : : InitHTTPMessage(content_line, request_message,
845 : 437 : is_orig, HTTP_BODY_MAYBE, len);
846 : : }
847 : :
848 : : else
849 : : {
850 [ # # ]: 0 : if ( ! RequestExpected() )
851 : : HTTP_Event("crud_trailing_HTTP_request",
852 : 0 : new_string_val(line, end_of_line));
853 : : else
854 : 0 : ProtocolViolation("not a http request line");
855 : : }
856 : 437 : break;
857 : :
858 : : case EXPECT_REQUEST_MESSAGE:
859 : 4989 : request_message->Deliver(len, line, 1);
860 : : break;
861 : :
862 : : case EXPECT_REQUEST_TRAILER:
863 : : break;
864 : : }
865 : : }
866 : : else
867 : : { // HTTP reply
868 [ + + - ]: 5048 : switch ( reply_state ) {
869 : : case EXPECT_REPLY_LINE:
870 [ + - ]: 444 : if ( HTTP_ReplyLine(line, end_of_line) )
871 : : {
872 : 444 : ++num_replies;
873 : :
874 [ + + ]: 444 : if ( unanswered_requests.empty() )
875 : 55 : Weird("unmatched_HTTP_reply");
876 : :
877 : 444 : reply_state = EXPECT_REPLY_MESSAGE;
878 : 444 : reply_ongoing = 1;
879 : :
880 : 444 : HTTP_Reply();
881 : :
882 : : InitHTTPMessage(content_line,
883 : : reply_message, is_orig,
884 : : ExpectReplyMessageBody(),
885 : 444 : len);
886 : : }
887 : : else
888 : 0 : ProtocolViolation("not a http reply line");
889 : :
890 : 444 : break;
891 : :
892 : : case EXPECT_REPLY_MESSAGE:
893 : 13485 : reply_message->Deliver(len, line, 1);
894 : : break;
895 : :
896 : : case EXPECT_REPLY_TRAILER:
897 : : break;
898 : : }
899 : : }
900 : : }
901 : :
902 : 338 : void HTTP_Analyzer::Undelivered(int seq, int len, bool is_orig)
903 : : {
904 : 338 : TCP_ApplicationAnalyzer::Undelivered(seq, len, is_orig);
905 : :
906 : : // DEBUG_MSG("Undelivered from %d: %d bytes\n", seq, length);
907 : :
908 : : HTTP_Message* msg =
909 [ + + ]: 338 : is_orig ? request_message : reply_message;
910 : :
911 : : ContentLine_Analyzer* content_line =
912 [ + + ]: 338 : is_orig ? content_line_orig : content_line_resp;
913 : :
914 [ + - ]: 338 : if ( ! content_line->IsSkippedContents(seq, len) )
915 : : {
916 [ + + ]: 338 : if ( msg )
917 : : msg->SubmitEvent(MIME_EVENT_CONTENT_GAP,
918 : 99 : fmt("seq=%d, len=%d", seq, len));
919 : : }
920 : :
921 : : // Check if the content gap falls completely within a message body
922 [ + + ][ + + ]: 338 : if ( msg && msg->Undelivered(len) )
[ + + ]
923 : : // If so, we are safe to skip the content and go on parsing
924 : 36 : return;
925 : :
926 : : // Otherwise stop parsing the connection
927 [ + + ]: 302 : if ( is_orig )
928 : : {
929 : : // Stop parsing reply messages too, because whether a
930 : : // reply contains a body may depend on knowing the
931 : : // request method
932 : :
933 : 198 : RequestMade(1, "message interrupted by a content gap");
934 : 198 : ReplyMade(1, "message interrupted by a content gap");
935 : :
936 : 198 : content_line->SetSkipDeliveries(1);
937 : 198 : content_line->SetSkipDeliveries(1);
938 : : }
939 : : else
940 : : {
941 : 104 : ReplyMade(1, "message interrupted by a content gap");
942 : 338 : content_line->SetSkipDeliveries(1);
943 : : }
944 : : }
945 : :
946 : 706 : void HTTP_Analyzer::EndpointEOF(bool is_orig)
947 : : {
948 : 706 : TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
949 : :
950 : : // DEBUG_MSG("%.6f eof\n", network_time);
951 : :
952 [ + + ]: 706 : if ( is_orig )
953 : 284 : RequestMade(0, "message ends as connection contents are completely delivered");
954 : : else
955 : 422 : ReplyMade(0, "message ends as connection contents are completely delivered");
956 : 706 : }
957 : :
958 : 268 : void HTTP_Analyzer::ConnectionFinished(int half_finished)
959 : : {
960 : 268 : TCP_ApplicationAnalyzer::ConnectionFinished(half_finished);
961 : :
962 : : // DEBUG_MSG("%.6f connection finished\n", network_time);
963 : 268 : RequestMade(1, "message ends as connection is finished");
964 : 268 : ReplyMade(1, "message ends as connection is finished");
965 : 268 : }
966 : :
967 : 41 : void HTTP_Analyzer::ConnectionReset()
968 : : {
969 : 41 : TCP_ApplicationAnalyzer::ConnectionReset();
970 : :
971 : 41 : RequestMade(1, "message interrupted by RST");
972 : 41 : ReplyMade(1, "message interrupted by RST");
973 : 41 : }
974 : :
975 : 128 : void HTTP_Analyzer::PacketWithRST()
976 : : {
977 : 128 : TCP_ApplicationAnalyzer::PacketWithRST();
978 : :
979 : 128 : RequestMade(1, "message interrupted by RST");
980 : 128 : ReplyMade(1, "message interrupted by RST");
981 : 128 : }
982 : :
983 : 684 : void HTTP_Analyzer::GenStats()
984 : : {
985 [ - + ]: 684 : if ( http_stats )
986 : : {
987 : 0 : RecordVal* r = new RecordVal(http_stats_rec);
988 : 0 : r->Assign(0, new Val(num_requests, TYPE_COUNT));
989 : 0 : r->Assign(1, new Val(num_replies, TYPE_COUNT));
990 : 0 : r->Assign(2, new Val(request_version, TYPE_DOUBLE));
991 : 0 : r->Assign(3, new Val(reply_version, TYPE_DOUBLE));
992 : :
993 : 0 : val_list* vl = new val_list;
994 : 0 : vl->append(BuildConnVal());
995 : 0 : vl->append(r);
996 : :
997 : : // DEBUG_MSG("%.6f http_stats\n", network_time);
998 : 0 : ConnectionEvent(http_stats, vl);
999 : : }
1000 : 684 : }
1001 : :
1002 : : const char* HTTP_Analyzer::PrefixMatch(const char* line,
1003 : 1914 : const char* end_of_line, const char* prefix)
1004 : : {
1005 [ + + ][ + - ]: 7650 : while ( *prefix && line < end_of_line && *prefix == *line )
[ + + ]
1006 : : {
1007 : 5736 : ++prefix;
1008 : 5736 : ++line;
1009 : : }
1010 : :
1011 [ + + ]: 1914 : if ( *prefix )
1012 : : // It didn't match.
1013 : 596 : return 0;
1014 : :
1015 : 1914 : return line;
1016 : : }
1017 : :
1018 : : const char* HTTP_Analyzer::PrefixWordMatch(const char* line,
1019 : 456 : const char* end_of_line, const char* prefix)
1020 : : {
1021 [ + + ]: 456 : if ( (line = PrefixMatch(line, end_of_line, prefix)) == 0 )
1022 : 19 : return 0;
1023 : :
1024 : 437 : const char* orig_line = line;
1025 : 437 : line = skip_whitespace(line, end_of_line);
1026 : :
1027 [ - + ]: 437 : if ( line == orig_line )
1028 : : // Word didn't end at prefix.
1029 : 0 : return 0;
1030 : :
1031 : 456 : return line;
1032 : : }
1033 : :
1034 : 437 : int HTTP_Analyzer::HTTP_RequestLine(const char* line, const char* end_of_line)
1035 : : {
1036 : 437 : const char* rest = 0;
1037 : : static const char* http_methods[] = {
1038 : : "GET", "POST", "HEAD",
1039 : :
1040 : : "OPTIONS", "PUT", "DELETE", "TRACE", "CONNECT",
1041 : :
1042 : : // HTTP methods for distributed authoring.
1043 : : "PROPFIND", "PROPPATCH", "MKCOL", "DELETE", "PUT",
1044 : : "COPY", "MOVE", "LOCK", "UNLOCK",
1045 : :
1046 : : "SEARCH",
1047 : :
1048 : : 0,
1049 : : };
1050 : :
1051 : : int i;
1052 [ + - ]: 456 : for ( i = 0; http_methods[i]; ++i )
1053 [ + + ]: 456 : if ( (rest = PrefixWordMatch(line, end_of_line, http_methods[i])) != 0 )
1054 : 437 : break;
1055 : :
1056 [ - + ]: 437 : if ( ! http_methods[i] )
1057 : : {
1058 : : // Weird("HTTP_unknown_method");
1059 [ # # ]: 0 : if ( RequestExpected() )
1060 : 0 : HTTP_Event("unknown_HTTP_method", new_string_val(line, end_of_line));
1061 : 0 : return 0;
1062 : : }
1063 : :
1064 : 437 : request_method = new StringVal(http_methods[i]);
1065 : :
1066 [ - + ]: 437 : if ( ! ParseRequest(rest, end_of_line) )
1067 : 0 : internal_error("HTTP ParseRequest failed");
1068 : :
1069 : : Conn()->Match(Rule::HTTP_REQUEST,
1070 : : (const u_char*) unescaped_URI->AsString()->Bytes(),
1071 : 437 : unescaped_URI->AsString()->Len(), true, true, true, true);
1072 : :
1073 : 437 : return 1;
1074 : : }
1075 : :
1076 : 437 : int HTTP_Analyzer::ParseRequest(const char* line, const char* end_of_line)
1077 : : {
1078 : : const char* end_of_uri;
1079 : : const char* version_start;
1080 : : const char* version_end;
1081 : :
1082 [ + - ]: 56308 : for ( end_of_uri = line; end_of_uri < end_of_line; ++end_of_uri )
1083 : : {
1084 [ + + ][ + + ]: 56308 : if ( ! is_reserved_URI_char(*end_of_uri) &&
[ + + ][ + + ]
1085 : : ! is_unreserved_URI_char(*end_of_uri) &&
1086 : : *end_of_uri != '%' )
1087 : 437 : break;
1088 : : }
1089 : :
1090 [ + - ]: 1014 : for ( version_start = end_of_uri; version_start < end_of_line; ++version_start )
1091 : : {
1092 : 1014 : end_of_uri = version_start;
1093 : 1014 : version_start = skip_whitespace(version_start, end_of_line);
1094 [ + + ]: 1014 : if ( PrefixMatch(version_start, end_of_line, "HTTP/") )
1095 : 437 : break;
1096 : : }
1097 : :
1098 [ - + ]: 437 : if ( version_start >= end_of_line )
1099 : : {
1100 : : // If no version is found
1101 : 0 : SetVersion(request_version, 0.9);
1102 : : }
1103 : : else
1104 : : {
1105 [ + - ]: 437 : if ( version_start + 8 <= end_of_line )
1106 : : {
1107 : 437 : version_start += 5; // "HTTP/"
1108 : : SetVersion(request_version,
1109 : : HTTP_Version(end_of_line - version_start,
1110 : 437 : version_start));
1111 : :
1112 : 437 : version_end = version_start + 3;
1113 [ - + ]: 437 : if ( skip_whitespace(version_end, end_of_line) != end_of_line )
1114 : : HTTP_Event("crud after HTTP version is ignored",
1115 : 437 : new_string_val(line, end_of_line));
1116 : : }
1117 : : else
1118 : 0 : HTTP_Event("bad_HTTP_version", new_string_val(line, end_of_line));
1119 : : }
1120 : :
1121 : : // NormalizeURI(line, end_of_uri);
1122 : :
1123 : 437 : request_URI = new StringVal(end_of_uri - line, line);
1124 : : unescaped_URI = new StringVal(unescape_URI((const u_char*) line,
1125 : 437 : (const u_char*) end_of_uri, this));
1126 : :
1127 : 437 : return 1;
1128 : : }
1129 : :
1130 : : // Only recognize [0-9][.][0-9].
1131 : 881 : double HTTP_Analyzer::HTTP_Version(int len, const char* data)
1132 : : {
1133 [ + - ][ + - ]: 881 : if ( len >= 3 &&
[ + - ][ + - ]
[ + - ][ + - ]
1134 : : data[0] >= '0' && data[0] <= '9' &&
1135 : : data[1] == '.' &&
1136 : : data[2] >= '0' && data[2] <= '9' )
1137 : : {
1138 : 881 : return double(data[0] - '0') + 0.1 * double(data[2] - '0');
1139 : : }
1140 : : else
1141 : : {
1142 : 0 : HTTP_Event("bad_HTTP_version", new_string_val(len, data));
1143 : 881 : return 0;
1144 : : }
1145 : : }
1146 : :
1147 : 881 : void HTTP_Analyzer::SetVersion(double& version, double new_version)
1148 : : {
1149 [ + + ]: 881 : if ( version == 0.0 )
1150 : 550 : version = new_version;
1151 : :
1152 [ - + ]: 331 : else if ( version != new_version )
1153 : 0 : Weird("HTTP_version_mismatch");
1154 : :
1155 [ + + ]: 881 : if ( version > 1.05 )
1156 : 875 : keep_alive = 1;
1157 : 881 : }
1158 : :
1159 : 115 : void HTTP_Analyzer::HTTP_Event(const char* category, const char* detail)
1160 : : {
1161 : 115 : HTTP_Event(category, new StringVal(detail));
1162 : 115 : }
1163 : :
1164 : 116 : void HTTP_Analyzer::HTTP_Event(const char* category, StringVal* detail)
1165 : : {
1166 [ - + ]: 116 : if ( http_event )
1167 : : {
1168 : 0 : val_list* vl = new val_list();
1169 : 0 : vl->append(BuildConnVal());
1170 : 0 : vl->append(new StringVal(category));
1171 : 0 : vl->append(detail);
1172 : :
1173 : : // DEBUG_MSG("%.6f http_event\n", network_time);
1174 : 0 : ConnectionEvent(http_event, vl);
1175 : : }
1176 : : else
1177 [ + - ]: 116 : delete detail;
1178 : 116 : }
1179 : :
1180 : 874 : StringVal* HTTP_Analyzer::TruncateURI(StringVal* uri)
1181 : : {
1182 : 874 : const BroString* str = uri->AsString();
1183 : :
1184 [ - + # # ]: 874 : if ( truncate_http_URI >= 0 && str->Len() > truncate_http_URI )
[ - + ]
1185 : : {
1186 : 0 : u_char* s = new u_char[truncate_http_URI + 4];
1187 : 0 : memcpy(s, str->Bytes(), truncate_http_URI);
1188 : 0 : memcpy(s + truncate_http_URI, "...", 4);
1189 : 0 : return new StringVal(new BroString(1, s, truncate_http_URI+3));
1190 : : }
1191 : : else
1192 : : {
1193 : 874 : Ref(uri);
1194 : 874 : return uri;
1195 : : }
1196 : : }
1197 : :
1198 : 437 : void HTTP_Analyzer::HTTP_Request()
1199 : : {
1200 : 437 : ProtocolConfirmation();
1201 : :
1202 [ + - ]: 437 : if ( http_request )
1203 : : {
1204 : 437 : val_list* vl = new val_list;
1205 : 437 : vl->append(BuildConnVal());
1206 : :
1207 : 437 : Ref(request_method);
1208 : 437 : vl->append(request_method);
1209 : 437 : vl->append(TruncateURI(request_URI->AsStringVal()));
1210 : 437 : vl->append(TruncateURI(unescaped_URI->AsStringVal()));
1211 : :
1212 : 437 : vl->append(new StringVal(fmt("%.1f", request_version)));
1213 : : // DEBUG_MSG("%.6f http_request\n", network_time);
1214 : 437 : ConnectionEvent(http_request, vl);
1215 : : }
1216 : 437 : }
1217 : :
1218 : 444 : void HTTP_Analyzer::HTTP_Reply()
1219 : : {
1220 [ + - ]: 444 : if ( http_reply )
1221 : : {
1222 : 444 : val_list* vl = new val_list;
1223 : 444 : vl->append(BuildConnVal());
1224 : 444 : vl->append(new StringVal(fmt("%.1f", reply_version)));
1225 : 444 : vl->append(new Val(reply_code, TYPE_COUNT));
1226 [ + + ]: 444 : if ( reply_reason_phrase )
1227 : 443 : vl->append(reply_reason_phrase->Ref());
1228 : : else
1229 : 1 : vl->append(new StringVal("<empty>"));
1230 : 444 : ConnectionEvent(http_reply, vl);
1231 : : }
1232 : : else
1233 : : {
1234 : 0 : Unref(reply_reason_phrase);
1235 : 0 : reply_reason_phrase = 0;
1236 : : }
1237 : 444 : }
1238 : :
1239 : 2040 : void HTTP_Analyzer::RequestMade(const int interrupted, const char* msg)
1240 : : {
1241 [ + + ]: 2040 : if ( ! request_ongoing )
1242 : 1603 : return;
1243 : :
1244 : 437 : request_ongoing = 0;
1245 : :
1246 [ + - ]: 437 : if ( request_message )
1247 : 437 : request_message->Done(interrupted, msg);
1248 : :
1249 : : // DEBUG_MSG("%.6f request made\n", network_time);
1250 : :
1251 : 437 : Unref(request_method);
1252 : 437 : Unref(unescaped_URI);
1253 : 437 : Unref(request_URI);
1254 : :
1255 : 437 : request_method = request_URI = unescaped_URI = 0;
1256 : :
1257 : 437 : num_request_lines = 0;
1258 : :
1259 : 2040 : request_state = EXPECT_REQUEST_LINE;
1260 : : }
1261 : :
1262 : 2289 : void HTTP_Analyzer::ReplyMade(const int interrupted, const char* msg)
1263 : : {
1264 [ + + ]: 2289 : if ( ! reply_ongoing )
1265 : 1845 : return;
1266 : :
1267 : 444 : reply_ongoing = 0;
1268 : :
1269 : : // DEBUG_MSG("%.6f reply made\n", network_time);
1270 : :
1271 [ + - ]: 444 : if ( reply_message )
1272 : 444 : reply_message->Done(interrupted, msg);
1273 : :
1274 [ + + ]: 444 : if ( ! unanswered_requests.empty() )
1275 : : {
1276 : 389 : Unref(unanswered_requests.front());
1277 : 389 : unanswered_requests.pop();
1278 : : }
1279 : :
1280 : 444 : reply_code = 0;
1281 : :
1282 [ + + ]: 444 : if ( reply_reason_phrase )
1283 : : {
1284 : 443 : Unref(reply_reason_phrase);
1285 : 443 : reply_reason_phrase = 0;
1286 : : }
1287 : :
1288 : 2289 : reply_state = EXPECT_REPLY_LINE;
1289 : : }
1290 : :
1291 : 0 : void HTTP_Analyzer::RequestClash(Val* /* clash_val */)
1292 : : {
1293 : 0 : Weird("multiple_HTTP_request_elements");
1294 : :
1295 : : // Flush out old values.
1296 : 0 : RequestMade(1, "request clash");
1297 : 0 : }
1298 : :
1299 : 444 : const BroString* HTTP_Analyzer::UnansweredRequestMethod()
1300 : : {
1301 [ + + ]: 444 : return unanswered_requests.empty() ? 0 : unanswered_requests.front()->AsString();
1302 : : }
1303 : :
1304 : 444 : int HTTP_Analyzer::HTTP_ReplyLine(const char* line, const char* end_of_line)
1305 : : {
1306 : : const char* rest;
1307 : :
1308 [ - + ]: 444 : if ( ! (rest = PrefixMatch(line, end_of_line, "HTTP/")) )
1309 : : {
1310 : : // ##TODO: some server replies with an HTML document
1311 : : // without a status line and a MIME header, when the
1312 : : // request is malformed.
1313 : 0 : HTTP_Event("bad_HTTP_reply", new_string_val(line, end_of_line));
1314 : 0 : return 0;
1315 : : }
1316 : :
1317 : 444 : SetVersion(reply_version, HTTP_Version(end_of_line - rest, rest));
1318 : :
1319 [ + - ]: 1776 : for ( ; rest < end_of_line; ++rest )
1320 [ + + ]: 1776 : if ( is_lws(*rest) )
1321 : 444 : break;
1322 : :
1323 [ - + ]: 444 : if ( rest >= end_of_line )
1324 : : {
1325 : : HTTP_Event("HTTP_reply_code_missing",
1326 : 0 : new_string_val(line, end_of_line));
1327 : 0 : return 0;
1328 : : }
1329 : :
1330 : 444 : rest = skip_whitespace(rest, end_of_line);
1331 : :
1332 [ - + ]: 444 : if ( rest + 3 > end_of_line )
1333 : : {
1334 : : HTTP_Event("HTTP_reply_code_missing",
1335 : 0 : new_string_val(line, end_of_line));
1336 : 0 : return 0;
1337 : : }
1338 : :
1339 : 444 : reply_code = HTTP_ReplyCode(rest);
1340 : :
1341 [ + + ]: 444 : for ( rest += 3; rest < end_of_line; ++rest )
1342 [ + - ]: 443 : if ( is_lws(*rest) )
1343 : 443 : break;
1344 : :
1345 [ + + ]: 444 : if ( rest >= end_of_line )
1346 : : {
1347 : : HTTP_Event("HTTP_reply_reason_phrase_missing",
1348 : 1 : new_string_val(line, end_of_line));
1349 : : // Tolerate missing reason phrase?
1350 : 1 : return 1;
1351 : : }
1352 : :
1353 : 443 : rest = skip_whitespace(rest, end_of_line);
1354 : : reply_reason_phrase =
1355 : 887 : new StringVal(end_of_line - rest, (const char *) rest);
1356 : :
1357 : 443 : return 1;
1358 : : }
1359 : :
1360 : 444 : int HTTP_Analyzer::HTTP_ReplyCode(const char* code_str)
1361 : : {
1362 [ + - ][ + - ]: 444 : if ( isdigit(code_str[0]) && isdigit(code_str[1]) && isdigit(code_str[2]) )
[ + - ]
1363 : : return (code_str[0] - '0') * 100 +
1364 : : (code_str[1] - '0') * 10 +
1365 : 444 : (code_str[2] - '0');
1366 : : else
1367 : 444 : return 0;
1368 : : }
1369 : :
1370 : 444 : int HTTP_Analyzer::ExpectReplyMessageBody()
1371 : : {
1372 : : // RFC 2616:
1373 : : //
1374 : : // For response messages, whether or not a message-body is included with
1375 : : // a message is dependent on both the request method and the response
1376 : : // status code (section 6.1.1). All responses to the HEAD request method
1377 : : // MUST NOT include a message-body, even though the presence of entity-
1378 : : // header fields might lead one to believe they do. All 1xx
1379 : : // (informational), 204 (no content), and 304 (not modified) responses
1380 : : // MUST NOT include a message-body. All other responses do include a
1381 : : // message-body, although it MAY be of zero length.
1382 : :
1383 : 444 : const BroString* method = UnansweredRequestMethod();
1384 : :
1385 [ + + - + ]: 444 : if ( method && strcasecmp_n(method->Len(), (const char*) (method->Bytes()), "HEAD") == 0 )
[ - + ]
1386 : 0 : return HTTP_BODY_NOT_EXPECTED;
1387 : :
1388 [ + - ][ + - ]: 444 : if ( (reply_code >= 100 && reply_code < 200) ||
[ + + ][ + + ]
1389 : : reply_code == 204 || reply_code == 304 )
1390 : 59 : return HTTP_BODY_NOT_EXPECTED;
1391 : :
1392 : 444 : return HTTP_BODY_EXPECTED;
1393 : : }
1394 : :
1395 : 7984 : void HTTP_Analyzer::HTTP_Header(int is_orig, MIME_Header* h)
1396 : : {
1397 : : #if 0
1398 : : // ### Only call ParseVersion if we're tracking versions:
1399 : : if ( strcasecmp_n(h->get_name(), "server") == 0 )
1400 : : ParseVersion(h->get_value(),
1401 : : (is_orig ? Conn()->OrigAddr() : Conn()->RespAddr()), false);
1402 : :
1403 : : else if ( strcasecmp_n(h->get_name(), "user-agent") == 0 )
1404 : : ParseVersion(h->get_value(),
1405 : : (is_orig ? Conn()->OrigAddr() : Conn()->RespAddr()), true);
1406 : : #endif
1407 : :
1408 : : // To be "liberal", we only look at "keep-alive" on the client
1409 : : // side, and if seen assume the connection to be persistent.
1410 : : // This seems fairly safe - at worst, the client does indeed
1411 : : // send additional requests, and the server ignores them.
1412 [ + + ][ + + ]: 7984 : if ( is_orig && strcasecmp_n(h->get_name(), "connection") == 0 )
[ + + ]
1413 : : {
1414 [ + - ]: 427 : if ( strcasecmp_n(h->get_value_token(), "keep-alive") == 0 )
1415 : 427 : keep_alive = 1;
1416 : : }
1417 : :
1418 [ + + ][ + + ]: 7984 : if ( ! is_orig &&
[ + + ]
1419 : : strcasecmp_n(h->get_name(), "connection") == 0 )
1420 : : {
1421 [ + + ]: 387 : if ( strcasecmp_n(h->get_value_token(), "close") == 0 )
1422 : 93 : connection_close = 1;
1423 : : }
1424 : :
1425 [ + - ]: 7984 : if ( http_header )
1426 : : {
1427 : : Rule::PatternType rule =
1428 : : is_orig ? Rule::HTTP_REQUEST_HEADER :
1429 [ + + ]: 7984 : Rule::HTTP_REPLY_HEADER;
1430 : :
1431 : 7984 : data_chunk_t hd_name = h->get_name();
1432 : 7984 : data_chunk_t hd_value = h->get_value();
1433 : :
1434 : : Conn()->Match(rule, (const u_char*) hd_name.data, hd_name.length,
1435 : 7984 : is_orig, true, false, true);
1436 : : Conn()->Match(rule, (const u_char*) ": ", 2, is_orig,
1437 : 7984 : false, false, false);
1438 : : Conn()->Match(rule, (const u_char*) hd_value.data, hd_value.length,
1439 : 7984 : is_orig, false, true, false);
1440 : :
1441 : 7984 : val_list* vl = new val_list();
1442 : 7984 : vl->append(BuildConnVal());
1443 : 7984 : vl->append(new Val(is_orig, TYPE_BOOL));
1444 : 7984 : vl->append(new_string_val(h->get_name())->ToUpper());
1445 : 7984 : vl->append(new_string_val(h->get_value()));
1446 : : if ( DEBUG_http )
1447 : : DEBUG_MSG("%.6f http_header\n", network_time);
1448 : 7984 : ConnectionEvent(http_header, vl);
1449 : : }
1450 : 7984 : }
1451 : :
1452 : : void HTTP_Analyzer::ParseVersion(data_chunk_t ver, const uint32* host,
1453 : 0 : bool user_agent)
1454 : : {
1455 : 0 : int len = ver.length;
1456 : 0 : const char* data = ver.data;
1457 : :
1458 [ # # ]: 0 : if ( software_unparsed_version_found )
1459 : 0 : Conn()->UnparsedVersionFoundEvent(host, data, len, this);
1460 : :
1461 : : // The RFC defines:
1462 : : //
1463 : : // product = token ["/" product-version]
1464 : : // product-version = token
1465 : : // Server = "Server" ":" 1*( product | comment )
1466 : :
1467 : : int offset;
1468 : : data_chunk_t product, product_version;
1469 : 0 : int num_version = 0;
1470 : :
1471 [ # # ]: 0 : while ( len > 0 )
1472 : : {
1473 : : // Skip white space.
1474 [ # # ][ # # ]: 0 : while ( len && is_lws(*data) )
[ # # ]
1475 : : {
1476 : 0 : ++data;
1477 : 0 : --len;
1478 : : }
1479 : :
1480 : : // See if a comment is coming next. For User-Agent,
1481 : : // we parse it, too.
1482 [ # # ][ # # ]: 0 : if ( user_agent && len && *data == '(' )
[ # # ]
1483 : : {
1484 : : // Find end of comment.
1485 : 0 : const char* data_start = data;
1486 : : const char* eoc =
1487 : 0 : data + MIME_skip_lws_comments(len, data);
1488 : :
1489 : : // Split into parts.
1490 : : // (This may get confused by nested comments,
1491 : : // but we ignore this for now.)
1492 : : const char* eot;
1493 : 0 : ++data;
1494 : 0 : while ( 1 )
1495 : : {
1496 : : // Eat spaces.
1497 [ # # ][ # # ]: 0 : while ( data < eoc && is_lws(*data) )
[ # # ]
1498 : 0 : ++data;
1499 : :
1500 : : // Find end of token.
1501 [ # # ][ # # ]: 0 : for ( eot = data;
[ # # ]
1502 : : eot < eoc && *eot != ';' && *eot != ')';
1503 : : ++eot )
1504 : : ;
1505 : :
1506 [ # # ]: 0 : if ( eot == eoc )
1507 : 0 : break;
1508 : :
1509 : : // Delete spaces at end of token.
1510 [ # # ][ # # ]: 0 : for ( ; eot > data && is_lws(*(eot-1)); --eot )
[ # # ]
1511 : : ;
1512 : :
1513 [ # # ][ # # ]: 0 : if ( data != eot && software_version_found )
[ # # ]
1514 : 0 : Conn()->VersionFoundEvent(host, data, eot - data, this);
1515 : 0 : data = eot + 1;
1516 : : }
1517 : :
1518 : 0 : len -= eoc - data_start;
1519 : 0 : data = eoc;
1520 : 0 : continue;
1521 : : }
1522 : :
1523 : : offset = MIME_get_slash_token_pair(len, data,
1524 : 0 : &product, &product_version);
1525 [ # # ]: 0 : if ( offset < 0 )
1526 : : {
1527 : : // I guess version detection is best-effort,
1528 : : // so we do not complain in the final version
1529 [ # # ]: 0 : if ( num_version == 0 )
1530 : : HTTP_Event("bad_HTTP_version",
1531 : 0 : new_string_val(len, data));
1532 : :
1533 : : // Try to simply skip next token.
1534 : 0 : offset = MIME_get_token(len, data, &product);
1535 [ # # ]: 0 : if ( offset < 0 )
1536 : 0 : break;
1537 : :
1538 : 0 : len -= offset;
1539 : 0 : data += offset;
1540 : : }
1541 : :
1542 : : else
1543 : : {
1544 : 0 : len -= offset;
1545 : 0 : data += offset;
1546 : :
1547 : : int version_len =
1548 : 0 : product.length + 1 + product_version.length;
1549 : :
1550 : 0 : char* version_str = new char[version_len+1];
1551 : 0 : char* s = version_str;
1552 : :
1553 : 0 : memcpy(s, product.data, product.length);
1554 : :
1555 : 0 : s += product.length;
1556 : 0 : *(s++) = '/';
1557 : :
1558 : 0 : memcpy(s, product_version.data, product_version.length);
1559 : :
1560 : 0 : s += product_version.length;
1561 : 0 : *s = 0;
1562 : :
1563 [ # # ]: 0 : if ( software_version_found )
1564 : : Conn()->VersionFoundEvent(host, version_str,
1565 : 0 : version_len, this);
1566 : :
1567 [ # # ]: 0 : delete [] version_str;
1568 : 0 : ++num_version;
1569 : : }
1570 : : }
1571 : 0 : }
1572 : :
1573 : 0 : void HTTP_Analyzer::HTTP_EntityData(int is_orig, const BroString* entity_data)
1574 : : {
1575 [ # # ]: 0 : if ( http_entity_data )
1576 : : {
1577 : 0 : val_list* vl = new val_list();
1578 : 0 : vl->append(BuildConnVal());
1579 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
1580 : 0 : vl->append(new Val(entity_data->Len(), TYPE_COUNT));
1581 : : // FIXME: Make sure that removing the const here is indeed ok...
1582 : 0 : vl->append(new StringVal(const_cast<BroString*>(entity_data)));
1583 : 0 : ConnectionEvent(http_entity_data, vl);
1584 : : }
1585 : : else
1586 [ # # ]: 0 : delete entity_data;
1587 : 0 : }
1588 : :
1589 : : // Calls request/reply done
1590 : 881 : void HTTP_Analyzer::HTTP_MessageDone(int is_orig, HTTP_Message* /* message */)
1591 : : {
1592 [ + + ]: 881 : if ( is_orig )
1593 : 437 : RequestMade(0, "message ends normally");
1594 : : else
1595 : 444 : ReplyMade(0, "message ends normally");
1596 : 881 : }
1597 : :
1598 : : void HTTP_Analyzer::InitHTTPMessage(ContentLine_Analyzer* cl, HTTP_Message*& message,
1599 : 881 : bool is_orig, int expect_body, int init_header_length)
1600 : : {
1601 [ + + ]: 881 : if ( message )
1602 : : {
1603 [ - + ]: 331 : if ( ! message->Finished() )
1604 : 0 : Weird("HTTP_overlapping_messages");
1605 : :
1606 [ + - ]: 331 : delete message;
1607 : : }
1608 : :
1609 : : // DEBUG_MSG("%.6f init http message\n", network_time);
1610 : : message = new HTTP_Message(this, cl, is_orig, expect_body,
1611 : 881 : init_header_length);
1612 : 881 : }
1613 : :
1614 : 0 : void HTTP_Analyzer::SkipEntityData(int is_orig)
1615 : : {
1616 [ # # ]: 0 : HTTP_Message* msg = is_orig ? request_message : reply_message;
1617 : :
1618 [ # # ]: 0 : if ( msg )
1619 : 0 : msg->SkipEntityData();
1620 : 0 : }
1621 : :
1622 : 106144 : int is_reserved_URI_char(unsigned char ch)
1623 : : { // see RFC 2396 (definition of URI)
1624 : 106144 : return strchr(";/?:@&=+$,", ch) != 0;
1625 : : }
1626 : :
1627 : 99197 : int is_unreserved_URI_char(unsigned char ch)
1628 : : { // see RFC 2396 (definition of URI)
1629 [ + + ][ + + ]: 99197 : return isalnum(ch) || strchr("-_.!~*\'()", ch) != 0;
1630 : : }
1631 : :
1632 : 0 : void escape_URI_char(unsigned char ch, unsigned char*& p)
1633 : : {
1634 : 0 : *p++ = '%';
1635 : 0 : *p++ = encode_hex((ch >> 4) & 0xf);
1636 : 0 : *p++ = encode_hex(ch & 0xf);
1637 : 0 : }
1638 : :
1639 : : BroString* unescape_URI(const u_char* line, const u_char* line_end,
1640 : 437 : Analyzer* analyzer)
1641 : : {
1642 : 437 : byte_vec decoded_URI = new u_char[line_end - line + 1];
1643 : 437 : byte_vec URI_p = decoded_URI;
1644 : :
1645 : : // An 'unescaped_special_char' here means a character that *should*
1646 : : // be escaped, but isn't in the URI. A control characters that
1647 : : // appears directly in the URI would be an example. The RFC implies
1648 : : // that if we do not unescape the URI that we see in the trace, every
1649 : : // character should be a printable one -- either reserved or unreserved
1650 : : // (or '%').
1651 : : //
1652 : : // Counting the number of unescaped characters and generating a weird
1653 : : // event on URI's with unescaped characters (which are rare) will
1654 : : // let us locate strange-looking URI's in the trace -- those URI's
1655 : : // are often interesting.
1656 : 437 : int unescaped_special_char = 0;
1657 : :
1658 [ + + ]: 52477 : while ( line < line_end )
1659 : : {
1660 [ + + ]: 52040 : if ( *line == '%' )
1661 : : {
1662 : 2204 : ++line;
1663 : :
1664 [ - + ]: 2204 : if ( line == line_end )
1665 : : {
1666 : : // How to deal with % at end of line?
1667 : : // *URI_p++ = '%';
1668 [ # # ]: 0 : if ( analyzer )
1669 : 0 : analyzer->Weird("illegal_%_at_end_of_URI");
1670 : 0 : break;
1671 : : }
1672 : :
1673 [ - + ]: 2204 : else if ( *line == '%' )
1674 : : {
1675 : : // Double '%' might be either due to
1676 : : // software bug, or more likely, an
1677 : : // evasion (e.g. used by Nimda).
1678 : : // *URI_p++ = '%';
1679 [ # # ]: 0 : if ( analyzer )
1680 : 0 : analyzer->Weird("double_%_in_URI");
1681 : 0 : --line; // ignore the first '%'
1682 : : }
1683 : :
1684 [ + - ][ + - ]: 4408 : else if ( isxdigit(line[0]) && isxdigit(line[1]) )
1685 : : {
1686 : : *URI_p++ = (decode_hex(line[0]) << 4) +
1687 : 2204 : decode_hex(line[1]);
1688 : 2204 : ++line; // place line at the last hex digit
1689 : : }
1690 : :
1691 : : else
1692 : : {
1693 [ # # ]: 0 : if ( analyzer )
1694 : 0 : analyzer->Weird("unescaped_%_in_URI");
1695 : 0 : *URI_p++ = '%'; // put back initial '%'
1696 : 2204 : *URI_p++ = *line; // take char w/o interp.
1697 : : }
1698 : : }
1699 : :
1700 : : else
1701 : : {
1702 [ + + ][ + + ]: 49836 : if ( ! is_reserved_URI_char(*line) &&
[ + + ]
1703 : : ! is_unreserved_URI_char(*line) )
1704 : : // Count these up as a way to compress
1705 : : // the corresponding Weird event to a
1706 : : // single instance.
1707 : 15 : ++unescaped_special_char;
1708 : 49836 : *URI_p++ = *line;
1709 : : }
1710 : :
1711 : 52040 : ++line;
1712 : : }
1713 : :
1714 : 437 : URI_p[0] = 0;
1715 : :
1716 [ + + ][ + - ]: 437 : if ( unescaped_special_char && analyzer )
1717 : 6 : analyzer->Weird("unescaped_special_URI_char");
1718 : :
1719 : 437 : return new BroString(1, decoded_URI, URI_p - decoded_URI);
1720 : : }
1721 : :
1722 : : #include "http-rw.bif.func_def"
|