/[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 134 by siliconforks, Thu Jun 19 05:54:02 2008 UTC revision 447 by siliconforks, Sun Aug 9 16:21:27 2009 UTC
# Line 1  Line 1 
1  /*  /*
2      jscoverage-server.c - JSCoverage server main routine      jscoverage-server.c - JSCoverage server main routine
3      Copyright (C) 2008 siliconforks.com      Copyright (C) 2008, 2009 siliconforks.com
4    
5      This program is free software; you can redistribute it and/or modify      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      it under the terms of the GNU General Public License as published by
# Line 22  Line 22 
22  #include <assert.h>  #include <assert.h>
23  #include <ctype.h>  #include <ctype.h>
24  #include <signal.h>  #include <signal.h>
25    #include <stdint.h>
26  #include <string.h>  #include <string.h>
27    
28  #include <dirent.h>  #include <dirent.h>
# Line 29  Line 30 
30  #include <pthread.h>  #include <pthread.h>
31  #endif  #endif
32    
33    #include "encoding.h"
34    #include "global.h"
35  #include "http-server.h"  #include "http-server.h"
36  #include "instrument-js.h"  #include "instrument-js.h"
37  #include "resource-manager.h"  #include "resource-manager.h"
38  #include "stream.h"  #include "stream.h"
39  #include "util.h"  #include "util.h"
40    
41    static const char * specified_encoding = NULL;
42    const char * jscoverage_encoding = "ISO-8859-1";
43    bool jscoverage_highlight = true;
44    
45  typedef struct SourceCache {  typedef struct SourceCache {
46    char * url;    char * url;
47    Stream * source;    uint16_t * characters;
48      size_t num_characters;
49    struct SourceCache * next;    struct SourceCache * next;
50  } SourceCache;  } SourceCache;
51    
# Line 78  Line 86 
86  #define UNLOCK pthread_mutex_unlock  #define UNLOCK pthread_mutex_unlock
87  #endif  #endif
88    
89  static Stream * find_cached_source(const char * url) {  static const SourceCache * find_cached_source(const char * url) {
90    Stream * result = NULL;    SourceCache * result = NULL;
91    LOCK(&source_cache_mutex);    LOCK(&source_cache_mutex);
92    for (SourceCache * p = source_cache; p != NULL; p = p->next) {    for (SourceCache * p = source_cache; p != NULL; p = p->next) {
93      if (strcmp(url, p->url) == 0) {      if (strcmp(url, p->url) == 0) {
94        result = p->source;        result = p;
95        break;        break;
96      }      }
97    }    }
# Line 91  Line 99 
99    return result;    return result;
100  }  }
101    
102  static void add_cached_source(const char * url, Stream * source) {  static void add_cached_source(const char * url, uint16_t * characters, size_t num_characters) {
103    SourceCache * new_source_cache = xmalloc(sizeof(SourceCache));    SourceCache * new_source_cache = xmalloc(sizeof(SourceCache));
104    new_source_cache->url = xstrdup(url);    new_source_cache->url = xstrdup(url);
105    new_source_cache->source = source;    new_source_cache->characters = characters;
106      new_source_cache->num_characters = num_characters;
107    LOCK(&source_cache_mutex);    LOCK(&source_cache_mutex);
108    new_source_cache->next = source_cache;    new_source_cache->next = source_cache;
109    source_cache = new_source_cache;    source_cache = new_source_cache;
110    UNLOCK(&source_cache_mutex);    UNLOCK(&source_cache_mutex);
111  }  }
112    
113  static int get(const char * url, Stream * stream) __attribute__((warn_unused_result));  static int get(const char * url, uint16_t ** characters, size_t * num_characters) __attribute__((warn_unused_result));
114    
115  static int get(const char * url, Stream * stream) {  static int get(const char * url, uint16_t ** characters, size_t * num_characters) {
116    char * host = NULL;    char * host = NULL;
117    uint16_t port;    uint16_t port;
118    char * abs_path = NULL;    char * abs_path = NULL;
119    char * query = NULL;    char * query = NULL;
120    HTTPConnection * connection = NULL;    HTTPConnection * connection = NULL;
121    HTTPExchange * exchange = NULL;    HTTPExchange * exchange = NULL;
122      Stream * stream = NULL;
123    
124    int result = URL_parse(url, &host, &port, &abs_path, &query);    int result = URL_parse(url, &host, &port, &abs_path, &query);
125    if (result != 0) {    if (result != 0) {
# Line 134  Line 144 
144      goto done;      goto done;
145    }    }
146    
147      stream = Stream_new(0);
148    result = HTTPExchange_read_entire_response_entity_body(exchange, stream);    result = HTTPExchange_read_entire_response_entity_body(exchange, stream);
149    if (result != 0) {    if (result != 0) {
150      goto done;      goto done;
151    }    }
152      char * encoding = HTTPMessage_get_charset(HTTPExchange_get_response_message(exchange));
153      if (encoding == NULL) {
154        encoding = xstrdup(jscoverage_encoding);
155      }
156      result = jscoverage_bytes_to_characters(encoding, stream->data, stream->length, characters, num_characters);
157      free(encoding);
158      if (result != 0) {
159        goto done;
160      }
161    
162    result = 0;    result = 0;
163    
164  done:  done:
165      if (stream != NULL) {
166        Stream_delete(stream);
167      }
168    if (exchange != NULL) {    if (exchange != NULL) {
169      HTTPExchange_delete(exchange);      HTTPExchange_delete(exchange);
170    }    }
# Line 215  Line 238 
238    return result;    return result;
239  }  }
240    
241    static unsigned int hex_value(char c) {
242      if ('0' <= c && c <= '9') {
243        return c - '0';
244      }
245      else if ('A' <= c && c <= 'F') {
246        return c - 'A' + 10;
247      }
248      else if ('a' <= c && c <= 'f') {
249        return c - 'a' + 10;
250      }
251      else {
252        return 0;
253      }
254    }
255    
256    static char * decode_uri_component(const char * s) {
257      size_t length = strlen(s);
258      char * result = xmalloc(length + 1);
259      char * p = result;
260      while (*s != '\0') {
261        if (*s == '%') {
262          if (s[1] == '\0' || s[2] == '\0') {
263            *p = '\0';
264            return result;
265          }
266          *p = hex_value(s[1]) * 16 + hex_value(s[2]);
267          s += 2;
268        }
269        else {
270          *p = *s;
271        }
272        p++;
273        s++;
274      }
275      *p = '\0';
276      return result;
277    }
278    
279  static const char * get_entity(char c) {  static const char * get_entity(char c) {
280    switch(c) {    switch(c) {
281    case '<':    case '<':
# Line 383  Line 444 
444      case '\t':      case '\t':
445        fputs("\\t", f);        fputs("\\t", f);
446        break;        break;
447        /* IE doesn't support this */
448        /*
449      case '\v':      case '\v':
450        fputs("\\v", f);        fputs("\\v", f);
451        break;        break;
452        */
453      case '"':      case '"':
454        fputs("\\\"", f);        fputs("\\\"", f);
455        break;        break;
# Line 400  Line 464 
464    putc('"', f);    putc('"', f);
465  }  }
466    
467    static void write_source(const char * id, const uint16_t * characters, size_t num_characters, FILE * f) {
468      Stream * output = Stream_new(num_characters);
469      jscoverage_write_source(id, characters, num_characters, output);
470      fwrite(output->data, 1, output->length, f);
471      Stream_delete(output);
472    }
473    
474  static void write_json_for_file(const FileCoverage * file_coverage, int i, void * p) {  static void write_json_for_file(const FileCoverage * file_coverage, int i, void * p) {
475    FILE * f = p;    FILE * f = p;
476    
# Line 410  Line 481 
481    write_js_quoted_string(f, file_coverage->id, strlen(file_coverage->id));    write_js_quoted_string(f, file_coverage->id, strlen(file_coverage->id));
482    
483    fputs(":{\"coverage\":[", f);    fputs(":{\"coverage\":[", f);
484    for (uint32_t i = 0; i <= file_coverage->num_lines; i++) {    for (uint32_t i = 0; i < file_coverage->num_coverage_lines; i++) {
485      if (i > 0) {      if (i > 0) {
486        putc(',', f);        putc(',', f);
487      }      }
488      int timesExecuted = file_coverage->lines[i];      int timesExecuted = file_coverage->coverage_lines[i];
489      if (timesExecuted < 0) {      if (timesExecuted < 0) {
490        fputs("null", f);        fputs("null", f);
491      }      }
# Line 423  Line 494 
494      }      }
495    }    }
496    fputs("],\"source\":", f);    fputs("],\"source\":", f);
497    if (file_coverage->source == NULL) {    if (file_coverage->source_lines == NULL) {
498      if (proxy) {      if (proxy) {
499        Stream * stream = find_cached_source(file_coverage->id);        const SourceCache * cached = find_cached_source(file_coverage->id);
500        if (stream == NULL) {        if (cached == NULL) {
501          stream = Stream_new(0);          uint16_t * characters;
502          if (get(file_coverage->id, stream) == 0) {          size_t num_characters;
503            write_js_quoted_string(f, stream->data, stream->length);          if (get(file_coverage->id, &characters, &num_characters) == 0) {
504            add_cached_source(file_coverage->id, stream);            write_source(file_coverage->id, characters, num_characters, f);
505              add_cached_source(file_coverage->id, characters, num_characters);
506          }          }
507          else {          else {
508            fputs("\"\"", f);            fputs("[]", f);
509            HTTPServer_log_err("Warning: cannot retrieve URL: %s\n", file_coverage->id);            HTTPServer_log_err("Warning: cannot retrieve URL: %s\n", file_coverage->id);
           Stream_delete(stream);  
510          }          }
511        }        }
512        else {        else {
513          write_js_quoted_string(f, stream->data, stream->length);          write_source(file_coverage->id, cached->characters, cached->num_characters, f);
514        }        }
515      }      }
516      else {      else {
517        /* check that the path begins with / */        /* check that the path begins with / */
518        if (file_coverage->id[0] == '/') {        if (file_coverage->id[0] == '/') {
519          char * source_path = make_path(document_root, file_coverage->id + 1);          char * decoded_path = decode_uri_component(file_coverage->id);
520            if (strstr(decoded_path, "..") != NULL) {
521              free(decoded_path);
522              fputs("[]", f);
523              HTTPServer_log_err("Warning: invalid source path: %s\n", file_coverage->id);
524              goto done;
525            }
526            char * source_path = make_path(document_root, decoded_path + 1);
527            free(decoded_path);
528          FILE * source_file = fopen(source_path, "rb");          FILE * source_file = fopen(source_path, "rb");
529          free(source_path);          free(source_path);
530          if (source_file == NULL) {          if (source_file == NULL) {
531            fputs("\"\"", f);            fputs("[]", f);
532            HTTPServer_log_err("Warning: cannot open file: %s\n", file_coverage->id);            HTTPServer_log_err("Warning: cannot open file: %s\n", file_coverage->id);
533          }          }
534          else {          else {
535            Stream * stream = Stream_new(0);            Stream * stream = Stream_new(0);
536            Stream_write_file_contents(stream, source_file);            Stream_write_file_contents(stream, source_file);
537            fclose(source_file);            fclose(source_file);
538            write_js_quoted_string(f, stream->data, stream->length);            uint16_t * characters;
539              size_t num_characters;
540              int result = jscoverage_bytes_to_characters(jscoverage_encoding, stream->data, stream->length, &characters, &num_characters);
541            Stream_delete(stream);            Stream_delete(stream);
542              if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) {
543                fputs("[]", f);
544                HTTPServer_log_err("Warning: encoding %s not supported\n", jscoverage_encoding);
545              }
546              else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) {
547                fputs("[]", f);
548                HTTPServer_log_err("Warning: error decoding %s in file %s\n", jscoverage_encoding, file_coverage->id);
549              }
550              else {
551                write_source(file_coverage->id, characters, num_characters, f);
552                free(characters);
553              }
554          }          }
555        }        }
556        else {        else {
557          /* path does not begin with / */          /* path does not begin with / */
558          fputs("\"\"", f);          fputs("[]", f);
559          HTTPServer_log_err("Warning: invalid source path: %s\n", file_coverage->id);          HTTPServer_log_err("Warning: invalid source path: %s\n", file_coverage->id);
560        }        }
561      }      }
562    }    }
563    else {    else {
564      write_js_quoted_string(f, file_coverage->source, strlen(file_coverage->source));      fputc('[', f);
565        for (uint32_t i = 0; i < file_coverage->num_source_lines; i++) {
566          if (i > 0) {
567            fputc(',', f);
568          }
569          char * source_line = file_coverage->source_lines[i];
570          write_js_quoted_string(f, source_line, strlen(source_line));
571        }
572        fputc(']', f);
573    }    }
574    done:
575    fputc('}', f);    fputc('}', f);
576  }  }
577    
# Line 477  Line 579 
579    
580  static int write_json(Coverage * coverage, const char * path) {  static int write_json(Coverage * coverage, const char * path) {
581    /* write the JSON */    /* write the JSON */
582    FILE * f = fopen(path, "w");    FILE * f = fopen(path, "wb");
583    if (f == NULL) {    if (f == NULL) {
584      return -1;      return -1;
585    }    }
# Line 525  Line 627 
627      }      }
628    
629      mkdir_if_necessary(report_directory);      mkdir_if_necessary(report_directory);
630      char * path = make_path(report_directory, "jscoverage.json");      char * current_report_directory;
631        if (str_starts_with(abs_path, "/jscoverage-store/") && abs_path[18] != '\0') {
632          char * dir = decode_uri_component(abs_path + 18);
633          current_report_directory = make_path(report_directory, dir);
634          free(dir);
635        }
636        else {
637          current_report_directory = xstrdup(report_directory);
638        }
639        mkdir_if_necessary(current_report_directory);
640        char * path = make_path(current_report_directory, "jscoverage.json");
641    
642      /* check if the JSON file exists */      /* check if the JSON file exists */
643      struct stat buf;      struct stat buf;
644      if (stat(path, &buf) == 0) {      if (stat(path, &buf) == 0) {
645        /* it exists: merge */        /* it exists: merge */
646        FILE * f = fopen(path, "r");        FILE * f = fopen(path, "rb");
647        if (f == NULL) {        if (f == NULL) {
648          result = 1;          result = 1;
649        }        }
# Line 542  Line 654 
654          }          }
655        }        }
656        if (result != 0) {        if (result != 0) {
657            free(current_report_directory);
658          free(path);          free(path);
659          Coverage_delete(coverage);          Coverage_delete(coverage);
660          send_response(exchange, 500, "Could not merge with existing coverage data\n");          send_response(exchange, 500, "Could not merge with existing coverage data\n");
# Line 553  Line 666 
666      free(path);      free(path);
667      Coverage_delete(coverage);      Coverage_delete(coverage);
668      if (result != 0) {      if (result != 0) {
669          free(current_report_directory);
670        send_response(exchange, 500, "Could not write coverage data\n");        send_response(exchange, 500, "Could not write coverage data\n");
671        return;        return;
672      }      }
673    
674      /* copy other files */      /* copy other files */
675      jscoverage_copy_resources(report_directory);      jscoverage_copy_resources(current_report_directory);
676      path = make_path(report_directory, "jscoverage.js");      path = make_path(current_report_directory, "jscoverage.js");
677        free(current_report_directory);
678      FILE * f = fopen(path, "ab");      FILE * f = fopen(path, "ab");
679      free(path);      free(path);
680      if (f == NULL) {      if (f == NULL) {
# Line 616  Line 731 
731    }    }
732  }  }
733    
734  static void instrument_js(const char * id, Stream * input_stream, Stream * output_stream) {  static void instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output_stream) {
   LOCK(&javascript_mutex);  
   jscoverage_instrument_js(id, input_stream, output_stream);  
   UNLOCK(&javascript_mutex);  
   
735    const struct Resource * resource = get_resource("report.js");    const struct Resource * resource = get_resource("report.js");
736    Stream_write(output_stream, resource->data, resource->length);    Stream_write(output_stream, resource->data, resource->length);
737    
738      LOCK(&javascript_mutex);
739      jscoverage_instrument_js(id, characters, num_characters, output_stream);
740      UNLOCK(&javascript_mutex);
741  }  }
742    
743  static bool is_hop_by_hop_header(const char * h) {  static bool is_hop_by_hop_header(const char * h) {
# Line 740  Line 855 
855      }      }
856    
857      const char * request_uri = HTTPExchange_get_request_uri(client_exchange);      const char * request_uri = HTTPExchange_get_request_uri(client_exchange);
858        char * encoding = HTTPMessage_get_charset(HTTPExchange_get_response_message(server_exchange));
859        if (encoding == NULL) {
860          encoding = xstrdup(jscoverage_encoding);
861        }
862        uint16_t * characters;
863        size_t num_characters;
864        int result = jscoverage_bytes_to_characters(encoding, input_stream->data, input_stream->length, &characters, &num_characters);
865        free(encoding);
866        Stream_delete(input_stream);
867        if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) {
868          send_response(client_exchange, 500, "Encoding not supported\n");
869          goto done;
870        }
871        else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) {
872          send_response(client_exchange, 502, "Error decoding response\n");
873          goto done;
874        }
875    
876      Stream * output_stream = Stream_new(0);      Stream * output_stream = Stream_new(0);
877      instrument_js(request_uri, input_stream, output_stream);      instrument_js(request_uri, characters, num_characters, output_stream);
878    
879      /* send the headers to the client */      /* send the headers to the client */
880      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) {
881        if (is_hop_by_hop_header(h->name) || strcasecmp(h->name, HTTP_CONTENT_LENGTH) == 0) {        if (is_hop_by_hop_header(h->name) || strcasecmp(h->name, HTTP_CONTENT_LENGTH) == 0) {
882          continue;          continue;
883        }        }
884          else if (strcasecmp(h->name, HTTP_CONTENT_TYPE) == 0) {
885            HTTPExchange_add_response_header(client_exchange, HTTP_CONTENT_TYPE, "text/javascript; charset=ISO-8859-1");
886            continue;
887          }
888        HTTPExchange_add_response_header(client_exchange, h->name, h->value);        HTTPExchange_add_response_header(client_exchange, h->name, h->value);
889      }      }
890      add_via_header(HTTPExchange_get_response_message(client_exchange), HTTPExchange_get_response_http_version(server_exchange));      add_via_header(HTTPExchange_get_response_message(client_exchange), HTTPExchange_get_response_http_version(server_exchange));
# Line 758  Line 895 
895        HTTPServer_log_err("Warning: error writing to client\n");        HTTPServer_log_err("Warning: error writing to client\n");
896      }      }
897    
898      /* input_stream goes on the cache */      /* characters go on the cache */
899      /*      /*
900      Stream_delete(input_stream);      free(characters);
901      */      */
902      Stream_delete(output_stream);      Stream_delete(output_stream);
903      add_cached_source(request_uri, input_stream);      add_cached_source(request_uri, characters, num_characters);
904    }    }
905    else {    else {
906      /* does not need instrumentation */      /* does not need instrumentation */
# Line 811  Line 948 
948    /* add the `Server' response-header (RFC 2616 14.38, 3.8) */    /* add the `Server' response-header (RFC 2616 14.38, 3.8) */
949    HTTPExchange_add_response_header(exchange, HTTP_SERVER, "jscoverage-server/" VERSION);    HTTPExchange_add_response_header(exchange, HTTP_SERVER, "jscoverage-server/" VERSION);
950    
951      char * decoded_path = NULL;
952    char * filesystem_path = NULL;    char * filesystem_path = NULL;
953    
954    const char * abs_path = HTTPExchange_get_abs_path(exchange);    const char * abs_path = HTTPExchange_get_abs_path(exchange);
955    assert(*abs_path != '\0');    assert(*abs_path != '\0');
956    
957    if (str_starts_with(abs_path, "/jscoverage")) {    decoded_path = decode_uri_component(abs_path);
958    
959      if (str_starts_with(decoded_path, "/jscoverage")) {
960      handle_jscoverage_request(exchange);      handle_jscoverage_request(exchange);
961      goto done;      goto done;
962    }    }
963    
964    if (strstr(abs_path, "..") != NULL) {    if (strstr(decoded_path, "..") != NULL) {
965      send_response(exchange, 403, "Forbidden\n");      send_response(exchange, 403, "Forbidden\n");
966      goto done;      goto done;
967    }    }
968    
969    filesystem_path = make_path(document_root, abs_path + 1);    filesystem_path = make_path(document_root, decoded_path + 1);
970    size_t filesystem_path_length = strlen(filesystem_path);    size_t filesystem_path_length = strlen(filesystem_path);
971    if (filesystem_path_length > 0 && filesystem_path[filesystem_path_length - 1] == '/') {    if (filesystem_path_length > 0 && filesystem_path[filesystem_path_length - 1] == '/') {
972      /* stat on Windows doesn't work with trailing slash */      /* stat on Windows doesn't work with trailing slash */
# Line 881  Line 1021 
1021        goto done;        goto done;
1022      }      }
1023    
1024        /*
1025        When do we send a charset with Content-Type?
1026        if Content-Type is "text" or "application"
1027          if instrumented JavaScript
1028            use Content-Type: application/javascript; charset=ISO-8859-1
1029          else if --encoding is given
1030            use that encoding
1031          else
1032            send no charset
1033        else
1034          send no charset
1035        */
1036      const char * content_type = get_content_type(filesystem_path);      const char * content_type = get_content_type(filesystem_path);
1037      HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type);      if (strcmp(content_type, "text/javascript") == 0 && ! is_no_instrument(abs_path)) {
1038      const char * request_uri = HTTPExchange_get_request_uri(exchange);        HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, "text/javascript; charset=ISO-8859-1");
     if (strcmp(content_type, "text/javascript") == 0 && ! is_no_instrument(request_uri)) {  
       Stream * input_stream = Stream_new(0);  
       Stream * output_stream = Stream_new(0);  
1039    
1040          Stream * input_stream = Stream_new(0);
1041        Stream_write_file_contents(input_stream, f);        Stream_write_file_contents(input_stream, f);
1042    
1043        instrument_js(request_uri, input_stream, output_stream);        uint16_t * characters;
1044          size_t num_characters;
1045          int result = jscoverage_bytes_to_characters(jscoverage_encoding, input_stream->data, input_stream->length, &characters, &num_characters);
1046          Stream_delete(input_stream);
1047    
1048          if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) {
1049            send_response(exchange, 500, "Encoding not supported\n");
1050            goto done;
1051          }
1052          else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) {
1053            send_response(exchange, 500, "Error decoding JavaScript file\n");
1054            goto done;
1055          }
1056    
1057          Stream * output_stream = Stream_new(0);
1058          instrument_js(abs_path, characters, num_characters, output_stream);
1059          free(characters);
1060    
1061        if (HTTPExchange_write_response(exchange, output_stream->data, output_stream->length) != 0) {        if (HTTPExchange_write_response(exchange, output_stream->data, output_stream->length) != 0) {
1062          HTTPServer_log_err("Warning: error writing to client\n");          HTTPServer_log_err("Warning: error writing to client\n");
1063        }        }
   
       Stream_delete(input_stream);  
