/[jscoverage]/trunk/jscoverage-server.c
ViewVC logotype

Diff of /trunk/jscoverage-server.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 119 by siliconforks, Sun Jun 1 14:05:47 2008 UTC revision 174 by siliconforks, Sat Sep 20 23:27:14 2008 UTC
# Line 25  Line 25 
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 "global.h"
33  #include "http-server.h"  #include "http-server.h"
34  #include "instrument-js.h"  #include "instrument-js.h"
35  #include "resource-manager.h"  #include "resource-manager.h"
36  #include "stream.h"  #include "stream.h"
37  #include "util.h"  #include "util.h"
38    
39    const char * jscoverage_encoding = "ISO-8859-1";
40    
41  typedef struct SourceCache {  typedef struct SourceCache {
42    char * url;    char * url;
43    Stream * source;    Stream * source;
# Line 64  Line 69 
69  static const char ** no_instrument;  static const char ** no_instrument;
70  static size_t num_no_instrument = 0;  static size_t num_no_instrument = 0;
71    
72    #ifdef __MINGW32__
73    CRITICAL_SECTION javascript_mutex;
74    CRITICAL_SECTION source_cache_mutex;
75    #define LOCK EnterCriticalSection
76    #define UNLOCK LeaveCriticalSection
77    #else
78  pthread_mutex_t javascript_mutex = PTHREAD_MUTEX_INITIALIZER;  pthread_mutex_t javascript_mutex = PTHREAD_MUTEX_INITIALIZER;
79  pthread_mutex_t source_cache_mutex = PTHREAD_MUTEX_INITIALIZER;  pthread_mutex_t source_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
80    #define LOCK pthread_mutex_lock
81    #define UNLOCK pthread_mutex_unlock
82    #endif
83    
84  static Stream * find_cached_source(const char * url) {  static Stream * find_cached_source(const char * url) {
85    Stream * result = NULL;    Stream * result = NULL;
86    pthread_mutex_lock(&source_cache_mutex);    LOCK(&source_cache_mutex);
87    for (SourceCache * p = source_cache; p != NULL; p = p->next) {    for (SourceCache * p = source_cache; p != NULL; p = p->next) {
88      if (strcmp(url, p->url) == 0) {      if (strcmp(url, p->url) == 0) {
89        result = p->source;        result = p->source;
90        break;        break;
91      }      }
92    }    }
93    pthread_mutex_unlock(&source_cache_mutex);    UNLOCK(&source_cache_mutex);
94    return result;    return result;
95  }  }
96    
# Line 84  Line 98 
98    SourceCache * new_source_cache = xmalloc(sizeof(SourceCache));    SourceCache * new_source_cache = xmalloc(sizeof(SourceCache));
99    new_source_cache->url = xstrdup(url);    new_source_cache->url = xstrdup(url);
100    new_source_cache->source = source;    new_source_cache->source = source;
101    pthread_mutex_lock(&source_cache_mutex);    LOCK(&source_cache_mutex);
102    new_source_cache->next = source_cache;    new_source_cache->next = source_cache;
103    source_cache = new_source_cache;    source_cache = new_source_cache;
104    pthread_mutex_unlock(&source_cache_mutex);    UNLOCK(&source_cache_mutex);
105  }  }
106    
107  static int get(const char * url, Stream * stream) __attribute__((warn_unused_result));  static int get(const char * url, Stream * stream) __attribute__((warn_unused_result));
# Line 344  Line 358 
358    Stream * stream = Stream_new(0);    Stream * stream = Stream_new(0);
359    Stream_write_file_contents(stream, f);    Stream_write_file_contents(stream, f);
360    
361    pthread_mutex_lock(&javascript_mutex);    LOCK(&javascript_mutex);
362    int result = jscoverage_parse_json(coverage, stream->data, stream->length);    int result = jscoverage_parse_json(coverage, stream->data, stream->length);
363    pthread_mutex_unlock(&javascript_mutex);    UNLOCK(&javascript_mutex);
364    
365    Stream_delete(stream);    Stream_delete(stream);
366    return result;    return result;
# Line 435  Line 449 
449        /* check that the path begins with / */        /* check that the path begins with / */
450        if (file_coverage->id[0] == '/') {        if (file_coverage->id[0] == '/') {
451          char * source_path = make_path(document_root, file_coverage->id + 1);          char * source_path = make_path(document_root, file_coverage->id + 1);
452          FILE * source_file = fopen(source_path, "r");          FILE * source_file = fopen(source_path, "rb");
453          free(source_path);          free(source_path);
454          if (source_file == NULL) {          if (source_file == NULL) {
455            fputs("\"\"", f);            fputs("\"\"", f);
# Line 502  Line 516 
516      }      }
517    
518      Coverage * coverage = Coverage_new();      Coverage * coverage = Coverage_new();
519      pthread_mutex_lock(&javascript_mutex);      LOCK(&javascript_mutex);
520      int result = jscoverage_parse_json(coverage, json->data, json->length);      int result = jscoverage_parse_json(coverage, json->data, json->length);
521      pthread_mutex_unlock(&javascript_mutex);      UNLOCK(&javascript_mutex);
522      Stream_delete(json);      Stream_delete(json);
523    
524      if (result != 0) {      if (result != 0) {
# Line 515  Line 529 
529    
530      mkdir_if_necessary(report_directory);      mkdir_if_necessary(report_directory);
531      char * path = make_path(report_directory, "jscoverage.json");      char * path = make_path(report_directory, "jscoverage.json");
532      FILE * f = fopen(path, "r");  
533      if (f != NULL) {      /* check if the JSON file exists */
534        struct stat buf;
535        if (stat(path, &buf) == 0) {
536        /* it exists: merge */        /* it exists: merge */
537        result = merge(coverage, f);        FILE * f = fopen(path, "r");
538        if (fclose(f) == EOF) {        if (f == NULL) {
539          result = 1;          result = 1;
540        }        }
541          else {
542            result = merge(coverage, f);
543            if (fclose(f) == EOF) {
544              result = 1;
545            }
546          }
547        if (result != 0) {        if (result != 0) {
548          free(path);          free(path);
549          Coverage_delete(coverage);          Coverage_delete(coverage);
# Line 541  Line 563 
563      /* copy other files */      /* copy other files */
564      jscoverage_copy_resources(report_directory);      jscoverage_copy_resources(report_directory);
565      path = make_path(report_directory, "jscoverage.js");      path = make_path(report_directory, "jscoverage.js");
566      f = fopen(path, "ab");      FILE * f = fopen(path, "ab");
567      free(path);      free(path);
568      if (f == NULL) {      if (f == NULL) {
569        send_response(exchange, 500, "Could not write to file: jscoverage.js\n");        send_response(exchange, 500, "Could not write to file: jscoverage.js\n");
# Line 597  Line 619 
619    }    }
620  }  }
621    
622  static void instrument_js(const char * id, Stream * input_stream, Stream * output_stream) {  static void instrument_js(const char * id, const char * encoding, Stream * input_stream, Stream * output_stream) {
623    pthread_mutex_lock(&javascript_mutex);    LOCK(&javascript_mutex);
624    jscoverage_instrument_js(id, input_stream, output_stream);    jscoverage_instrument_js(id, encoding, input_stream, output_stream);
625    pthread_mutex_unlock(&javascript_mutex);    UNLOCK(&javascript_mutex);
626    
627    const struct Resource * resource = get_resource("report.js");    const struct Resource * resource = get_resource("report.js");
628    Stream_write(output_stream, resource->data, resource->length);    Stream_write(output_stream, resource->data, resource->length);
# Line 722  Line 744 
744    
745      const char * request_uri = HTTPExchange_get_request_uri(client_exchange);      const char * request_uri = HTTPExchange_get_request_uri(client_exchange);
746      Stream * output_stream = Stream_new(0);      Stream * output_stream = Stream_new(0);
747      instrument_js(request_uri, input_stream, output_stream);      instrument_js(request_uri, jscoverage_encoding, input_stream, output_stream);
748    
749      /* send the headers to the client */      /* send the headers to the client */
750      for (const HTTPHeader * h = HTTPExchange_get_response_headers(server_exchange); h != NULL; h = h->next) {      for (const HTTPHeader * h = HTTPExchange_get_response_headers(server_exchange); h != NULL; h = h->next) {
# Line 808  Line 830 
830    }    }
831    
832    filesystem_path = make_path(document_root, abs_path + 1);    filesystem_path = make_path(document_root, abs_path + 1);
833      size_t filesystem_path_length = strlen(filesystem_path);
834      if (filesystem_path_length > 0 && filesystem_path[filesystem_path_length - 1] == '/') {
835        /* stat on Windows doesn't work with trailing slash */
836        filesystem_path[filesystem_path_length - 1] = '\0';
837      }
838    
839    struct stat buf;    struct stat buf;
840    if (stat(filesystem_path, &buf) == -1) {    if (stat(filesystem_path, &buf) == -1) {
# Line 816  Line 843 
843    }    }
844    
845    if (S_ISDIR(buf.st_mode)) {    if (S_ISDIR(buf.st_mode)) {
846      if (filesystem_path[strlen(filesystem_path) - 1] != '/') {      if (abs_path[strlen(abs_path) - 1] != '/') {
847        const char * request_uri = HTTPExchange_get_request_uri(exchange);        const char * request_uri = HTTPExchange_get_request_uri(exchange);
848        char * uri = xmalloc(strlen(request_uri) + 2);        char * uri = xmalloc(strlen(request_uri) + 2);
849        strcpy(uri, request_uri);        strcpy(uri, request_uri);
# Line 851  Line 878 
878      closedir(d);      closedir(d);
879    }    }
880    else if (S_ISREG(buf.st_mode)) {    else if (S_ISREG(buf.st_mode)) {
881      FILE * f = fopen(filesystem_path, "r");      FILE * f = fopen(filesystem_path, "rb");
882      if (f == NULL) {      if (f == NULL) {
883        send_response(exchange, 404, "Not found\n");        send_response(exchange, 404, "Not found\n");
884        goto done;        goto done;
# Line 859  Line 886 
886    
887      const char * content_type = get_content_type(filesystem_path);      const char * content_type = get_content_type(filesystem_path);
888      HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type);      HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type);
889      const char * request_uri = HTTPExchange_get_request_uri(exchange);      if (strcmp(content_type, "text/javascript") == 0 && ! is_no_instrument(abs_path)) {
     if (strcmp(content_type, "text/javascript") == 0 && ! is_no_instrument(request_uri)) {  
890        Stream * input_stream = Stream_new(0);        Stream * input_stream = Stream_new(0);
891        Stream * output_stream = Stream_new(0);        Stream * output_stream = Stream_new(0);
892    
893        Stream_write_file_contents(input_stream, f);        Stream_write_file_contents(input_stream, f);
894    
895        instrument_js(request_uri, input_stream, output_stream);        instrument_js(abs_path, jscoverage_encoding, input_stream, output_stream);
896    
897        if (HTTPExchange_write_response(exchange, output_stream->data, output_stream->length) != 0) {        if (HTTPExchange_write_response(exchange, output_stream->data, output_stream->length) != 0) {
898          HTTPServer_log_err("Warning: error writing to client\n");          HTTPServer_log_err("Warning: error writing to client\n");
# Line 952  Line 978 
978        document_root = argv[i] + 16;        document_root = argv[i] + 16;
979      }      }
980    
981        else if (strcmp(argv[i], "--encoding") == 0) {
982          i++;
983          if (i == argc) {
984            fatal("--encoding: option requires an argument");
985          }
986          jscoverage_encoding = argv[i];
987        }
988        else if (strncmp(argv[i], "--encoding=", 11) == 0) {
989          jscoverage_encoding = argv[i] + 11;
990        }
991    
992      else if (strcmp(argv[i], "--ip-address") == 0) {      else if (strcmp(argv[i], "--ip-address") == 0) {
993        i++;        i++;
994        if (i == argc) {        if (i == argc) {
# Line 1015  Line 1052 
1052    
1053    /* is this a shutdown? */    /* is this a shutdown? */
1054    if (shutdown) {    if (shutdown) {
1055    #ifdef __MINGW32__
1056        WSADATA data;
1057        if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
1058          fatal("could not start Winsock");
1059        }
1060    #endif
1061    
1062      /* INADDR_LOOPBACK */      /* INADDR_LOOPBACK */
1063      HTTPConnection * connection = HTTPConnection_new_client("127.0.0.1", numeric_port);      HTTPConnection * connection = HTTPConnection_new_client("127.0.0.1", numeric_port);
1064      if (connection == NULL) {      if (connection == NULL) {
# Line 1044  Line 1088 
1088    
1089    jscoverage_init();    jscoverage_init();
1090    
1091    #ifndef __MINGW32__
1092    /* handle broken pipe */    /* handle broken pipe */
1093    signal(SIGPIPE, SIG_IGN);    signal(SIGPIPE, SIG_IGN);
1094    #endif
1095    
1096    #ifdef __MINGW32__
1097    InitializeCriticalSection(&javascript_mutex);
1098    InitializeCriticalSection(&source_cache_mutex);
1099    #endif
1100    
1101    if (verbose) {    if (verbose) {
1102      printf("Starting HTTP server on %s:%lu\n", ip_address, numeric_port);      printf("Starting HTTP server on %s:%lu\n", ip_address, numeric_port);
1103        fflush(stdout);
1104    }    }
1105    HTTPServer_run(ip_address, (uint16_t) numeric_port, handler);    HTTPServer_run(ip_address, (uint16_t) numeric_port, handler);
1106    if (verbose) {    if (verbose) {
1107      printf("Stopping HTTP server\n");      printf("Stopping HTTP server\n");
1108        fflush(stdout);
1109    }    }
1110    
1111    jscoverage_cleanup();    jscoverage_cleanup();
1112    
1113    free(no_instrument);    free(no_instrument);
1114    
1115    pthread_mutex_lock(&source_cache_mutex);    LOCK(&source_cache_mutex);
1116    while (source_cache != NULL) {    while (source_cache != NULL) {
1117      SourceCache * p = source_cache;      SourceCache * p = source_cache;
1118      source_cache = source_cache->next;      source_cache = source_cache->next;
# Line 1067  Line 1120 
1120      Stream_delete(p->source);      Stream_delete(p->source);
1121      free(p);      free(p);
1122    }    }
1123    pthread_mutex_unlock(&source_cache_mutex);    UNLOCK(&source_cache_mutex);
1124    
1125    return 0;    return 0;
1126  }  }

Legend:
Removed from v.119  
changed lines
  Added in v.174

  ViewVC Help
Powered by ViewVC 1.1.24