/[jscoverage]/trunk/http-message.c
ViewVC logotype

Contents of /trunk/http-message.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 123 - (show annotations)
Sun Jun 1 14:19:21 2008 UTC (11 years, 2 months ago) by siliconforks
File MIME type: text/plain
File size: 20103 byte(s)
Remove unused #include.

1 /*
2 http-message.c - HTTP message object
3 Copyright (C) 2008 siliconforks.com
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <config.h>
21
22 #include "http-server.h"
23
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include "stream.h"
29 #include "util.h"
30
31 enum ChunkedBodyState {
32 CHUNKED_BODY_CHUNK_SIZE, CHUNKED_BODY_CHUNK_DATA, CHUNKED_BODY_TRAILER, CHUNKED_BODY_DONE
33 };
34
35 struct HTTPMessage {
36 char * start_line;
37 HTTPHeader * headers;
38
39 /* used for sending and receiving */
40 struct HTTPConnection * connection;
41
42 /* used only for receiving */
43 bool has_content_length;
44 bool is_chunked;
45 size_t bytes_remaining;
46 enum ChunkedBodyState chunked_body_state;
47 Stream * chunk_buffer;
48
49 /* used only for sending */
50 bool is_started;
51 };
52
53 HTTPMessage * HTTPMessage_new(HTTPConnection * connection) {
54 HTTPMessage * message = xmalloc(sizeof(HTTPMessage));
55 message->start_line = NULL;
56 message->headers = NULL;
57 message->connection = connection;
58
59 message->has_content_length = false;
60 message->is_chunked = false;
61 message->bytes_remaining = 0;
62 message->chunked_body_state = CHUNKED_BODY_CHUNK_SIZE;
63 message->chunk_buffer = NULL;
64
65 message->is_started = false;
66 return message;
67 }
68
69 void HTTPMessage_delete(HTTPMessage * message) {
70 free(message->start_line);
71
72 HTTPHeader * h = message->headers;
73 while (h != NULL) {
74 HTTPHeader * doomed = h;
75 h = h->next;
76 free(doomed->name);
77 free(doomed->value);
78 free(doomed);
79 }
80
81 if (message->chunk_buffer != NULL) {
82 Stream_delete(message->chunk_buffer);
83 }
84
85 free(message);
86 }
87
88 HTTPConnection * HTTPMessage_get_connection(const HTTPMessage * message) {
89 return message->connection;
90 }
91
92 void HTTPMessage_add_header(HTTPMessage * message, const char * name, const char * value) {
93 HTTPHeader * last = NULL;
94 for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
95 if (strcmp(h->name, name) == 0) {
96 char * new_value;
97 xasprintf(&new_value, "%s, %s", h->value, value);
98 free(h->value);
99 h->value = new_value;
100 return;
101 }
102 last = h;
103 }
104
105 HTTPHeader * header = xmalloc(sizeof(HTTPHeader));
106 header->name = xstrdup(name);
107 header->value = xstrdup(value);
108 header->next = NULL;
109 if (last == NULL) {
110 message->headers = header;
111 }
112 else {
113 last->next = header;
114 }
115 }
116
117 void HTTPMessage_set_header(HTTPMessage * message, const char * name, const char * value) {
118 for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
119 if (strcmp(name, h->name) == 0) {
120 free(h->value);
121 h->value = xstrdup(value);
122 return;
123 }
124 }
125 HTTPMessage_add_header(message, name, value);
126 }
127
128 void HTTPMessage_set_content_length(HTTPMessage * message, size_t value) {
129 char * s;
130 xasprintf(&s, "%u", value);
131 HTTPMessage_set_header(message, HTTP_CONTENT_LENGTH, s);
132 free(s);
133 }
134
135 const char * HTTPMessage_find_header(const HTTPMessage * message, const char * name) {
136 for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
137 if (strcasecmp(h->name, name) == 0) {
138 return h->value;
139 }
140 }
141 return NULL;
142 }
143
144 const HTTPHeader * HTTPMessage_get_headers(const HTTPMessage * message) {
145 return message->headers;
146 }
147
148 const char * HTTPMessage_get_start_line(const HTTPMessage * message) {
149 return message->start_line;
150 }
151
152 void HTTPMessage_set_start_line(HTTPMessage * message, const char * start_line) {
153 free(message->start_line);
154 message->start_line = xstrdup(start_line);
155 }
156
157 static int read_line(Stream * stream, HTTPConnection * connection) __attribute__((warn_unused_result));
158
159 static int read_line(Stream * stream, HTTPConnection * connection) {
160 for (;;) {
161 int octet;
162 int result = HTTPConnection_read_octet(connection, &octet);
163 if (result != 0) {
164 return result;
165 }
166
167 /* check for end of input */
168 if (octet == -1) {
169 return 0;
170 }
171
172 char c = (char) octet;
173 Stream_write_char(stream, c);
174 if (c == '\n') {
175 return 0;
176 }
177 }
178 }
179
180 static int read_header(Stream * stream, HTTPConnection * connection) __attribute__((warn_unused_result));
181
182 static int read_header(Stream * stream, HTTPConnection * connection) {
183 int c;
184
185 do {
186 int result = read_line(stream, connection);
187 if (result != 0) {
188 return result;
189 }
190
191 /* check for blank line ending the headers */
192 if (stream->length == 0 ||
193 (stream->length == 1 && stream->data[0] == '\n') ||
194 (stream->length == 2 && stream->data[0] == '\r' && stream->data[1] == '\n')) {
195 break;
196 }
197
198 result = HTTPConnection_peek_octet(connection, &c);
199 if (result != 0) {
200 return result;
201 }
202 }
203 while (c == ' ' || c == '\t');
204
205 return 0;
206 }
207
208 static bool is_lws(uint8_t c) {
209 return c == '\r' || c == '\n' || c == ' ' || c == '\t';
210 }
211
212 static bool is_separator(uint8_t c) {
213 /* RFC 2616 2.2 */
214 return strchr("()<>@,;:\\\"/[]?={} \t", c) != NULL;
215 }
216
217 static bool is_token_char(uint8_t c) {
218 /* RFC 2616 2.2 */
219 return 32 <= c && c <= 126 && ! is_separator(c);
220 }
221
222 static bool is_text(uint8_t c) {
223 return ! (c <= 31 || c == 127);
224 }
225
226 static void skip_lws(const uint8_t ** p) {
227 while (**p != '\0' && is_lws(**p)) {
228 (*p)++;
229 }
230 }
231
232 static uint8_t * parse_token(const uint8_t ** p) {
233 const uint8_t * start = *p;
234 while (**p != '\0' && is_token_char(**p)) {
235 (*p)++;
236 }
237
238 if (*p == start) {
239 return NULL;
240 }
241
242 return (uint8_t *) xstrndup((char *) start, *p - start);
243 }
244
245 static uint8_t * parse_quoted_string(const uint8_t ** p) {
246 const uint8_t * start = *p;
247
248 if (**p != '"') {
249 return NULL;
250 }
251 (*p)++;
252
253 while (**p != '\0' && **p != '"') {
254 if (**p == '\\') {
255 (*p)++;
256 if (**p < 1 || **p > 127) {
257 return NULL;
258 }
259 (*p)++;
260 }
261 else if (is_text(**p)) {
262 (*p)++;
263 }
264 else {
265 return NULL;
266 }
267 }
268
269 if (**p != '"') {
270 return NULL;
271 }
272 (*p)++;
273
274 return (uint8_t *) xstrndup((char *) start, *p - start);
275 }
276
277 static bool stream_contains_nul(const Stream * stream) {
278 for (size_t i = 0; i < stream->length; i++) {
279 if (stream->data[i] == '\0') {
280 return true;
281 }
282 }
283 return false;
284 }
285
286 int HTTPMessage_read_start_line_and_headers(HTTPMessage * message) {
287 Stream * stream = Stream_new(0);
288
289 /* read the start line */
290 int result = read_line(stream, message->connection);
291 if (result != 0) {
292 Stream_delete(stream);
293 return -1;
294 }
295
296 /* check for NUL byte */
297 if (stream_contains_nul(stream)) {
298 Stream_delete(stream);
299 return -1;
300 }
301
302 message->start_line = xstrndup((char *) stream->data, stream->length);
303
304 /* read the headers - RFC 2616 4.2 */
305 message->headers = NULL;
306 for (;;) {
307 Stream_reset(stream);
308 result = read_header(stream, message->connection);
309 if (result != 0) {
310 Stream_delete(stream);
311 return -1;
312 }
313
314 /* check for CRLF (or similar) to terminate headers */
315 if (stream->length == 0 ||
316 (stream->length == 1 && stream->data[0] == '\n') ||
317 (stream->length == 2 && stream->data[0] == '\r' && stream->data[1] == '\n')) {
318 break;
319 }
320
321 /* check for NUL byte */
322 if (stream_contains_nul(stream)) {
323 Stream_delete(stream);
324 return -1;
325 }
326
327 /* NUL-terminate the header */
328 Stream_write_char(stream, '\0');
329
330 const uint8_t * p = stream->data;
331
332 char * name = (char *) parse_token(&p);
333 if (name == NULL) {
334 Stream_delete(stream);
335 return -1;
336 }
337
338 skip_lws(&p);
339
340 /* expect colon */
341 if (*p != ':') {
342 free(name);
343 Stream_delete(stream);
344 return -1;
345 }
346
347 /* skip over colon */
348 p++;
349
350 skip_lws(&p);
351
352 if (*p == '\0') {
353 free(name);
354 Stream_delete(stream);
355 return -1;
356 }
357
358 /* skip backward over LWS, starting from the last char in the buffer */
359 uint8_t * end = stream->data + stream->length - 2;
360 while (end > p && is_lws(*end)) {
361 end--;
362 }
363
364 char * value = xstrndup((char *) p, end - p + 1);
365
366 HTTPMessage_add_header(message, name, value);
367 free(name);
368 free(value);
369 }
370
371 Stream_delete(stream);
372
373 /*
374 RFC 2616 4.3:
375 - a request has a body iff the request headers include Content-Length or Transfer-Encoding
376 - a response has a body iff the request is not HEAD and the response is not 1xx, 204, 304
377 */
378
379 const char * content_length = HTTPMessage_find_header(message, HTTP_CONTENT_LENGTH);
380 if (content_length != NULL) {
381 size_t value = 0;
382 for (const char * p = content_length; *p != '\0'; p++) {
383 /* check for overflow */
384 if (SIZE_MAX / 10 < value) {
385 return -1;
386 }
387 value *= 10;
388
389 uint8_t digit = *p;
390
391 /* check that it contains only decimal digits */
392 if (digit < '0' || digit > '9') {
393 return -1;
394 }
395
396 size_t digit_value = digit - '0';
397
398 /* check for overflow */
399 if (SIZE_MAX - digit_value < value) {
400 return -1;
401 }
402 value += digit_value;
403 }
404
405 message->bytes_remaining = value;
406 message->has_content_length = true;
407 }
408
409 const char * transfer_encoding = HTTPMessage_find_header(message, HTTP_TRANSFER_ENCODING);
410 if (transfer_encoding != NULL) {
411 uint8_t * token = NULL;
412
413 const uint8_t * p = (const uint8_t *) transfer_encoding;
414 result = 0;
415 for (;;) {
416 skip_lws(&p);
417
418 if (! is_token_char(*p)) {
419 result = -1;
420 break;
421 }
422
423 free(token);
424 token = parse_token(&p);
425
426 skip_lws(&p);
427
428 while (*p == ';') {
429 p++;
430
431 skip_lws(&p);
432
433 if (! is_token_char(*p)) {
434 result = -1;
435 break;
436 }
437 uint8_t * attribute = parse_token(&p);
438 free(attribute);
439
440 skip_lws(&p);
441
442 if (*p != '=') {
443 result = -1;
444 break;
445 }
446 p++;
447
448 skip_lws(&p);
449
450 if (*p == '"') {
451 uint8_t * value = parse_quoted_string(&p);
452 if (value == NULL) {
453 result = -1;
454 break;
455 }
456 free(value);
457 }
458 else if (is_token_char(*p)) {
459 uint8_t * value = parse_token(&p);
460 free(value);
461 }
462 else {
463 result = -1;
464 break;
465 }
466
467 skip_lws(&p);
468 }
469
470 if (result == -1) {
471 break;
472 }
473
474 if (*p != ',') {
475 break;
476 }
477
478 p++;
479 }
480
481 if (result == 0 && *p == '\0' && token != NULL && strcasecmp((char *) token, "chunked") == 0) {
482 message->is_chunked = true;
483 message->chunk_buffer = Stream_new(0);
484 }
485
486 free(token);
487 }
488
489 return result;
490 }
491
492 int HTTPMessage_write_start_line_and_headers(HTTPMessage * message) {
493 int result = 0;
494
495 if (message->is_started) {
496 return result;
497 }
498
499 message->is_started = true;
500
501 /* send the start line */
502 assert(message->start_line != NULL);
503 size_t length = strlen(message->start_line);
504 assert(length >= 2 && message->start_line[length - 2] == '\r' && message->start_line[length - 1] == '\n');
505 result = HTTPConnection_write(message->connection, message->start_line, length);
506 if (result != 0) {
507 return result;
508 }
509
510 /* send the headers */
511 HTTPMessage_set_header(message, HTTP_CONNECTION, "close");
512 for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
513 result = HTTPConnection_write(message->connection, h->name, strlen(h->name));
514 if (result != 0) {
515 return result;
516 }
517 result = HTTPConnection_write(message->connection, ": ", 2);
518 if (result != 0) {
519 return result;
520 }
521 result = HTTPConnection_write(message->connection, h->value, strlen(h->value));
522 if (result != 0) {
523 return result;
524 }
525 result = HTTPConnection_write(message->connection, "\r\n", 2);
526 if (result != 0) {
527 return result;
528 }
529 }
530
531 result = HTTPConnection_write(message->connection, "\r\n", 2);
532 return result;
533 }
534
535 bool HTTPMessage_has_sent_headers(const HTTPMessage * message) {
536 return message->is_started;
537 }
538
539 int HTTPMessage_write(HTTPMessage * message, const void * p, size_t size) {
540 int result = 0;
541 result = HTTPMessage_write_start_line_and_headers(message);
542 if (result != 0) {
543 return result;
544 }
545 result = HTTPConnection_write(message->connection, p, size);
546 return result;
547 }
548
549 int HTTPMessage_flush(HTTPMessage * message) {
550 int result = 0;
551 result = HTTPMessage_write_start_line_and_headers(message);
552 if (result != 0) {
553 return result;
554 }
555 result = HTTPConnection_flush(message->connection);
556 return result;
557 }
558
559 static int read_chunk_size_line(HTTPMessage * message) __attribute__((warn_unused_result));
560
561 static int read_chunk_size_line(HTTPMessage * message) {
562 Stream_reset(message->chunk_buffer);
563 int result = read_line(message->chunk_buffer, message->connection);
564 if (result != 0) {
565 return result;
566 }
567 if (message->chunk_buffer->length < 2) {
568 return -1;
569 }
570 return 0;
571 }
572
573 static int read_chunk_size(Stream * stream, size_t * chunk_size) __attribute__((warn_unused_result));
574
575 static int read_chunk_size(Stream * stream, size_t * chunk_size) {
576 size_t value = 0;
577 for (size_t i = 0; i < stream->length; i++) {
578 uint8_t digit = stream->data[i];
579
580 /* check that it contains only hexadecimal digits */
581 size_t digit_value;
582 if ('0' <= digit && digit <= '9') {
583 digit_value = digit - '0';
584 }
585 else if ('a' <= digit && digit <= 'f') {
586 digit_value = digit - 'a' + 10;
587 }
588 else if ('A' <= digit && digit <= 'F') {
589 digit_value = digit - 'A' + 10;
590 }
591 else if (is_lws(digit) || digit == ';') {
592 break;
593 }
594 else {
595 return -1;
596 }
597
598 /* check for overflow */
599 if (SIZE_MAX / 16 < value) {
600 return -1;
601 }
602 value *= 16;
603
604 /* check for overflow */
605 if (SIZE_MAX - digit_value < value) {
606 return -1;
607 }
608 value += digit_value;
609 }
610
611 *chunk_size = value;
612 return 0;
613 }
614
615 static int read_chunked_message_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
616 int result = 0;
617 *bytes_read = 0;
618
619 if (message->chunked_body_state == CHUNKED_BODY_DONE) {
620 return 0;
621 }
622
623 uint8_t * s = p;
624 int c;
625 for (*bytes_read = 0; *bytes_read < capacity; (*bytes_read)++) {
626 switch (message->chunked_body_state) {
627 case CHUNKED_BODY_CHUNK_SIZE:
628 if (message->chunk_buffer->length == 0) {
629 /* read a `chunk-size' line */
630 result = read_chunk_size_line(message);
631 if (result != 0) {
632 return result;
633 }
634
635 message->bytes_remaining = message->chunk_buffer->length;
636 }
637
638 if (message->bytes_remaining == 0) {
639 return -1;
640 }
641
642 /* serve from the chunk buffer */
643 s[*bytes_read] = message->chunk_buffer->data[message->chunk_buffer->length - message->bytes_remaining];
644 message->bytes_remaining--;
645
646 if (message->bytes_remaining == 0) {
647 size_t chunk_size;
648 result = read_chunk_size(message->chunk_buffer, &chunk_size);
649 if (result != 0) {
650 return result;
651 }
652 Stream_reset(message->chunk_buffer);
653 if (chunk_size == 0) {
654 message->chunked_body_state = CHUNKED_BODY_TRAILER;
655 }
656 else if (SIZE_MAX - 2 < chunk_size) {
657 /* overflow */
658 return -1;
659 }
660 else {
661 message->chunked_body_state = CHUNKED_BODY_CHUNK_DATA;
662 message->bytes_remaining = chunk_size + 2;
663 }
664 }
665
666 break;
667 case CHUNKED_BODY_CHUNK_DATA:
668 /* serve from the chunk */
669 result = HTTPConnection_read_octet(message->connection, &c);
670 if (result != 0) {
671 return result;
672 }
673 if (c == -1) {
674 result = -1;
675 message->chunked_body_state = CHUNKED_BODY_DONE;
676 return result;
677 }
678 s[*bytes_read] = (uint8_t) c;
679 message->bytes_remaining--;
680
681 if (message->bytes_remaining == 0) {
682 message->chunked_body_state = CHUNKED_BODY_CHUNK_SIZE;
683 }
684
685 break;
686 case CHUNKED_BODY_TRAILER:
687 if (message->chunk_buffer->length == 0) {
688 /* read a header */
689 result = read_header(message->chunk_buffer, message->connection);
690 if (result != 0) {
691 return result;
692 }
693 message->bytes_remaining = message->chunk_buffer->length;
694 }
695
696 if (message->bytes_remaining == 0) {
697 message->chunked_body_state = CHUNKED_BODY_DONE;
698 return result;
699 }
700
701 /* serve from the chunk buffer */
702 s[*bytes_read] = message->chunk_buffer->data[message->chunk_buffer->length - message->bytes_remaining];
703 message->bytes_remaining--;
704
705 if (message->bytes_remaining == 0) {
706 size_t length = message->chunk_buffer->length;
707 uint8_t * chunk_buffer = message->chunk_buffer->data;
708 if (length == 0 ||
709 (length == 1 && chunk_buffer[0] == '\n') ||
710 (length == 2 && chunk_buffer[0] == '\r' && chunk_buffer[1] == '\n')) {
711 message->chunked_body_state = CHUNKED_BODY_DONE;
712 return result;
713 }
714 Stream_reset(message->chunk_buffer);
715 }
716
717 break;
718 default:
719 break;
720 }
721 }
722
723 return result;
724 }
725
726 static int read_chunked_entity_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
727 int result = 0;
728 *bytes_read = 0;
729
730 if (message->chunked_body_state == CHUNKED_BODY_DONE) {
731 return result;
732 }
733
734 uint8_t * s = p;
735 for (*bytes_read = 0; *bytes_read < capacity; (*bytes_read)++) {
736 if (message->bytes_remaining == 0) {
737 result = read_chunk_size_line(message);
738 if (result != 0) {
739 break;
740 }
741 size_t chunk_size;
742 result = read_chunk_size(message->chunk_buffer, &chunk_size);
743 if (result != 0) {
744 break;
745 }
746 message->bytes_remaining = chunk_size;
747 if (chunk_size == 0) {
748 message->chunked_body_state = CHUNKED_BODY_DONE;
749 break;
750 }
751 }
752
753 int c;
754 result = HTTPConnection_read_octet(message->connection, &c);
755 if (result != 0) {
756 break;
757 }
758 if (c == -1) {
759 result = -1;
760 message->chunked_body_state = CHUNKED_BODY_DONE;
761 break;
762 }
763 s[*bytes_read] = (uint8_t) c;
764 message->bytes_remaining--;
765 }
766
767 return result;
768 }
769
770 int HTTPMessage_read_message_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
771 if (message->is_chunked) {
772 return read_chunked_message_body(message, p, capacity, bytes_read);
773 }
774
775 int result = 0;
776 uint8_t * s = p;
777 for (*bytes_read = 0; *bytes_read < capacity; (*bytes_read)++) {
778 if (message->has_content_length && message->bytes_remaining == 0) {
779 break;
780 }
781
782 int c;
783 result = HTTPConnection_read_octet(message->connection, &c);
784 if (result != 0) {
785 break;
786 }
787 if (c == -1) {
788 break;
789 }
790 s[*bytes_read] = (uint8_t) c;
791 message->bytes_remaining--;
792 }
793 return result;
794 }
795
796 int HTTPMessage_read_entity_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
797 if (message->is_chunked) {
798 return read_chunked_entity_body(message, p, capacity, bytes_read);
799 }
800
801 return HTTPMessage_read_message_body(message, p, capacity, bytes_read);
802 }
803
804 int HTTPMessage_read_entire_entity_body(HTTPMessage * message, Stream * input_stream) {
805 int result = 0;
806 uint8_t * buffer[8192];
807 for (;;) {
808 size_t bytes_read;
809 result = HTTPMessage_read_entity_body(message, buffer, 8192, &bytes_read);
810 if (result != 0) {
811 break;
812 }
813 if (bytes_read == 0) {
814 break;
815 }
816 Stream_write(input_stream, buffer, bytes_read);
817 }
818 return result;
819 }

  ViewVC Help
Powered by ViewVC 1.1.24