/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/http-exchange.c
C | 494 lines | 371 code | 79 blank | 44 comment | 83 complexity | f3e6871684b6a0ed778439b813a336e4 MD5 | raw file
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 30struct 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 50static 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 95HTTPExchange * 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 116void 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 131int HTTPExchange_get_peer(const HTTPExchange * exchange, struct sockaddr_in * peer) { 132 return HTTPConnection_get_peer(exchange->connection, peer); 133} 134 135HTTPMessage * HTTPExchange_get_request_message(const HTTPExchange * exchange) { 136 return exchange->request_message; 137} 138 139const char * HTTPExchange_get_request_line(const HTTPExchange * exchange) { 140 return HTTPMessage_get_start_line(exchange->request_message); 141} 142 143const char * HTTPExchange_get_method(const HTTPExchange * exchange) { 144 return exchange->method; 145} 146 147const char * HTTPExchange_get_request_uri(const HTTPExchange * exchange) { 148 return exchange->request_uri; 149} 150 151const char * HTTPExchange_get_request_http_version(const HTTPExchange * exchange) { 152 return exchange->request_http_version; 153} 154 155const char * HTTPExchange_get_host(const HTTPExchange * exchange) { 156 return exchange->host; 157} 158 159uint16_t HTTPExchange_get_port(const HTTPExchange * exchange) { 160 return exchange->port; 161} 162 163const char * HTTPExchange_get_abs_path(const HTTPExchange * exchange) { 164 return exchange->abs_path; 165} 166 167void HTTPExchange_set_method(HTTPExchange * exchange, const char * method) { 168 free(exchange->method); 169 exchange->method = xstrdup(method); 170} 171 172void HTTPExchange_set_request_uri(HTTPExchange * exchange, const char * request_uri) { 173 free(exchange->request_uri); 174 exchange->request_uri = xstrdup(request_uri); 175} 176 177const HTTPHeader * HTTPExchange_get_request_headers(const HTTPExchange * exchange) { 178 return HTTPMessage_get_headers(exchange->request_message); 179} 180 181const char * HTTPExchange_find_request_header(const HTTPExchange * exchange, const char * name) { 182 return HTTPMessage_find_header(exchange->request_message, name); 183} 184 185void HTTPExchange_add_request_header(HTTPExchange * exchange, const char * name, const char * value) { 186 HTTPMessage_add_header(exchange->request_message, name, value); 187} 188 189void HTTPExchange_set_request_header(HTTPExchange * exchange, const char * name, const char * value) { 190 HTTPMessage_set_header(exchange->request_message, name, value); 191} 192 193void HTTPExchange_set_request_content_length(HTTPExchange * exchange, size_t value) { 194 HTTPMessage_set_content_length(exchange->request_message, value); 195} 196 197int 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 278int 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 315bool 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 323int HTTPExchange_read_entire_request_entity_body(HTTPExchange * exchange, Stream * stream) { 324 return HTTPMessage_read_entire_entity_body(exchange->request_message, stream); 325} 326 327int HTTPExchange_flush_request(HTTPExchange * exchange) { 328 return HTTPMessage_flush(exchange->request_message); 329} 330 331/* response methods */ 332 333HTTPMessage * HTTPExchange_get_response_message(const HTTPExchange * exchange) { 334 return exchange->response_message; 335} 336 337const char * HTTPExchange_get_response_http_version(const HTTPExchange * exchange) { 338 return exchange->response_http_version; 339} 340 341uint16_t HTTPExchange_get_status_code(const HTTPExchange * exchange) { 342 return exchange->status_code; 343} 344 345void HTTPExchange_set_status_code(HTTPExchange * exchange, uint16_t status_code) { 346 exchange->status_code = status_code; 347} 348 349const HTTPHeader * HTTPExchange_get_response_headers(const HTTPExchange * exchange) { 350 return HTTPMessage_get_headers(exchange->response_message); 351} 352 353const char * HTTPExchange_find_response_header(const HTTPExchange * exchange, const char * name) { 354 return HTTPMessage_find_header(exchange->response_message, name); 355} 356 357void HTTPExchange_add_response_header(HTTPExchange * exchange, const char * name, const char * value) { 358 HTTPMessage_add_header(exchange->response_message, name, value); 359} 360 361void HTTPExchange_set_response_header(HTTPExchange * exchange, const char * name, const char * value) { 362 HTTPMessage_set_header(exchange->response_message, name, value); 363} 364 365void HTTPExchange_set_response_content_length(HTTPExchange * exchange, size_t value) { 366 HTTPMessage_set_content_length(exchange->response_message, value); 367} 368 369static void skip_digits(const char ** p) { 370 while (**p != '\0' && isdigit(**p)) { 371 (*p)++; 372 } 373} 374 375int 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 432int 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 464bool 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 476int HTTPExchange_read_entire_response_entity_body(HTTPExchange * exchange, Stream * stream) { 477 return HTTPMessage_read_entire_entity_body(exchange->response_message, stream); 478} 479 480int 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 488int 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}