aboutsummaryrefslogtreecommitdiffstats
path: root/tools/node_modules/expresso/deps/jscoverage/http-exchange.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/expresso/deps/jscoverage/http-exchange.c')
-rw-r--r--tools/node_modules/expresso/deps/jscoverage/http-exchange.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/tools/node_modules/expresso/deps/jscoverage/http-exchange.c b/tools/node_modules/expresso/deps/jscoverage/http-exchange.c
new file mode 100644
index 0000000..9356455
--- /dev/null
+++ b/tools/node_modules/expresso/deps/jscoverage/http-exchange.c
@@ -0,0 +1,494 @@
+/*
+ http-exchange.c - HTTP request/response exchange
+ Copyright (C) 2008 siliconforks.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <config.h>
+
+#include "http-server.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "util.h"
+
+struct HTTPExchange {
+ HTTPConnection * connection;
+
+ HTTPMessage * request_message;
+
+ char * method;
+ char * request_uri;
+ char * request_http_version;
+
+ char * host;
+ uint16_t port;
+ char * abs_path;
+ char * query;
+
+ HTTPMessage * response_message;
+
+ uint16_t status_code;
+ char * response_http_version;
+};
+
+static const struct {
+ const int status_code;
+ const char * const reason_phrase;
+} reason_phrases[] = {
+ {100, "Continue"},
+ {101, "Switching Protocols"},
+ {200, "OK"},
+ {201, "Created"},
+ {202, "Accepted"},
+ {203, "Non-Authoritative Information"},
+ {204, "No Content"},
+ {205, "Reset Content"},
+ {206, "Partial Content"},
+ {301, "Moved Permanently"},
+ {302, "Found"},
+ {303, "See Other"},
+ {304, "Not Modified"},
+ {305, "Use Proxy"},
+ {307, "Temporary Redirect"},
+ {400, "Bad Request"},
+ {401, "Unauthorized"},
+ {402, "Payment Required"},
+ {403, "Forbidden"},
+ {404, "Not Found"},
+ {405, "Method Not Allowed"},
+ {406, "Not Acceptable"},
+ {407, "Proxy Authentication Required"},
+ {408, "Request Time-out"},
+ {409, "Conflict"},
+ {410, "Gone"},
+ {411, "Length Required"},
+ {412, "Precondition Failed"},
+ {413, "Request Entity Too Large"},
+ {414, "Request-URI Too Large"},
+ {415, "Unsupported Media Type"},
+ {416, "Requested range not satisfiable"},
+ {417, "Expectation Failed"},
+ {500, "Internal Server Error"},
+ {501, "Not Implemented"},
+ {502, "Bad Gateway"},
+ {503, "Service Unavailable"},
+ {504, "Gateway Time-out"},
+ {505, "HTTP Version not supported"},
+};
+
+HTTPExchange * HTTPExchange_new(HTTPConnection * connection) {
+ HTTPExchange * exchange = xmalloc(sizeof(HTTPExchange));
+
+ exchange->connection = connection;
+
+ exchange->request_message = HTTPMessage_new(connection);
+ exchange->method = NULL;
+ exchange->request_uri = NULL;
+ exchange->request_http_version = NULL;
+ exchange->host = NULL;
+ exchange->port = 0;
+ exchange->abs_path = NULL;
+ exchange->query = NULL;
+
+ exchange->response_message = HTTPMessage_new(connection);
+ exchange->response_http_version = NULL;
+ exchange->status_code = 0;
+
+ return exchange;
+}
+
+void HTTPExchange_delete(HTTPExchange * exchange) {
+ HTTPMessage_delete(exchange->response_message);
+ free(exchange->response_http_version);
+
+ HTTPMessage_delete(exchange->request_message);
+ free(exchange->method);
+ free(exchange->request_uri);
+ free(exchange->request_http_version);
+ free(exchange->host);
+ free(exchange->abs_path);
+ free(exchange->query);
+
+ free(exchange);
+}
+
+int HTTPExchange_get_peer(const HTTPExchange * exchange, struct sockaddr_in * peer) {
+ return HTTPConnection_get_peer(exchange->connection, peer);
+}
+
+HTTPMessage * HTTPExchange_get_request_message(const HTTPExchange * exchange) {
+ return exchange->request_message;
+}
+
+const char * HTTPExchange_get_request_line(const HTTPExchange * exchange) {
+ return HTTPMessage_get_start_line(exchange->request_message);
+}
+
+const char * HTTPExchange_get_method(const HTTPExchange * exchange) {
+ return exchange->method;
+}
+
+const char * HTTPExchange_get_request_uri(const HTTPExchange * exchange) {
+ return exchange->request_uri;
+}
+
+const char * HTTPExchange_get_request_http_version(const HTTPExchange * exchange) {
+ return exchange->request_http_version;
+}
+
+const char * HTTPExchange_get_host(const HTTPExchange * exchange) {
+ return exchange->host;
+}
+
+uint16_t HTTPExchange_get_port(const HTTPExchange * exchange) {
+ return exchange->port;
+}
+
+const char * HTTPExchange_get_abs_path(const HTTPExchange * exchange) {
+ return exchange->abs_path;
+}
+
+void HTTPExchange_set_method(HTTPExchange * exchange, const char * method) {
+ free(exchange->method);
+ exchange->method = xstrdup(method);
+}
+
+void HTTPExchange_set_request_uri(HTTPExchange * exchange, const char * request_uri) {
+ free(exchange->request_uri);
+ exchange->request_uri = xstrdup(request_uri);
+}
+
+const HTTPHeader * HTTPExchange_get_request_headers(const HTTPExchange * exchange) {
+ return HTTPMessage_get_headers(exchange->request_message);
+}
+
+const char * HTTPExchange_find_request_header(const HTTPExchange * exchange, const char * name) {
+ return HTTPMessage_find_header(exchange->request_message, name);
+}
+
+void HTTPExchange_add_request_header(HTTPExchange * exchange, const char * name, const char * value) {
+ HTTPMessage_add_header(exchange->request_message, name, value);
+}
+
+void HTTPExchange_set_request_header(HTTPExchange * exchange, const char * name, const char * value) {
+ HTTPMessage_set_header(exchange->request_message, name, value);
+}
+
+void HTTPExchange_set_request_content_length(HTTPExchange * exchange, size_t value) {
+ HTTPMessage_set_content_length(exchange->request_message, value);
+}
+
+int HTTPExchange_read_request_headers(HTTPExchange * exchange) {
+ int result = 0;
+
+ result = HTTPMessage_read_start_line_and_headers(exchange->request_message);
+ if (result != 0) {
+ return result;
+ }
+
+ /* parse the Request-Line */
+ const char * request_line = HTTPMessage_get_start_line(exchange->request_message);
+ const char * p = request_line;
+
+ /* parse the Method */
+ while (*p != ' ') {
+ if (*p == '\0') {
+ return -1;
+ }
+ p++;
+ }
+ if (p == request_line) {
+ return -1;
+ }
+ exchange->method = xstrndup(request_line, p - request_line);
+
+ /* skip over space */
+ p++;
+
+ /* parse the Request-URI */
+ const char * start = p;
+ while (*p != ' ') {
+ if (*p == '\0') {
+ return -1;
+ }
+ p++;
+ }
+ if (p == start) {
+ return -1;
+ }
+ exchange->request_uri = xstrndup(start, p - start);
+
+ /* skip over space */
+ p++;
+
+ /* parse the HTTP-Version */
+ start = p;
+ while (*p != '\r' && *p != '\n') {
+ if (*p == '\0') {
+ return -1;
+ }
+ p++;
+ }
+ if (p == start) {
+ return -1;
+ }
+ exchange->request_http_version = xstrndup(start, p - start);
+
+ /* uri elements */
+ /* RFC 2616 5.1.2: the Request-URI can be an `absoluteURI' or an `abs_path' */
+ result = URL_parse(exchange->request_uri, &(exchange->host), &(exchange->port),
+ &(exchange->abs_path), &(exchange->query));
+ if (result != 0) {
+ return result;
+ }
+
+ if (exchange->host == NULL) {
+ /* abs_path */
+ const char * h = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
+ if (h == NULL) {
+ /* this must be an HTTP/1.0 client */
+ }
+ else {
+ result = URL_parse_host_and_port(h, &(exchange->host), &(exchange->port));
+ if (result != 0) {
+ return result;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int HTTPExchange_write_request_headers(HTTPExchange * exchange) {
+ if (HTTPMessage_has_sent_headers(exchange->request_message)) {
+ return 0;
+ }
+
+ /* set the Request-Line */
+ if (HTTPMessage_get_start_line(exchange->request_message) == NULL) {
+ if (exchange->method == NULL) {
+ exchange->method = xstrdup("GET");
+ }
+ assert(exchange->request_uri != NULL);
+ char * request_line;
+ xasprintf(&request_line, "%s %s HTTP/1.1\r\n", exchange->method, exchange->request_uri);
+ HTTPMessage_set_start_line(exchange->request_message, request_line);
+ free(request_line);
+ }
+
+ /* set the Host, if necessary */
+ if (! str_starts_with(exchange->request_uri, "http://")) {
+ const char * host = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
+ if (host == NULL) {
+ struct sockaddr_in peer;
+ int result = HTTPConnection_get_peer(exchange->connection, &peer);
+ if (result != 0) {
+ return result;
+ }
+ const char * a = inet_ntoa(peer.sin_addr);
+ char * value;
+ xasprintf(&value, "%s:%u", a, ntohs(peer.sin_port));
+ HTTPMessage_add_header(exchange->request_message, HTTP_HOST, value);
+ free(value);
+ }
+ }
+
+ return HTTPMessage_write_start_line_and_headers(exchange->request_message);
+}
+
+bool HTTPExchange_request_has_body(const HTTPExchange * exchange) {
+ /*
+ RFC 2616 4.3: a request has a body iff the request has a Content-Length or Transfer-Encoding header
+ */
+ return HTTPMessage_find_header(exchange->request_message, HTTP_CONTENT_LENGTH) != NULL ||
+ HTTPMessage_find_header(exchange->request_message, HTTP_TRANSFER_ENCODING) != NULL;
+}
+
+int HTTPExchange_read_entire_request_entity_body(HTTPExchange * exchange, Stream * stream) {
+ return HTTPMessage_read_entire_entity_body(exchange->request_message, stream);
+}
+
+int HTTPExchange_flush_request(HTTPExchange * exchange) {
+ return HTTPMessage_flush(exchange->request_message);
+}
+
+/* response methods */
+
+HTTPMessage * HTTPExchange_get_response_message(const HTTPExchange * exchange) {
+ return exchange->response_message;
+}
+
+const char * HTTPExchange_get_response_http_version(const HTTPExchange * exchange) {
+ return exchange->response_http_version;
+}
+
+uint16_t HTTPExchange_get_status_code(const HTTPExchange * exchange) {
+ return exchange->status_code;
+}
+
+void HTTPExchange_set_status_code(HTTPExchange * exchange, uint16_t status_code) {
+ exchange->status_code = status_code;
+}
+
+const HTTPHeader * HTTPExchange_get_response_headers(const HTTPExchange * exchange) {
+ return HTTPMessage_get_headers(exchange->response_message);
+}
+
+const char * HTTPExchange_find_response_header(const HTTPExchange * exchange, const char * name) {
+ return HTTPMessage_find_header(exchange->response_message, name);
+}
+
+void HTTPExchange_add_response_header(HTTPExchange * exchange, const char * name, const char * value) {
+ HTTPMessage_add_header(exchange->response_message, name, value);
+}
+
+void HTTPExchange_set_response_header(HTTPExchange * exchange, const char * name, const char * value) {
+ HTTPMessage_set_header(exchange->response_message, name, value);
+}
+
+void HTTPExchange_set_response_content_length(HTTPExchange * exchange, size_t value) {
+ HTTPMessage_set_content_length(exchange->response_message, value);
+}
+
+static void skip_digits(const char ** p) {
+ while (**p != '\0' && isdigit(**p)) {
+ (*p)++;
+ }
+}
+
+int HTTPExchange_read_response_headers(HTTPExchange * exchange) {
+ /* make sure the request went through before we try to read stuff */
+ int result = HTTPExchange_flush_request(exchange);
+ if (result != 0) {
+ return result;
+ }
+
+ result = HTTPMessage_read_start_line_and_headers(exchange->response_message);
+ if (result != 0) {
+ return result;
+ }
+
+ /* parse the Status-Line (RFC 2616 6.1) */
+ const char * status_line = HTTPMessage_get_start_line(exchange->response_message);
+ const char * p = status_line;
+
+ /* read the HTTP-Version */
+ if (! str_starts_with(p, "HTTP/")) {
+ return -1;
+ }
+ p += 5;
+ const char * start = p;
+ skip_digits(&p);
+ if (start == p) {
+ return -1;
+ }
+ if (*p != '.') {
+ return -1;
+ }
+ p++;
+ start = p;
+ skip_digits(&p);
+ if (start == p) {
+ return -1;
+ }
+ if (*p != ' ') {
+ return -1;
+ }
+ exchange->response_http_version = xstrndup(status_line, p - status_line);
+
+ /* skip over the space */
+ p++;
+
+ /* read the Status-Code */
+ start = p;
+ skip_digits(&p);
+ if (p - start != 3) {
+ return -1;
+ }
+ if (*p != ' ') {
+ return -1;
+ }
+ exchange->status_code = strtoul(start, NULL, 10);
+
+ return 0;
+}
+
+int HTTPExchange_write_response_headers(HTTPExchange * exchange) {
+ if (HTTPMessage_has_sent_headers(exchange->response_message)) {
+ return 0;
+ }
+
+ /* set the Status-Line (RFC 2616 6.1) */
+ if (exchange->status_code == 0) {
+ exchange->status_code = 200;
+ }
+ const char * reason_phrase = NULL;
+ size_t num_reason_phrases = sizeof(reason_phrases) / sizeof(reason_phrases[0]);
+ for (size_t i = 0; i < num_reason_phrases; i++) {
+ if (reason_phrases[i].status_code == exchange->status_code) {
+ reason_phrase = reason_phrases[i].reason_phrase;
+ break;
+ }
+ }
+ assert(reason_phrase != NULL);
+ char * status_line;
+ xasprintf(&status_line, "HTTP/1.1 %u %s\r\n", exchange->status_code, reason_phrase);
+ HTTPMessage_set_start_line(exchange->response_message, status_line);
+ free(status_line);
+
+ /* set the Content-Type, if necessary */
+ const char * content_type = HTTPMessage_find_header(exchange->response_message, HTTP_CONTENT_TYPE);
+ if (content_type == NULL) {
+ HTTPMessage_set_header(exchange->response_message, HTTP_CONTENT_TYPE, "text/html");
+ }
+
+ return HTTPMessage_write_start_line_and_headers(exchange->response_message);
+}
+
+bool HTTPExchange_response_has_body(const HTTPExchange * exchange) {
+ /*
+ RFC 2616 4.3: a response has a body iff the request is not HEAD and the response is not 1xx, 204, 304
+ */
+ const char * request_method = HTTPExchange_get_method(exchange);
+ assert(request_method != NULL);
+ return strcmp(request_method, "HEAD") != 0 &&
+ exchange->status_code != 304 &&
+ exchange->status_code != 204 &&
+ exchange->status_code / 100 != 1;
+}
+
+int HTTPExchange_read_entire_response_entity_body(HTTPExchange * exchange, Stream * stream) {
+ return HTTPMessage_read_entire_entity_body(exchange->response_message, stream);
+}
+
+int HTTPExchange_write_response(HTTPExchange * exchange, const void * p, size_t size) {
+ int result = HTTPExchange_write_response_headers(exchange);
+ if (result != 0) {
+ return result;
+ }
+ return HTTPMessage_write(exchange->response_message, p, size);
+}
+
+int HTTPExchange_flush_response(HTTPExchange * exchange) {
+ int result = HTTPExchange_write_response_headers(exchange);
+ if (result != 0) {
+ return result;
+ }
+ return HTTPMessage_flush(exchange->response_message);
+}