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

Annotation of /trunk/http-exchange.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 505 - (hide annotations)
Sat Jan 2 04:55:54 2010 UTC (9 years, 10 months ago) by siliconforks
File MIME type: text/plain
File size: 14380 byte(s)
Update copyright year.

1 siliconforks 116 /*
2     http-exchange.c - HTTP request/response exchange
3 siliconforks 505 Copyright (C) 2008, 2009, 2010 siliconforks.com
4 siliconforks 116
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 siliconforks 478 const char * HTTPExchange_get_query(const HTTPExchange * exchange) {
168     return exchange->query;
169     }
170    
171 siliconforks 116 void HTTPExchange_set_method(HTTPExchange * exchange, const char * method) {
172     free(exchange->method);
173     exchange->method = xstrdup(method);
174     }
175    
176     void HTTPExchange_set_request_uri(HTTPExchange * exchange, const char * request_uri) {
177     free(exchange->request_uri);
178     exchange->request_uri = xstrdup(request_uri);
179     }
180    
181     const HTTPHeader * HTTPExchange_get_request_headers(const HTTPExchange * exchange) {
182     return HTTPMessage_get_headers(exchange->request_message);
183     }
184    
185     const char * HTTPExchange_find_request_header(const HTTPExchange * exchange, const char * name) {
186     return HTTPMessage_find_header(exchange->request_message, name);
187     }
188    
189     void HTTPExchange_add_request_header(HTTPExchange * exchange, const char * name, const char * value) {
190     HTTPMessage_add_header(exchange->request_message, name, value);
191     }
192    
193     void HTTPExchange_set_request_header(HTTPExchange * exchange, const char * name, const char * value) {
194     HTTPMessage_set_header(exchange->request_message, name, value);
195     }
196    
197     void HTTPExchange_set_request_content_length(HTTPExchange * exchange, size_t value) {
198     HTTPMessage_set_content_length(exchange->request_message, value);
199     }
200    
201     int HTTPExchange_read_request_headers(HTTPExchange * exchange) {
202     int result = 0;
203    
204     result = HTTPMessage_read_start_line_and_headers(exchange->request_message);
205     if (result != 0) {
206     return result;
207     }
208    
209     /* parse the Request-Line */
210     const char * request_line = HTTPMessage_get_start_line(exchange->request_message);
211     const char * p = request_line;
212    
213     /* parse the Method */
214     while (*p != ' ') {
215     if (*p == '\0') {
216     return -1;
217     }
218     p++;
219     }
220     if (p == request_line) {
221     return -1;
222     }
223     exchange->method = xstrndup(request_line, p - request_line);
224    
225     /* skip over space */
226     p++;
227    
228     /* parse the Request-URI */
229     const char * start = p;
230     while (*p != ' ') {
231     if (*p == '\0') {
232     return -1;
233     }
234     p++;
235     }
236     if (p == start) {
237     return -1;
238     }
239     exchange->request_uri = xstrndup(start, p - start);
240    
241     /* skip over space */
242     p++;
243    
244     /* parse the HTTP-Version */
245     start = p;
246     while (*p != '\r' && *p != '\n') {
247     if (*p == '\0') {
248     return -1;
249     }
250     p++;
251     }
252     if (p == start) {
253     return -1;
254     }
255     exchange->request_http_version = xstrndup(start, p - start);
256    
257     /* uri elements */
258     /* RFC 2616 5.1.2: the Request-URI can be an `absoluteURI' or an `abs_path' */
259     result = URL_parse(exchange->request_uri, &(exchange->host), &(exchange->port),
260     &(exchange->abs_path), &(exchange->query));
261     if (result != 0) {
262     return result;
263     }
264    
265     if (exchange->host == NULL) {
266     /* abs_path */
267     const char * h = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
268     if (h == NULL) {
269     /* this must be an HTTP/1.0 client */
270     }
271     else {
272     result = URL_parse_host_and_port(h, &(exchange->host), &(exchange->port));
273     if (result != 0) {
274     return result;
275     }
276     }
277     }
278    
279     return 0;
280     }
281    
282     int HTTPExchange_write_request_headers(HTTPExchange * exchange) {
283     if (HTTPMessage_has_sent_headers(exchange->request_message)) {
284     return 0;
285     }
286    
287     /* set the Request-Line */
288     if (HTTPMessage_get_start_line(exchange->request_message) == NULL) {
289     if (exchange->method == NULL) {
290     exchange->method = xstrdup("GET");
291     }
292     assert(exchange->request_uri != NULL);
293     char * request_line;
294     xasprintf(&request_line, "%s %s HTTP/1.1\r\n", exchange->method, exchange->request_uri);
295     HTTPMessage_set_start_line(exchange->request_message, request_line);
296     free(request_line);
297     }
298    
299     /* set the Host, if necessary */
300     if (! str_starts_with(exchange->request_uri, "http://")) {
301     const char * host = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
302     if (host == NULL) {
303     struct sockaddr_in peer;
304     int result = HTTPConnection_get_peer(exchange->connection, &peer);
305     if (result != 0) {
306     return result;
307     }
308     const char * a = inet_ntoa(peer.sin_addr);
309     char * value;
310     xasprintf(&value, "%s:%u", a, ntohs(peer.sin_port));
311     HTTPMessage_add_header(exchange->request_message, HTTP_HOST, value);
312     free(value);
313     }
314     }
315    
316     return HTTPMessage_write_start_line_and_headers(exchange->request_message);
317     }
318    
319     bool HTTPExchange_request_has_body(const HTTPExchange * exchange) {
320     /*
321     RFC 2616 4.3: a request has a body iff the request has a Content-Length or Transfer-Encoding header
322     */
323     return HTTPMessage_find_header(exchange->request_message, HTTP_CONTENT_LENGTH) != NULL ||
324     HTTPMessage_find_header(exchange->request_message, HTTP_TRANSFER_ENCODING) != NULL;
325     }
326    
327     int HTTPExchange_read_entire_request_entity_body(HTTPExchange * exchange, Stream * stream) {
328     return HTTPMessage_read_entire_entity_body(exchange->request_message, stream);
329     }
330    
331     int HTTPExchange_flush_request(HTTPExchange * exchange) {
332     return HTTPMessage_flush(exchange->request_message);
333     }
334    
335     /* response methods */
336    
337     HTTPMessage * HTTPExchange_get_response_message(const HTTPExchange * exchange) {
338     return exchange->response_message;
339     }
340    
341     const char * HTTPExchange_get_response_http_version(const HTTPExchange * exchange) {
342     return exchange->response_http_version;
343     }
344    
345     uint16_t HTTPExchange_get_status_code(const HTTPExchange * exchange) {
346     return exchange->status_code;
347     }
348    
349     void HTTPExchange_set_status_code(HTTPExchange * exchange, uint16_t status_code) {
350     exchange->status_code = status_code;
351     }
352    
353     const HTTPHeader * HTTPExchange_get_response_headers(const HTTPExchange * exchange) {
354     return HTTPMessage_get_headers(exchange->response_message);
355     }
356    
357     const char * HTTPExchange_find_response_header(const HTTPExchange * exchange, const char * name) {
358     return HTTPMessage_find_header(exchange->response_message, name);
359     }
360    
361     void HTTPExchange_add_response_header(HTTPExchange * exchange, const char * name, const char * value) {
362     HTTPMessage_add_header(exchange->response_message, name, value);
363     }
364    
365     void HTTPExchange_set_response_header(HTTPExchange * exchange, const char * name, const char * value) {
366     HTTPMessage_set_header(exchange->response_message, name, value);
367     }
368    
369     void HTTPExchange_set_response_content_length(HTTPExchange * exchange, size_t value) {
370     HTTPMessage_set_content_length(exchange->response_message, value);
371     }
372    
373     static void skip_digits(const char ** p) {
374     while (**p != '\0' && isdigit(**p)) {
375     (*p)++;
376     }
377     }
378    
379     int HTTPExchange_read_response_headers(HTTPExchange * exchange) {
380     /* make sure the request went through before we try to read stuff */
381     int result = HTTPExchange_flush_request(exchange);
382     if (result != 0) {
383     return result;
384     }
385    
386     result = HTTPMessage_read_start_line_and_headers(exchange->response_message);
387     if (result != 0) {
388     return result;
389     }
390    
391     /* parse the Status-Line (RFC 2616 6.1) */
392     const char * status_line = HTTPMessage_get_start_line(exchange->response_message);
393     const char * p = status_line;
394    
395     /* read the HTTP-Version */
396     if (! str_starts_with(p, "HTTP/")) {
397     return -1;
398     }
399     p += 5;
400     const char * start = p;
401     skip_digits(&p);
402     if (start == p) {
403     return -1;
404     }
405     if (*p != '.') {
406     return -1;
407     }
408     p++;
409     start = p;
410     skip_digits(&p);
411     if (start == p) {
412     return -1;
413     }
414     if (*p != ' ') {
415     return -1;
416     }
417     exchange->response_http_version = xstrndup(status_line, p - status_line);
418    
419     /* skip over the space */
420     p++;
421    
422     /* read the Status-Code */
423     start = p;
424     skip_digits(&p);
425     if (p - start != 3) {
426     return -1;
427     }
428     if (*p != ' ') {
429     return -1;
430     }
431     exchange->status_code = strtoul(start, NULL, 10);
432    
433     return 0;
434     }
435    
436     int HTTPExchange_write_response_headers(HTTPExchange * exchange) {
437     if (HTTPMessage_has_sent_headers(exchange->response_message)) {
438     return 0;
439     }
440    
441     /* set the Status-Line (RFC 2616 6.1) */
442     if (exchange->status_code == 0) {
443     exchange->status_code = 200;
444     }
445     const char * reason_phrase = NULL;
446     size_t num_reason_phrases = sizeof(reason_phrases) / sizeof(reason_phrases[0]);
447     for (size_t i = 0; i < num_reason_phrases; i++) {
448     if (reason_phrases[i].status_code == exchange->status_code) {
449     reason_phrase = reason_phrases[i].reason_phrase;
450     break;
451     }
452     }
453     assert(reason_phrase != NULL);
454     char * status_line;
455     xasprintf(&status_line, "HTTP/1.1 %u %s\r\n", exchange->status_code, reason_phrase);
456     HTTPMessage_set_start_line(exchange->response_message, status_line);
457     free(status_line);
458    
459     /* set the Content-Type, if necessary */
460     const char * content_type = HTTPMessage_find_header(exchange->response_message, HTTP_CONTENT_TYPE);
461     if (content_type == NULL) {
462     HTTPMessage_set_header(exchange->response_message, HTTP_CONTENT_TYPE, "text/html");
463     }
464    
465     return HTTPMessage_write_start_line_and_headers(exchange->response_message);
466     }
467    
468     bool HTTPExchange_response_has_body(const HTTPExchange * exchange) {
469     /*
470     RFC 2616 4.3: a response has a body iff the request is not HEAD and the response is not 1xx, 204, 304
471     */
472     const char * request_method = HTTPExchange_get_method(exchange);
473     assert(request_method != NULL);
474     return strcmp(request_method, "HEAD") != 0 &&
475     exchange->status_code != 304 &&
476     exchange->status_code != 204 &&
477     exchange->status_code / 100 != 1;
478     }
479    
480     int HTTPExchange_read_entire_response_entity_body(HTTPExchange * exchange, Stream * stream) {
481     return HTTPMessage_read_entire_entity_body(exchange->response_message, stream);
482     }
483    
484     int HTTPExchange_write_response(HTTPExchange * exchange, const void * p, size_t size) {
485     int result = HTTPExchange_write_response_headers(exchange);
486     if (result != 0) {
487     return result;
488     }
489     return HTTPMessage_write(exchange->response_message, p, size);
490     }
491    
492     int HTTPExchange_flush_response(HTTPExchange * exchange) {
493     int result = HTTPExchange_write_response_headers(exchange);
494     if (result != 0) {
495     return result;
496     }
497     return HTTPMessage_flush(exchange->response_message);
498     }

  ViewVC Help
Powered by ViewVC 1.1.24