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

Annotation of /trunk/http-message.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 siliconforks 116 /*
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