diff options
Diffstat (limited to 'tools/node_modules/expresso/deps/jscoverage/http-server.c')
-rw-r--r-- | tools/node_modules/expresso/deps/jscoverage/http-server.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/tools/node_modules/expresso/deps/jscoverage/http-server.c b/tools/node_modules/expresso/deps/jscoverage/http-server.c new file mode 100644 index 0000000..853d285 --- /dev/null +++ b/tools/node_modules/expresso/deps/jscoverage/http-server.c @@ -0,0 +1,236 @@ +/* + http-server.c - generic HTTP server + 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 <stdarg.h> +#include <string.h> + +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#ifdef __MINGW32__ +#include <process.h> +#endif + +#include "util.h" + +#ifdef __MINGW32__ +typedef void ThreadRoutineReturnType; +#define THREAD_ROUTINE_RETURN return +#else +typedef void * ThreadRoutineReturnType; +#define THREAD_ROUTINE_RETURN return NULL +#endif + +struct HTTPServer { + char * ip_address; + uint16_t port; + HTTPServerHandler handler; + SOCKET s; +}; + +struct HTTPServerConnection { + HTTPConnection * connection; + struct HTTPServer * server; +}; + +static bool is_shutdown = false; +#ifdef __MINGW32__ +CRITICAL_SECTION shutdown_mutex; +#define LOCK EnterCriticalSection +#define UNLOCK LeaveCriticalSection +#else +pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER; +#define LOCK pthread_mutex_lock +#define UNLOCK pthread_mutex_unlock +#endif + +static ThreadRoutineReturnType handle_connection(void * p) { + struct HTTPServerConnection * connection = p; + uint16_t port = connection->server->port; + + HTTPExchange * exchange = HTTPExchange_new(connection->connection); + if (HTTPExchange_read_request_headers(exchange) == 0) { + connection->server->handler(exchange); + } + else { + HTTPExchange_set_status_code(exchange, 400); + const char * message = "Could not parse request headers\n"; + if (HTTPExchange_write_response(exchange, message, strlen(message)) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + } + if (HTTPExchange_flush_response(exchange) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + HTTPExchange_delete(exchange); + if (HTTPConnection_delete(connection->connection) != 0) { + HTTPServer_log_err("Warning: error closing connection to client\n"); + } + free(connection); + + /* HACK: make connection to server to force accept() to return */ + LOCK(&shutdown_mutex); + if (is_shutdown) { + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + HTTPServer_log_err("Warning: error creating socket\n"); + } + else { + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(port); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (connect(s, (struct sockaddr *) &a, sizeof(a)) == -1) { + HTTPServer_log_err("Warning: error connecting to server\n"); + } + closesocket(s); + } + } + UNLOCK(&shutdown_mutex); + + THREAD_ROUTINE_RETURN; +} + +static struct HTTPServer * HTTPServer_new(const char * ip_address, uint16_t port, HTTPServerHandler handler) { + struct HTTPServer * result = xmalloc(sizeof(struct HTTPServer)); + if (ip_address == NULL) { + result->ip_address = NULL; + } + else { + result->ip_address = xstrdup(ip_address); + } + result->port = port; + result->handler = handler; + result->s = -1; + return result; +} + +static void HTTPServer_delete(struct HTTPServer * server) { + free(server->ip_address); + closesocket(server->s); + free(server); +} + +void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) { + struct HTTPServer * server = HTTPServer_new(ip_address, port, handler); + +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + fatal("could not start Winsock"); + } + InitializeCriticalSection(&shutdown_mutex); +#endif + + server->s = socket(PF_INET, SOCK_STREAM, 0); + if (server->s == INVALID_SOCKET) { + fatal("could not create socket"); + } + + /* http://hea-www.harvard.edu/~fine/Tech/addrinuse.html */ + int optval = 1; + setsockopt(server->s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(server->port); + if (server->ip_address == NULL) { + /* + a.sin_addr.s_addr = htonl(INADDR_ANY); + */ + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + else { + if (inet_aton(server->ip_address, &(a.sin_addr)) == 0) { + closesocket(server->s); + fatal("invalid address: %s", server->ip_address); + } + } + + if (bind(server->s, (struct sockaddr *) &a, sizeof(a)) == -1) { + closesocket(server->s); + fatal("could not bind to address"); + } + + if (listen(server->s, 5) == -1) { + closesocket(server->s); + fatal("could not listen for connections"); + } + + for (;;) { + struct sockaddr_in client_address; + size_t client_address_size = sizeof(client_address); + SOCKET s = accept(server->s, (struct sockaddr *) &client_address, &client_address_size); + if (s == INVALID_SOCKET) { + HTTPServer_log_err("Warning: could not accept client connection\n"); + continue; + } + + LOCK(&shutdown_mutex); + if (is_shutdown) { + closesocket(s); + break; + } + UNLOCK(&shutdown_mutex); + + struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection)); + connection->server = server; + connection->connection = HTTPConnection_new_server(s); + +#ifdef __MINGW32__ + unsigned long thread = _beginthread(handle_connection, 0, connection); +#else + pthread_t thread; + pthread_attr_t a; + pthread_attr_init(&a); + pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); + pthread_create(&thread, &a, handle_connection, connection); + pthread_attr_destroy(&a); +#endif + } + + HTTPServer_delete(server); +} + +void HTTPServer_shutdown(void) { + LOCK(&shutdown_mutex); + is_shutdown = true; + UNLOCK(&shutdown_mutex); +} + +void HTTPServer_log_out(const char * format, ...) { + va_list a; + va_start(a, format); + vfprintf(stdout, format, a); + va_end(a); + fflush(stdout); +} + +void HTTPServer_log_err(const char * format, ...) { + va_list a; + va_start(a, format); + vfprintf(stderr, format, a); + va_end(a); + fflush(stderr); +} |