1064        Stream_delete(output_stream);        Stream_delete(output_stream);
1065      }      }
1066      else {      else {
1067          /* send the Content-Type with charset if necessary */
1068          if (specified_encoding != NULL && (str_starts_with(content_type, "text/") || str_starts_with(content_type, "application/"))) {
1069            char * content_type_with_charset = NULL;
1070            xasprintf(&content_type_with_charset, "%s; charset=%s", content_type, specified_encoding);
1071            HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type_with_charset);
1072            free(content_type_with_charset);
1073          }
1074          else {
1075            HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type);
1076          }
1077    
1078        char buffer[8192];        char buffer[8192];
1079        size_t bytes_read;        size_t bytes_read;
1080        while ((bytes_read = fread(buffer, 1, 8192, f)) > 0) {        while ((bytes_read = fread(buffer, 1, 8192, f)) > 0) {
# Line 917  Line 1092 
1092    
1093  done:  done:
1094    free(filesystem_path);    free(filesystem_path);
1095      free(decoded_path);
1096  }  }
1097    
1098  static void handler(HTTPExchange * exchange) {  static void handler(HTTPExchange * exchange) {
# Line 947  Line 1123 
1123        exit(EXIT_SUCCESS);        exit(EXIT_SUCCESS);
1124      }      }
1125      else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {      else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
1126        printf("jscoverage-server %s\n", VERSION);        version();
       exit(EXIT_SUCCESS);  
1127      }      }
1128      else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {      else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
1129        verbose = 1;        verbose = 1;
# Line 957  Line 1132 
1132      else if (strcmp(argv[i], "--report-dir") == 0) {      else if (strcmp(argv[i], "--report-dir") == 0) {
1133        i++;        i++;
1134        if (i == argc) {        if (i == argc) {
1135          fatal("--report-dir: option requires an argument");          fatal_command_line("--report-dir: option requires an argument");
1136        }        }
1137        report_directory = argv[i];        report_directory = argv[i];
1138      }      }
# Line 968  Line 1143 
1143      else if (strcmp(argv[i], "--document-root") == 0) {      else if (strcmp(argv[i], "--document-root") == 0) {
1144        i++;        i++;
1145        if (i == argc) {        if (i == argc) {
1146          fatal("--document-root: option requires an argument");          fatal_command_line("--document-root: option requires an argument");
1147        }        }
1148        document_root = argv[i];        document_root = argv[i];
1149      }      }
# Line 976  Line 1151 
1151        document_root = argv[i] + 16;        document_root = argv[i] + 16;
1152      }      }
1153    
1154        else if (strcmp(argv[i], "--encoding") == 0) {
1155          i++;
1156          if (i == argc) {
1157            fatal_command_line("--encoding: option requires an argument");
1158          }
1159          jscoverage_encoding = argv[i];
1160          specified_encoding = jscoverage_encoding;
1161        }
1162        else if (strncmp(argv[i], "--encoding=", 11) == 0) {
1163          jscoverage_encoding = argv[i] + 11;
1164          specified_encoding = jscoverage_encoding;
1165        }
1166    
1167      else if (strcmp(argv[i], "--ip-address") == 0) {      else if (strcmp(argv[i], "--ip-address") == 0) {
1168        i++;        i++;
1169        if (i == argc) {        if (i == argc) {
1170          fatal("--ip-address: option requires an argument");          fatal_command_line("--ip-address: option requires an argument");
1171        }        }
1172        ip_address = argv[i];        ip_address = argv[i];
1173      }      }
# Line 987  Line 1175 
1175        ip_address = argv[i] + 13;        ip_address = argv[i] + 13;
1176      }      }
1177    
1178        else if (strcmp(argv[i], "--js-version") == 0) {
1179          i++;
1180          if (i == argc) {
1181            fatal_command_line("--js-version: option requires an argument");
1182          }
1183          jscoverage_set_js_version(argv[i]);
1184        }
1185        else if (strncmp(argv[i], "--js-version=", 13) == 0) {
1186          jscoverage_set_js_version(argv[i] + 13);
1187        }
1188    
1189        else if (strcmp(argv[i], "--no-highlight") == 0) {
1190          jscoverage_highlight = false;
1191        }
1192    
1193      else if (strcmp(argv[i], "--no-instrument") == 0) {      else if (strcmp(argv[i], "--no-instrument") == 0) {
1194        i++;        i++;
1195        if (i == argc) {        if (i == argc) {
1196          fatal("--no-instrument: option requires an argument");          fatal_command_line("--no-instrument: option requires an argument");
1197        }        }
1198        no_instrument[num_no_instrument] = argv[i];        no_instrument[num_no_instrument] = argv[i];
1199        num_no_instrument++;        num_no_instrument++;
# Line 1003  Line 1206 
1206      else if (strcmp(argv[i], "--port") == 0) {      else if (strcmp(argv[i], "--port") == 0) {
1207        i++;        i++;
1208        if (i == argc) {        if (i == argc) {
1209          fatal("--port: option requires an argument");          fatal_command_line("--port: option requires an argument");
1210        }        }
1211        port = argv[i];        port = argv[i];
1212      }      }
# Line 1020  Line 1223 
1223      }      }
1224    
1225      else if (strncmp(argv[i], "-", 1) == 0) {      else if (strncmp(argv[i], "-", 1) == 0) {
1226        fatal("unrecognized option `%s'", argv[i]);        fatal_command_line("unrecognized option `%s'", argv[i]);
1227      }      }
1228      else {      else {
1229        fatal("too many arguments");        fatal_command_line("too many arguments");
1230      }      }
1231    }    }
1232    
# Line 1031  Line 1234 
1234    char * end;    char * end;
1235    unsigned long numeric_port = strtoul(port, &end, 10);    unsigned long numeric_port = strtoul(port, &end, 10);
1236    if (*end != '\0') {    if (*end != '\0') {
1237      fatal("--port: option must be an integer");      fatal_command_line("--port: option must be an integer");
1238    }    }
1239    if (numeric_port > UINT16_MAX) {    if (numeric_port > UINT16_MAX) {
1240      fatal("--port: option must be 16 bits");      fatal_command_line("--port: option must be 16 bits");
1241    }    }
1242    
1243    /* is this a shutdown? */    /* is this a shutdown? */
# Line 1104  Line 1307 
1307      SourceCache * p = source_cache;      SourceCache * p = source_cache;
1308      source_cache = source_cache->next;      source_cache = source_cache->next;
1309      free(p->url);      free(p->url);
1310      Stream_delete(p->source);      free(p->characters);
1311      free(p);      free(p);
1312    }    }
1313    UNLOCK(&source_cache_mutex);    UNLOCK(&source_cache_mutex);

Legend:
Removed from v.134  
changed lines
  Added in v.447

  ViewVC Help
Powered by ViewVC 1.1.24