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

Annotation of /trunk/http-exchange.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 125 - (hide annotations)
Mon Jun 2 17:52:38 2008 UTC (11 years, 2 months ago) by siliconforks
File MIME type: text/plain
File size: 14270 byte(s)
Fixes for compiling with MinGW.

1 siliconforks 116 /*
2     http-exchange.c - HTTP request/response exchange
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 <ctype.h>
26     #include <string.h>
27    
28     #include "util.h"
29    
30     struct HTTPExchange {
31     HTTPConnection * connection;
32    
33     HTTPMessage * request_message;
34    
35     char * method;
36     char * request_uri;
37     char * request_http_version;
38    
39     char * host;
40     uint16_t port;
41     char * abs_path;
42     char * query;
43    
44     HTTPMessage * response_message;
45    
46     uint16_t status_code;
47     char * response_http_version;
48     };
49    
50     static const struct {
51     const int status_code;
52     const char * const reason_phrase;
53     } reason_phrases[] = {
54     {100, "Continue"},
55     {101, "Switching Protocols"},
56     {200, "OK"},
57     {201, "Created"},
58     {202, "Accepted"},
59     {203, "Non-Authoritative Information"},
60     {204, "No Content"},
61     {205, "Reset Content"},
62     {206, "Partial Content"},
63     {301, "Moved Permanently"},
64     {302, "Found"},
65     {303, "See Other"},
66     {304, "Not Modified"},
67     {305, "Use Proxy"},
68     {307, "Temporary Redirect"},
69     {400, "Bad Request"},
70     {401, "Unauthorized"},
71     {402, "Payment Required"},
72     {403, "Forbidden"},
73     {404, "Not Found"},
74     {405, "Method Not Allowed"},
75     {406, "Not Acceptable"},
76     {407, "Proxy Authentication Required"},
77     {408, "Request Time-out"},
78     {409, "Conflict"},
79     {410, "Gone"},
80     {411, "Length Required"},
81     {412, "Precondition Failed"},
82     {413, "Request Entity Too Large"},
83     {414, "Request-URI Too Large"},
84     {415, "Unsupported Media Type"},
85     {416, "Requested range not satisfiable"},
86     {417, "Expectation Failed"},
87     {500, "Internal Server Error"},
88     {501, "Not Implemented"},
89     {502, "Bad Gateway"},
90     {503, "Service Unavailable"},
91     {504, "Gateway Time-out"},
92     {505, "HTTP Version not supported"},
93     };
94    
95     HTTPExchange * HTTPExchange_new(HTTPConnection * connection) {
96     HTTPExchange * exchange = xmalloc(sizeof(HTTPExchange));
97    
98     exchange->connection = connection;
99    
100     exchange->request_message = HTTPMessage_new(connection);
101     exchange->method = NULL;
102     exchange->request_uri = NULL;
103     exchange->request_http_version = NULL;
104     exchange->host = NULL;
105     exchange->port = 0;
106     exchange->abs_path = NULL;
107     exchange->query = NULL;
108    
109     exchange->response_message = HTTPMessage_new(connection);
110     exchange->response_http_version = NULL;
111     exchange->status_code = 0;
112    
113     return exchange;
114     }
115    
116     void HTTPExchange_delete(HTTPExchange * exchange) {
117     HTTPMessage_delete(exchange->response_message);
118     free(exchange->response_http_version);
119    
120     HTTPMessage_delete(exchange->request_message);
121     free(exchange->method);
122     free(exchange->request_uri);
123     free(exchange->request_http_version);
124     free(exchange->host);
125     free(exchange->abs_path);
126     free(exchange->query);
127    
128     free(exchange);
129     }
130    
131     int HTTPExchange_get_peer(const HTTPExchange * exchange, struct sockaddr_in * peer) {
132     return HTTPConnection_get_peer(exchange->connection, peer);
133     }
134    
135     HTTPMessage * HTTPExchange_get_request_message(const HTTPExchange * exchange) {
136     return exchange->request_message;
137     }
138    
139     const char * HTTPExchange_get_request_line(const HTTPExchange * exchange) {
140     return HTTPMessage_get_start_line(exchange->request_message);
141     }
142    
143     const char * HTTPExchange_get_method(const HTTPExchange * exchange) {
144     return exchange->method;
145     }
146    
147     const char * HTTPExchange_get_request_uri(const HTTPExchange * exchange) {
148     return exchange->request_uri;
149     }
150    
151     const char * HTTPExchange_get_request_http_version(const HTTPExchange * exchange) {
152     return exchange->request_http_version;
153     }
154    
155     const char * HTTPExchange_get_host(const HTTPExchange * exchange) {
156     return exchange->host;
157     }
158    
159     uint16_t HTTPExchange_get_port(const HTTPExchange * exchange) {
160     return exchange->port;
161     }
162    
163     const char * HTTPExchange_get_abs_path(const HTTPExchange * exchange) {
164     return exchange->abs_path;
165     }
166    
167     void HTTPExchange_set_method(HTTPExchange * exchange, const char * method) {
168     free(exchange->method);
169     exchange->method = xstrdup(method);
170     }
171    
172     void HTTPExchange_set_request_uri(HTTPExchange * exchange, const char * request_uri) {
173     free(exchange->request_uri);
174     exchange->request_uri = xstrdup(request_uri);
175     }
176    
177     const HTTPHeader * HTTPExchange_get_request_headers(const HTTPExchange * exchange) {
178     return HTTPMessage_get_headers(exchange->request_message);
179     }
180    
181     const char * HTTPExchange_find_request_header(const HTTPExchange * exchange, const char * name) {
182     return HTTPMessage_find_header(exchange->request_message, name);
183     }
184    
185     void HTTPExchange_add_request_header(HTTPExchange * exchange, const char * name, const char * value) {
186     HTTPMessage_add_header(exchange->request_message, name, value);
187     }
188    
189     void HTTPExchange_set_request_header(HTTPExchange * exchange, const char * name, const char * value) {
190     HTTPMessage_set_header(exchange->request_message, name, value);
191     }
192    
193     void HTTPExchange_set_request_content_length(HTTPExchange * exchange, size_t value) {
194     HTTPMessage_set_content_length(exchange->request_message, value);
195     }
196    
197     int HTTPExchange_read_request_headers(HTTPExchange * exchange) {
198     int result = 0;
199    
200     result = HTTPMessage_read_start_line_and_headers(exchange->request_message);
201     if (result != 0) {
202     return result;
203     }
204    
205     /* parse the Request-Line */
206     const char * request_line = HTTPMessage_get_start_line(exchange->request_message);
207     const char * p = request_line;
208    
209     /* parse the Method */
210     while (*p != ' ') {
211     if (*p == '\0') {
212     return -1;
213     }
214     p++;
215     }
216     if (p == request_line) {
217     return -1;
218     }
219     exchange->method = xstrndup(request_line, p - request_line);
220    
221     /* skip over space */
222     p++;
223    
224     /* parse the Request-URI */
225     const char * start = p;
226     while (*p != ' ') {
227     if (*p == '\0') {
228     return -1;
229     }
230     p++;
231     }
232     if (p == start) {
233     return -1;
234     }
235     exchange->request_uri = xstrndup(start, p - start);
236    
237     /* skip over space */
238     p++;
239    
240     /* parse the HTTP-Version */
241     start = p;
242     while (*p != '\r' && *p != '\n') {
243     if (*p == '\0') {
244     return -1;
245     }
246     p++;
247     }
248     if (p == start) {
249     return -1;
250     }
251     exchange->request_http_version = xstrndup(start, p - start);
252    
253     /* uri elements */
254     /* RFC 2616 5.1.2: the Request-URI can be an `absoluteURI' or an `abs_path' */
255     result = URL_parse(exchange->request_uri, &(exchange->host), &(exchange->port),
256     &(exchange->abs_path), &(exchange->query));
257     if (result != 0) {
258     return result;
259     }
260    
261     if (exchange->host == NULL) {
262     /* abs_path */
263     const char * h = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
264     if (h == NULL) {
265     /* this must be an HTTP/1.0 client */
266     }
267     else {
268     result = URL_parse_host_and_port(h, &(exchange->host), &(exchange->port));
269     if (result != 0) {
270     return result;
271     }
272     }
273     }
274    
275     return 0;
276     }
277    
278     int HTTPExchange_write_request_headers(HTTPExchange * exchange) {
279     if (HTTPMessage_has_sent_headers(exchange->request_message)) {
280     return 0;
281     }
282    
283     /* set the Request-Line */
284     if (HTTPMessage_get_start_line(exchange->request_message) == NULL) {
285     if (exchange->method == NULL) {
286     exchange->method = xstrdup("GET");
287     }
288     assert(exchange->request_uri != NULL);
289     char * request_line;
290     xasprintf(&request_line, "%s %s HTTP/1.1\r\n", exchange->method, exchange->request_uri);
291     HTTPMessage_set_start_line(exchange->request_message, request_line);
292     free(request_line);
293     }
294    
295     /* set the Host, if necessary */
296     if (! str_starts_with(exchange->request_uri, "http://")) {
297     const char * host = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
298     if (host == NULL) {
299     struct sockaddr_in peer;
300     int result = HTTPConnection_get_peer(exchange->connection, &peer);
301     if (result != 0) {
302     return result;
303     }
304     const char * a = inet_ntoa(peer.sin_addr);
305     char * value;
306     xasprintf(&value, "%s:%u", a, ntohs(peer.sin_port));
307     HTTPMessage_add_header(exchange->request_message, HTTP_HOST, value);
308     free(value);
309     }
310     }
311    
312     return HTTPMessage_write_start_line_and_headers(exchange->request_message);
313     }
314    
315     bool HTTPExchange_request_has_body(const HTTPExchange * exchange) {
316     /*
317     RFC 2616 4.3: a request has a body iff the request has a Content-Length or Transfer-Encoding header
318     */
319     return HTTPMessage_find_header(exchange->request_message, HTTP_CONTENT_LENGTH) != NULL ||
320     HTTPMessage_find_header(exchange->request_message, HTTP_TRANSFER_ENCODING) != NULL;
321     }
322    
323     int HTTPExchange_read_entire_request_entity_body(HTTPExchange * exchange, Stream * stream) {
324     return HTTPMessage_read_entire_entity_body(exchange->request_message, stream);
325     }
326    
327     int HTTPExchange_flush_request(HTTPExchange * exchange) {
328     return HTTPMessage_flush(exchange->request_message);
329     }
330    
331     /* response methods */
332    
333     HTTPMessage * HTTPExchange_get_response_message(const HTTPExchange * exchange) {
334     return exchange->response_message;
335     }
336    
337     const char * HTTPExchange_get_response_http_version(const HTTPExchange * exchange) {
338     return exchange->response_http_version;
339     }
340    
341     uint16_t HTTPExchange_get_status_code(const HTTPExchange * exchange) {
342     return exchange->status_code;
343     }
344    
345     void HTTPExchange_set_status_code(HTTPExchange * exchange, uint16_t status_code) {
346     exchange->status_code = status_code;
347     }
348    
349     const HTTPHeader * HTTPExchange_get_response_headers(const HTTPExchange * exchange) {
350     return HTTPMessage_get_headers(exchange->response_message);
351     }
352    
353     const char * HTTPExchange_find_response_header(const HTTPExchange * exchange, const char * name) {
354     return HTTPMessage_find_header(exchange->response_message, name);
355     }
356    
357     void HTTPExchange_add_response_header(HTTPExchange * exchange, const char * name, const char * value) {
358     HTTPMessage_add_header(exchange->response_message, name, value);
359     }
360    
361     void HTTPExchange_set_response_header(HTTPExchange * exchange, const char * name, const char * value) {
362     HTTPMessage_set_header(exchange->response_message, name, value);
363     }
364    
365     void HTTPExchange_set_response_content_length(HTTPExchange * exchange, size_t value) {
366     HTTPMessage_set_content_length(exchange->response_message, value);
367     }
368    
369     static void skip_digits(const char ** p) {
370     while (**p != '\0' && isdigit(**p)) {
371     (*p)++;
372     }
373     }
374    
375     int HTTPExchange_read_response_headers(HTTPExchange * exchange) {
376     /* make sure the request went through before we try to read stuff */
377     int result = HTTPExchange_flush_request(exchange);
378     if (result != 0) {
379     return result;
380     }
381    
382     result = HTTPMessage_read_start_line_and_headers(exchange->response_message);
383     if (result != 0) {
384     return result;
385     }
386    
387     /* parse the Status-Line (RFC 2616 6.1) */
388     const char * status_line = HTTPMessage_get_start_line(exchange->response_message);
389     const char * p = status_line;
390    
391     /* read the HTTP-Version */
392     if (! str_starts_with(p, "HTTP/")) {
393     return -1;
394     }
395     p += 5;
396     const char * start = p;
397     skip_digits(&p);
398     if (start == p) {
399     return -1;
400     }
401     if (*p != '.') {
402     return -1;
403     }
404     p++;
405     start = p;
406     skip_digits(&p);
407     if (start == p) {
408     return -1;
409     }
410     if (*p != ' ') {
411     return -1;
412     }
413     exchange->response_http_version = xstrndup(status_line, p - status_line);
414    
415     /* skip over the space */
416     p++;
417    
418     /* read the Status-Code */
419     start = p;
420     skip_digits(&p);
421     if (p - start != 3) {
422     return -1;
423     }
424     if (*p != ' ') {
425     return -1;
426     }
427     exchange->status_code = strtoul(start, NULL, 10);
428    
429     return 0;
430     }
431    
432     int HTTPExchange_write_response_headers(HTTPExchange * exchange) {
433     if (HTTPMessage_has_sent_headers(exchange->response_message)) {
434     return 0;
435     }
436    
437     /* set the Status-Line (RFC 2616 6.1) */
438     if (exchange->status_code == 0) {
439     exchange->status_code = 200;
440     }
441     const char * reason_phrase = NULL;
442     size_t num_reason_phrases = sizeof(reason_phrases) / sizeof(reason_phrases[0]);
443     for (size_t i = 0; i < num_reason_phrases; i++) {
444     if (reason_phrases[i].status_code == exchange->status_code) {
445     reason_phrase = reason_phrases[i].reason_phrase;
446     break;
447     }
448     }
449     assert(reason_phrase != NULL);
450     char * status_line;
451     xasprintf(&status_line, "HTTP/1.1 %u %s\r\n", exchange->status_code, reason_phrase);
452     HTTPMessage_set_start_line(exchange->response_message, status_line);
453     free(status_line);
454    
455     /* set the Content-Type, if necessary */
456     const char * content_type = HTTPMessage_find_header(exchange->response_message, HTTP_CONTENT_TYPE);
457     if (content_type == NULL) {
458     HTTPMessage_set_header(exchange->response_message, HTTP_CONTENT_TYPE, "text/html");
459     }
460    
461     return HTTPMessage_write_start_line_and_headers(exchange->response_message);
462     }
463    
464     bool HTTPExchange_response_has_body(const HTTPExchange * exchange) {
465     /*
466     RFC 2616 4.3: a response has a body iff the request is not HEAD and the response is not 1xx, 204, 304
467     */
468     const char * request_method = HTTPExchange_get_method(exchange);
469     assert(request_method != NULL);
470     return strcmp(request_method, "HEAD") != 0 &&
471     exchange->status_code != 304 &&
472     exchange->status_code != 204 &&
473     exchange->status_code / 100 != 1;
474     }
475    
476     int HTTPExchange_read_entire_response_entity_body(HTTPExchange * exchange, Stream * stream) {
477     return HTTPMessage_read_entire_entity_body(exchange->response_message, stream);
478     }
479    
480     int HTTPExchange_write_response(HTTPExchange * exchange, const void * p, size_t size) {
481     int result = HTTPExchange_write_response_headers(exchange);
482     if (result != 0) {
483     return result;
484     }
485     return HTTPMessage_write(exchange->response_message, p, size);
486     }
487    
488     int HTTPExchange_flush_response(HTTPExchange * exchange) {
489     int result = HTTPExchange_write_response_headers(exchange);
490     if (result != 0) {
491     return result;
492     }
493     return HTTPMessage_flush(exchange->response_message);
494     }

  ViewVC Help
Powered by ViewVC 1.1.24