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

Contents of /trunk/http-exchange.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 /*
2 http-exchange.c - HTTP request/response exchange
3 Copyright (C) 2008, 2009, 2010 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 const char * HTTPExchange_get_query(const HTTPExchange * exchange) {
168 return exchange->query;
169 }
170
171 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