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

Contents of /trunk/http-exchange.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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 "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