|  | @@ -7,6 +7,8 @@
 | 
											
												
													
														|  |  } while (0)
 |  |  } while (0)
 | 
											
												
													
														|  |  #define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
 |  |  #define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +#define UNUSED_PORT "33796"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  static void test_parse_http_request() {
 |  |  static void test_parse_http_request() {
 | 
											
												
													
														|  |    struct mg_request_info ri;
 |  |    struct mg_request_info ri;
 | 
											
												
													
														|  |    char req1[] = "GET / HTTP/1.1\r\n\r\n";
 |  |    char req1[] = "GET / HTTP/1.1\r\n\r\n";
 | 
											
										
											
												
													
														|  | @@ -126,15 +128,24 @@ static void test_remove_double_dots() {
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static const char *fetch_data = "hello world!\n";
 |  |  static const char *fetch_data = "hello world!\n";
 | 
											
												
													
														|  | -static void *event_handler(enum mg_event event,
 |  | 
 | 
											
												
													
														|  | -                           struct mg_connection *conn) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +static const char *inmemory_file_data = "hi there";
 | 
											
												
													
														|  | 
 |  | +static void *event_handler(enum mg_event event, struct mg_connection *conn) {
 | 
											
												
													
														|  |    const struct mg_request_info *request_info = mg_get_request_info(conn);
 |  |    const struct mg_request_info *request_info = mg_get_request_info(conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    if (event == MG_NEW_REQUEST && !strcmp(request_info->uri, "/data")) {
 |  |    if (event == MG_NEW_REQUEST && !strcmp(request_info->uri, "/data")) {
 | 
											
												
													
														|  |      mg_printf(conn, "HTTP/1.1 200 OK\r\n"
 |  |      mg_printf(conn, "HTTP/1.1 200 OK\r\n"
 | 
											
												
													
														|  |                "Content-Length: %d\r\n"
 |  |                "Content-Length: %d\r\n"
 | 
											
												
													
														|  |                "Content-Type: text/plain\r\n\r\n"
 |  |                "Content-Type: text/plain\r\n\r\n"
 | 
											
												
													
														|  |                "%s", (int) strlen(fetch_data), fetch_data);
 |  |                "%s", (int) strlen(fetch_data), fetch_data);
 | 
											
												
													
														|  |      return "";
 |  |      return "";
 | 
											
												
													
														|  | 
 |  | +  } else if (event == MG_OPEN_FILE) {
 | 
											
												
													
														|  | 
 |  | +    const char *path = request_info->ev_data;
 | 
											
												
													
														|  | 
 |  | +    printf("%s: [%s]\n", __func__, path);
 | 
											
												
													
														|  | 
 |  | +    if (strcmp(path, "./blah") == 0) {
 | 
											
												
													
														|  | 
 |  | +      mg_get_request_info(conn)->ev_data =
 | 
											
												
													
														|  | 
 |  | +        (void *) (int) strlen(inmemory_file_data);
 | 
											
												
													
														|  | 
 |  | +      return (void *) inmemory_file_data;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |    } else if (event == MG_EVENT_LOG) {
 |  |    } else if (event == MG_EVENT_LOG) {
 | 
											
												
													
														|  |      printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
 |  |      printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
										
											
												
													
														|  | @@ -145,33 +156,33 @@ static void *event_handler(enum mg_event event,
 | 
											
												
													
														|  |  static void test_mg_fetch(void) {
 |  |  static void test_mg_fetch(void) {
 | 
											
												
													
														|  |    static const char *options[] = {
 |  |    static const char *options[] = {
 | 
											
												
													
														|  |      "document_root", ".",
 |  |      "document_root", ".",
 | 
											
												
													
														|  | -    "listening_ports", "33796",
 |  | 
 | 
											
												
													
														|  | 
 |  | +    "listening_ports", UNUSED_PORT,
 | 
											
												
													
														|  |      NULL,
 |  |      NULL,
 | 
											
												
													
														|  |    };
 |  |    };
 | 
											
												
													
														|  |    char buf[2000], buf2[2000];
 |  |    char buf[2000], buf2[2000];
 | 
											
												
													
														|  | -  int length;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  int n, length;
 | 
											
												
													
														|  |    struct mg_context *ctx;
 |  |    struct mg_context *ctx;
 | 
											
												
													
														|  |    struct mg_request_info ri;
 |  |    struct mg_request_info ri;
 | 
											
												
													
														|  |    const char *tmp_file = "temporary_file_name_for_unit_test.txt";
 |  |    const char *tmp_file = "temporary_file_name_for_unit_test.txt";
 | 
											
												
													
														|  | -  struct mgstat st;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  struct file file;
 | 
											
												
													
														|  |    FILE *fp;
 |  |    FILE *fp;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    ASSERT((ctx = mg_start(event_handler, NULL, options)) != NULL);
 |  |    ASSERT((ctx = mg_start(event_handler, NULL, options)) != NULL);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Failed fetch, pass invalid URL
 |  |    // Failed fetch, pass invalid URL
 | 
											
												
													
														|  |    ASSERT(mg_fetch(ctx, "localhost", tmp_file, buf, sizeof(buf), &ri) == NULL);
 |  |    ASSERT(mg_fetch(ctx, "localhost", tmp_file, buf, sizeof(buf), &ri) == NULL);
 | 
											
												
													
														|  | -  ASSERT(mg_fetch(ctx, "localhost:33796", tmp_file,
 |  | 
 | 
											
												
													
														|  | 
 |  | +  ASSERT(mg_fetch(ctx, "localhost:" UNUSED_PORT, tmp_file,
 | 
											
												
													
														|  |                    buf, sizeof(buf), &ri) == NULL);
 |  |                    buf, sizeof(buf), &ri) == NULL);
 | 
											
												
													
														|  |    ASSERT(mg_fetch(ctx, "http://$$$.$$$", tmp_file,
 |  |    ASSERT(mg_fetch(ctx, "http://$$$.$$$", tmp_file,
 | 
											
												
													
														|  |                    buf, sizeof(buf), &ri) == NULL);
 |  |                    buf, sizeof(buf), &ri) == NULL);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Failed fetch, pass invalid file name
 |  |    // Failed fetch, pass invalid file name
 | 
											
												
													
														|  | -  ASSERT(mg_fetch(ctx, "http://localhost:33796/data",
 |  | 
 | 
											
												
													
														|  | 
 |  | +  ASSERT(mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/data",
 | 
											
												
													
														|  |                    "/this/file/must/not/exist/ever",
 |  |                    "/this/file/must/not/exist/ever",
 | 
											
												
													
														|  |                    buf, sizeof(buf), &ri) == NULL);
 |  |                    buf, sizeof(buf), &ri) == NULL);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Successful fetch
 |  |    // Successful fetch
 | 
											
												
													
														|  | -  ASSERT((fp = mg_fetch(ctx, "http://localhost:33796/data",
 |  | 
 | 
											
												
													
														|  | 
 |  | +  ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/data",
 | 
											
												
													
														|  |                          tmp_file, buf, sizeof(buf), &ri)) != NULL);
 |  |                          tmp_file, buf, sizeof(buf), &ri)) != NULL);
 | 
											
												
													
														|  |    ASSERT(ri.num_headers == 2);
 |  |    ASSERT(ri.num_headers == 2);
 | 
											
												
													
														|  |    ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
 |  |    ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
 | 
											
										
											
												
													
														|  | @@ -184,12 +195,31 @@ static void test_mg_fetch(void) {
 | 
											
												
													
														|  |    fclose(fp);
 |  |    fclose(fp);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Fetch big file, mongoose.c
 |  |    // Fetch big file, mongoose.c
 | 
											
												
													
														|  | -  ASSERT((fp = mg_fetch(ctx, "http://localhost:33796/mongoose.c",
 |  | 
 | 
											
												
													
														|  | 
 |  | +  ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/mongoose.c",
 | 
											
												
													
														|  |                          tmp_file, buf, sizeof(buf), &ri)) != NULL);
 |  |                          tmp_file, buf, sizeof(buf), &ri)) != NULL);
 | 
											
												
													
														|  | -  ASSERT(mg_stat("mongoose.c", &st) == 0);
 |  | 
 | 
											
												
													
														|  | -  ASSERT(st.size == ftell(fp));
 |  | 
 | 
											
												
													
														|  | 
 |  | +  ASSERT(mg_stat(fc(ctx), "mongoose.c", &file));
 | 
											
												
													
														|  | 
 |  | +  ASSERT(file.size == ftell(fp));
 | 
											
												
													
														|  |    ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
 |  |    ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +  // Fetch nonexistent file, /blah
 | 
											
												
													
														|  | 
 |  | +  ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/boo",
 | 
											
												
													
														|  | 
 |  | +                        tmp_file, buf, sizeof(buf), &ri)) != NULL);
 | 
											
												
													
														|  | 
 |  | +  ASSERT(!mg_strcasecmp(ri.uri, "404"));
 | 
											
												
													
														|  | 
 |  | +  fclose(fp);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Fetch existing inmemory file
 | 
											
												
													
														|  | 
 |  | +  ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/blah",
 | 
											
												
													
														|  | 
 |  | +                        tmp_file, buf, sizeof(buf), &ri)) != NULL);
 | 
											
												
													
														|  | 
 |  | +  ASSERT(!mg_strcasecmp(ri.uri, "200"));
 | 
											
												
													
														|  | 
 |  | +  n = ftell(fp);
 | 
											
												
													
														|  | 
 |  | +  fseek(fp, 0, SEEK_SET);
 | 
											
												
													
														|  | 
 |  | +  printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2);
 | 
											
												
													
														|  | 
 |  | +  n = fread(buf2, 1, n, fp);
 | 
											
												
													
														|  | 
 |  | +  printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2);
 | 
											
												
													
														|  | 
 |  | +  ASSERT((size_t) ftell(fp) == (size_t) strlen(inmemory_file_data));
 | 
											
												
													
														|  | 
 |  | +  ASSERT(!memcmp(inmemory_file_data, buf2, ftell(fp)));
 | 
											
												
													
														|  | 
 |  | +  fclose(fp);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    remove(tmp_file);
 |  |    remove(tmp_file);
 | 
											
												
													
														|  |    mg_stop(ctx);
 |  |    mg_stop(ctx);
 | 
											
												
													
														|  |  }
 |  |  }
 |