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

Annotation of /trunk/http-exchange.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 116 - (hide annotations)
Sat May 31 21:42:36 2008 UTC (11 years, 2 months ago) by siliconforks
File MIME type: text/plain
File size: 14336 byte(s)
Add jscoverage-server.

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

  ViewVC Help
Powered by ViewVC 1.1.24