25 |
#include <string.h> |
#include <string.h> |
26 |
|
|
27 |
#include <dirent.h> |
#include <dirent.h> |
28 |
|
#ifdef HAVE_PTHREAD_H |
29 |
#include <pthread.h> |
#include <pthread.h> |
30 |
|
#endif |
31 |
|
|
32 |
#include "http-server.h" |
#include "http-server.h" |
33 |
#include "instrument-js.h" |
#include "instrument-js.h" |
66 |
static const char ** no_instrument; |
static const char ** no_instrument; |
67 |
static size_t num_no_instrument = 0; |
static size_t num_no_instrument = 0; |
68 |
|
|
69 |
|
#ifdef __MINGW32__ |
70 |
|
CRITICAL_SECTION javascript_mutex; |
71 |
|
CRITICAL_SECTION source_cache_mutex; |
72 |
|
#define LOCK EnterCriticalSection |
73 |
|
#define UNLOCK LeaveCriticalSection |
74 |
|
#else |
75 |
pthread_mutex_t javascript_mutex = PTHREAD_MUTEX_INITIALIZER; |
pthread_mutex_t javascript_mutex = PTHREAD_MUTEX_INITIALIZER; |
76 |
pthread_mutex_t source_cache_mutex = PTHREAD_MUTEX_INITIALIZER; |
pthread_mutex_t source_cache_mutex = PTHREAD_MUTEX_INITIALIZER; |
77 |
|
#define LOCK pthread_mutex_lock |
78 |
|
#define UNLOCK pthread_mutex_unlock |
79 |
|
#endif |
80 |
|
|
81 |
static Stream * find_cached_source(const char * url) { |
static Stream * find_cached_source(const char * url) { |
82 |
Stream * result = NULL; |
Stream * result = NULL; |
83 |
pthread_mutex_lock(&source_cache_mutex); |
LOCK(&source_cache_mutex); |
84 |
for (SourceCache * p = source_cache; p != NULL; p = p->next) { |
for (SourceCache * p = source_cache; p != NULL; p = p->next) { |
85 |
if (strcmp(url, p->url) == 0) { |
if (strcmp(url, p->url) == 0) { |
86 |
result = p->source; |
result = p->source; |
87 |
break; |
break; |
88 |
} |
} |
89 |
} |
} |
90 |
pthread_mutex_unlock(&source_cache_mutex); |
UNLOCK(&source_cache_mutex); |
91 |
return result; |
return result; |
92 |
} |
} |
93 |
|
|
95 |
SourceCache * new_source_cache = xmalloc(sizeof(SourceCache)); |
SourceCache * new_source_cache = xmalloc(sizeof(SourceCache)); |
96 |
new_source_cache->url = xstrdup(url); |
new_source_cache->url = xstrdup(url); |
97 |
new_source_cache->source = source; |
new_source_cache->source = source; |
98 |
pthread_mutex_lock(&source_cache_mutex); |
LOCK(&source_cache_mutex); |
99 |
new_source_cache->next = source_cache; |
new_source_cache->next = source_cache; |
100 |
source_cache = new_source_cache; |
source_cache = new_source_cache; |
101 |
pthread_mutex_unlock(&source_cache_mutex); |
UNLOCK(&source_cache_mutex); |
102 |
} |
} |
103 |
|
|
104 |
static int get(const char * url, Stream * stream) __attribute__((warn_unused_result)); |
static int get(const char * url, Stream * stream) __attribute__((warn_unused_result)); |
355 |
Stream * stream = Stream_new(0); |
Stream * stream = Stream_new(0); |
356 |
Stream_write_file_contents(stream, f); |
Stream_write_file_contents(stream, f); |
357 |
|
|
358 |
pthread_mutex_lock(&javascript_mutex); |
LOCK(&javascript_mutex); |
359 |
int result = jscoverage_parse_json(coverage, stream->data, stream->length); |
int result = jscoverage_parse_json(coverage, stream->data, stream->length); |
360 |
pthread_mutex_unlock(&javascript_mutex); |
UNLOCK(&javascript_mutex); |
361 |
|
|
362 |
Stream_delete(stream); |
Stream_delete(stream); |
363 |
return result; |
return result; |
446 |
/* check that the path begins with / */ |
/* check that the path begins with / */ |
447 |
if (file_coverage->id[0] == '/') { |
if (file_coverage->id[0] == '/') { |
448 |
char * source_path = make_path(document_root, file_coverage->id + 1); |
char * source_path = make_path(document_root, file_coverage->id + 1); |
449 |
FILE * source_file = fopen(source_path, "r"); |
FILE * source_file = fopen(source_path, "rb"); |
450 |
free(source_path); |
free(source_path); |
451 |
if (source_file == NULL) { |
if (source_file == NULL) { |
452 |
fputs("\"\"", f); |
fputs("\"\"", f); |
513 |
} |
} |
514 |
|
|
515 |
Coverage * coverage = Coverage_new(); |
Coverage * coverage = Coverage_new(); |
516 |
pthread_mutex_lock(&javascript_mutex); |
LOCK(&javascript_mutex); |
517 |
int result = jscoverage_parse_json(coverage, json->data, json->length); |
int result = jscoverage_parse_json(coverage, json->data, json->length); |
518 |
pthread_mutex_unlock(&javascript_mutex); |
UNLOCK(&javascript_mutex); |
519 |
Stream_delete(json); |
Stream_delete(json); |
520 |
|
|
521 |
if (result != 0) { |
if (result != 0) { |
609 |
} |
} |
610 |
|
|
611 |
static void instrument_js(const char * id, Stream * input_stream, Stream * output_stream) { |
static void instrument_js(const char * id, Stream * input_stream, Stream * output_stream) { |
612 |
pthread_mutex_lock(&javascript_mutex); |
LOCK(&javascript_mutex); |
613 |
jscoverage_instrument_js(id, input_stream, output_stream); |
jscoverage_instrument_js(id, input_stream, output_stream); |
614 |
pthread_mutex_unlock(&javascript_mutex); |
UNLOCK(&javascript_mutex); |
615 |
|
|
616 |
const struct Resource * resource = get_resource("report.js"); |
const struct Resource * resource = get_resource("report.js"); |
617 |
Stream_write(output_stream, resource->data, resource->length); |
Stream_write(output_stream, resource->data, resource->length); |
819 |
} |
} |
820 |
|
|
821 |
filesystem_path = make_path(document_root, abs_path + 1); |
filesystem_path = make_path(document_root, abs_path + 1); |
822 |
|
size_t filesystem_path_length = strlen(filesystem_path); |
823 |
|
if (filesystem_path_length > 0 && filesystem_path[filesystem_path_length - 1] == '/') { |
824 |
|
/* stat on Windows doesn't work with trailing slash */ |
825 |
|
filesystem_path[filesystem_path_length - 1] = '\0'; |
826 |
|
} |
827 |
|
|
828 |
struct stat buf; |
struct stat buf; |
829 |
if (stat(filesystem_path, &buf) == -1) { |
if (stat(filesystem_path, &buf) == -1) { |
832 |
} |
} |
833 |
|
|
834 |
if (S_ISDIR(buf.st_mode)) { |
if (S_ISDIR(buf.st_mode)) { |
835 |
if (filesystem_path[strlen(filesystem_path) - 1] != '/') { |
if (abs_path[strlen(abs_path) - 1] != '/') { |
836 |
const char * request_uri = HTTPExchange_get_request_uri(exchange); |
const char * request_uri = HTTPExchange_get_request_uri(exchange); |
837 |
char * uri = xmalloc(strlen(request_uri) + 2); |
char * uri = xmalloc(strlen(request_uri) + 2); |
838 |
strcpy(uri, request_uri); |
strcpy(uri, request_uri); |
867 |
closedir(d); |
closedir(d); |
868 |
} |
} |
869 |
else if (S_ISREG(buf.st_mode)) { |
else if (S_ISREG(buf.st_mode)) { |
870 |
FILE * f = fopen(filesystem_path, "r"); |
FILE * f = fopen(filesystem_path, "rb"); |
871 |
if (f == NULL) { |
if (f == NULL) { |
872 |
send_response(exchange, 404, "Not found\n"); |
send_response(exchange, 404, "Not found\n"); |
873 |
goto done; |
goto done; |
1031 |
|
|
1032 |
/* is this a shutdown? */ |
/* is this a shutdown? */ |
1033 |
if (shutdown) { |
if (shutdown) { |
1034 |
|
#ifdef __MINGW32__ |
1035 |
|
WSADATA data; |
1036 |
|
if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { |
1037 |
|
fatal("Could not start Winsock"); |
1038 |
|
} |
1039 |
|
#endif |
1040 |
|
|
1041 |
/* INADDR_LOOPBACK */ |
/* INADDR_LOOPBACK */ |
1042 |
HTTPConnection * connection = HTTPConnection_new_client("127.0.0.1", numeric_port); |
HTTPConnection * connection = HTTPConnection_new_client("127.0.0.1", numeric_port); |
1043 |
if (connection == NULL) { |
if (connection == NULL) { |
1067 |
|
|
1068 |
jscoverage_init(); |
jscoverage_init(); |
1069 |
|
|
1070 |
|
#ifndef __MINGW32__ |
1071 |
/* handle broken pipe */ |
/* handle broken pipe */ |
1072 |
signal(SIGPIPE, SIG_IGN); |
signal(SIGPIPE, SIG_IGN); |
1073 |
|
#endif |
1074 |
|
|
1075 |
|
#ifdef __MINGW32__ |
1076 |
|
InitializeCriticalSection(&javascript_mutex); |
1077 |
|
InitializeCriticalSection(&source_cache_mutex); |
1078 |
|
#endif |
1079 |
|
|
1080 |
if (verbose) { |
if (verbose) { |
1081 |
printf("Starting HTTP server on %s:%lu\n", ip_address, numeric_port); |
printf("Starting HTTP server on %s:%lu\n", ip_address, numeric_port); |
1082 |
|
fflush(stdout); |
1083 |
} |
} |
1084 |
HTTPServer_run(ip_address, (uint16_t) numeric_port, handler); |
HTTPServer_run(ip_address, (uint16_t) numeric_port, handler); |
1085 |
if (verbose) { |
if (verbose) { |
1086 |
printf("Stopping HTTP server\n"); |
printf("Stopping HTTP server\n"); |
1087 |
|
fflush(stdout); |
1088 |
} |
} |
1089 |
|
|
1090 |
jscoverage_cleanup(); |
jscoverage_cleanup(); |
1091 |
|
|
1092 |
free(no_instrument); |
free(no_instrument); |
1093 |
|
|
1094 |
pthread_mutex_lock(&source_cache_mutex); |
LOCK(&source_cache_mutex); |
1095 |
while (source_cache != NULL) { |
while (source_cache != NULL) { |
1096 |
SourceCache * p = source_cache; |
SourceCache * p = source_cache; |
1097 |
source_cache = source_cache->next; |
source_cache = source_cache->next; |
1099 |
Stream_delete(p->source); |
Stream_delete(p->source); |
1100 |
free(p); |
free(p); |
1101 |
} |
} |
1102 |
pthread_mutex_unlock(&source_cache_mutex); |
UNLOCK(&source_cache_mutex); |
1103 |
|
|
1104 |
return 0; |
return 0; |
1105 |
} |
} |