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

Contents of /trunk/http-exchange.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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