|  | @@ -24,11 +24,18 @@
 | 
											
												
													
														|  |  #define USE_LUA
 |  |  #define USE_LUA
 | 
											
												
													
														|  |  #include "mongoose.c"
 |  |  #include "mongoose.c"
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#define FATAL(str, line) do {                     \
 |  | 
 | 
											
												
													
														|  | 
 |  | +static int s_total_tests = 0;
 | 
											
												
													
														|  | 
 |  | +static int s_failed_tests = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#define FAIL(str, line) do {                     \
 | 
											
												
													
														|  |    printf("Fail on line %d: [%s]\n", line, str);   \
 |  |    printf("Fail on line %d: [%s]\n", line, str);   \
 | 
											
												
													
														|  | -  abort();                                        \
 |  | 
 | 
											
												
													
														|  | 
 |  | +  s_failed_tests++; \
 | 
											
												
													
														|  | 
 |  | +} while (0)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#define ASSERT(expr) do { \
 | 
											
												
													
														|  | 
 |  | +  s_total_tests++; \
 | 
											
												
													
														|  | 
 |  | +  if (!(expr)) FAIL(#expr, __LINE__); \
 | 
											
												
													
														|  |  } while (0)
 |  |  } while (0)
 | 
											
												
													
														|  | -#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  #define HTTP_PORT "56789"
 |  |  #define HTTP_PORT "56789"
 | 
											
												
													
														|  |  #define HTTPS_PORT "56790"
 |  |  #define HTTPS_PORT "56790"
 | 
											
										
											
												
													
														|  | @@ -187,6 +194,7 @@ static char *read_file(const char *path, int *size) {
 | 
											
												
													
														|  |  static const char *fetch_data = "hello world!\n";
 |  |  static const char *fetch_data = "hello world!\n";
 | 
											
												
													
														|  |  static const char *inmemory_file_data = "hi there";
 |  |  static const char *inmemory_file_data = "hi there";
 | 
											
												
													
														|  |  static const char *upload_filename = "upload_test.txt";
 |  |  static const char *upload_filename = "upload_test.txt";
 | 
											
												
													
														|  | 
 |  | +static const char *upload_filename2 = "upload_test2.txt";
 | 
											
												
													
														|  |  static const char *upload_ok_message = "upload successful";
 |  |  static const char *upload_ok_message = "upload successful";
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static const char *open_file_cb(const struct mg_connection *conn,
 |  |  static const char *open_file_cb(const struct mg_connection *conn,
 | 
											
										
											
												
													
														|  | @@ -200,16 +208,39 @@ static const char *open_file_cb(const struct mg_connection *conn,
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static void upload_cb(struct mg_connection *conn, const char *path) {
 |  |  static void upload_cb(struct mg_connection *conn, const char *path) {
 | 
											
												
													
														|  | 
 |  | +  const struct mg_request_info *ri = mg_get_request_info(conn);
 | 
											
												
													
														|  |    char *p1, *p2;
 |  |    char *p1, *p2;
 | 
											
												
													
														|  |    int len1, len2;
 |  |    int len1, len2;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  ASSERT(!strcmp(path, "./upload_test.txt"));
 |  | 
 | 
											
												
													
														|  | -  ASSERT((p1 = read_file("mongoose.c", &len1)) != NULL);
 |  | 
 | 
											
												
													
														|  | -  ASSERT((p2 = read_file(path, &len2)) != NULL);
 |  | 
 | 
											
												
													
														|  | -  ASSERT(len1 == len2);
 |  | 
 | 
											
												
													
														|  | -  ASSERT(memcmp(p1, p2, len1) == 0);
 |  | 
 | 
											
												
													
														|  | -  free(p1), free(p2);
 |  | 
 | 
											
												
													
														|  | -  remove(upload_filename);
 |  | 
 | 
											
												
													
														|  | 
 |  | +  if (atoi(ri->query_string) == 1) {
 | 
											
												
													
														|  | 
 |  | +    ASSERT(!strcmp(path, "./upload_test.txt"));
 | 
											
												
													
														|  | 
 |  | +    ASSERT((p1 = read_file("mongoose.c", &len1)) != NULL);
 | 
											
												
													
														|  | 
 |  | +    ASSERT((p2 = read_file(path, &len2)) != NULL);
 | 
											
												
													
														|  | 
 |  | +    ASSERT(len1 == len2);
 | 
											
												
													
														|  | 
 |  | +    ASSERT(memcmp(p1, p2, len1) == 0);
 | 
											
												
													
														|  | 
 |  | +    free(p1), free(p2);
 | 
											
												
													
														|  | 
 |  | +    remove(upload_filename);
 | 
											
												
													
														|  | 
 |  | +  } else if (atoi(ri->query_string) == 2) {
 | 
											
												
													
														|  | 
 |  | +    if (!strcmp(path, "./upload_test.txt")) {
 | 
											
												
													
														|  | 
 |  | +      ASSERT((p1 = read_file("mongoose.h", &len1)) != NULL);
 | 
											
												
													
														|  | 
 |  | +      ASSERT((p2 = read_file(path, &len2)) != NULL);
 | 
											
												
													
														|  | 
 |  | +      ASSERT(len1 == len2);
 | 
											
												
													
														|  | 
 |  | +      ASSERT(memcmp(p1, p2, len1) == 0);
 | 
											
												
													
														|  | 
 |  | +      free(p1), free(p2);
 | 
											
												
													
														|  | 
 |  | +      remove(upload_filename);
 | 
											
												
													
														|  | 
 |  | +    } else if (!strcmp(path, "./upload_test2.txt")) {
 | 
											
												
													
														|  | 
 |  | +      ASSERT((p1 = read_file("README.md", &len1)) != NULL);
 | 
											
												
													
														|  | 
 |  | +      ASSERT((p2 = read_file(path, &len2)) != NULL);
 | 
											
												
													
														|  | 
 |  | +      ASSERT(len1 == len2);
 | 
											
												
													
														|  | 
 |  | +      ASSERT(memcmp(p1, p2, len1) == 0);
 | 
											
												
													
														|  | 
 |  | +      free(p1), free(p2);
 | 
											
												
													
														|  | 
 |  | +      remove(upload_filename);
 | 
											
												
													
														|  | 
 |  | +    } else {
 | 
											
												
													
														|  | 
 |  | +      ASSERT(0);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  } else {
 | 
											
												
													
														|  | 
 |  | +    ASSERT(0);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s",
 |  |    mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s",
 | 
											
												
													
														|  |              (int) strlen(upload_ok_message), upload_ok_message);
 |  |              (int) strlen(upload_ok_message), upload_ok_message);
 | 
											
										
											
												
													
														|  | @@ -227,7 +258,8 @@ static int begin_request_handler_cb(struct mg_connection *conn) {
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    if (!strcmp(ri->uri, "/upload")) {
 |  |    if (!strcmp(ri->uri, "/upload")) {
 | 
											
												
													
														|  | -    ASSERT(mg_upload(conn, ".") == 1);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    ASSERT(ri->query_string != NULL);
 | 
											
												
													
														|  | 
 |  | +    ASSERT(mg_upload(conn, ".") == atoi(ri->query_string));
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    return 0;
 |  |    return 0;
 | 
											
										
											
												
													
														|  | @@ -348,24 +380,27 @@ static void test_mg_upload(void) {
 | 
											
												
													
														|  |    static const char *boundary = "OOO___MY_BOUNDARY___OOO";
 |  |    static const char *boundary = "OOO___MY_BOUNDARY___OOO";
 | 
											
												
													
														|  |    struct mg_context *ctx;
 |  |    struct mg_context *ctx;
 | 
											
												
													
														|  |    struct mg_connection *conn;
 |  |    struct mg_connection *conn;
 | 
											
												
													
														|  | -  char ebuf[100], buf[20], *file_data, *post_data = NULL;
 |  | 
 | 
											
												
													
														|  | -  int file_len, post_data_len;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  char ebuf[100], buf[20], *file_data, *file2_data, *post_data;
 | 
											
												
													
														|  | 
 |  | +  int file_len, file2_len, post_data_len;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL);
 |  |    ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Upload one file
 | 
											
												
													
														|  |    ASSERT((file_data = read_file("mongoose.c", &file_len)) != NULL);
 |  |    ASSERT((file_data = read_file("mongoose.c", &file_len)) != NULL);
 | 
											
												
													
														|  | 
 |  | +  post_data = NULL;
 | 
											
												
													
														|  |    post_data_len = alloc_printf(&post_data, 0,
 |  |    post_data_len = alloc_printf(&post_data, 0,
 | 
											
												
													
														|  |                                         "--%s\r\n"
 |  |                                         "--%s\r\n"
 | 
											
												
													
														|  |                                         "Content-Disposition: form-data; "
 |  |                                         "Content-Disposition: form-data; "
 | 
											
												
													
														|  |                                         "name=\"file\"; "
 |  |                                         "name=\"file\"; "
 | 
											
												
													
														|  |                                         "filename=\"%s\"\r\n\r\n"
 |  |                                         "filename=\"%s\"\r\n\r\n"
 | 
											
												
													
														|  |                                         "%.*s\r\n"
 |  |                                         "%.*s\r\n"
 | 
											
												
													
														|  | -                                       "--%s\r\n",
 |  | 
 | 
											
												
													
														|  | 
 |  | +                                       "--%s--\r\n",
 | 
											
												
													
														|  |                                         boundary, upload_filename,
 |  |                                         boundary, upload_filename,
 | 
											
												
													
														|  |                                         file_len, file_data, boundary);
 |  |                                         file_len, file_data, boundary);
 | 
											
												
													
														|  |    ASSERT(post_data_len > 0);
 |  |    ASSERT(post_data_len > 0);
 | 
											
												
													
														|  |    ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1,
 |  |    ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1,
 | 
											
												
													
														|  |                               ebuf, sizeof(ebuf),
 |  |                               ebuf, sizeof(ebuf),
 | 
											
												
													
														|  | -                             "POST /upload HTTP/1.1\r\n"
 |  | 
 | 
											
												
													
														|  | 
 |  | +                             "POST /upload?1 HTTP/1.1\r\n"
 | 
											
												
													
														|  |                               "Content-Length: %d\r\n"
 |  |                               "Content-Length: %d\r\n"
 | 
											
												
													
														|  |                               "Content-Type: multipart/form-data; "
 |  |                               "Content-Type: multipart/form-data; "
 | 
											
												
													
														|  |                               "boundary=%s\r\n\r\n"
 |  |                               "boundary=%s\r\n\r\n"
 | 
											
										
											
												
													
														|  | @@ -375,6 +410,47 @@ static void test_mg_upload(void) {
 | 
											
												
													
														|  |    ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message));
 |  |    ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message));
 | 
											
												
													
														|  |    ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0);
 |  |    ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0);
 | 
											
												
													
														|  |    mg_close_connection(conn);
 |  |    mg_close_connection(conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Upload two files
 | 
											
												
													
														|  | 
 |  | +  ASSERT((file_data = read_file("mongoose.h", &file_len)) != NULL);
 | 
											
												
													
														|  | 
 |  | +  ASSERT((file2_data = read_file("README.md", &file2_len)) != NULL);
 | 
											
												
													
														|  | 
 |  | +  post_data = NULL;
 | 
											
												
													
														|  | 
 |  | +  post_data_len = alloc_printf(&post_data, 0,
 | 
											
												
													
														|  | 
 |  | +                               // First file
 | 
											
												
													
														|  | 
 |  | +                               "--%s\r\n"
 | 
											
												
													
														|  | 
 |  | +                               "Content-Disposition: form-data; "
 | 
											
												
													
														|  | 
 |  | +                               "name=\"file\"; "
 | 
											
												
													
														|  | 
 |  | +                               "filename=\"%s\"\r\n\r\n"
 | 
											
												
													
														|  | 
 |  | +                               "%.*s\r\n"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                               // Second file
 | 
											
												
													
														|  | 
 |  | +                               "--%s\r\n"
 | 
											
												
													
														|  | 
 |  | +                               "Content-Disposition: form-data; "
 | 
											
												
													
														|  | 
 |  | +                               "name=\"file\"; "
 | 
											
												
													
														|  | 
 |  | +                               "filename=\"%s\"\r\n\r\n"
 | 
											
												
													
														|  | 
 |  | +                               "%.*s\r\n"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                               // Final boundary
 | 
											
												
													
														|  | 
 |  | +                               "--%s--\r\n",
 | 
											
												
													
														|  | 
 |  | +                               boundary, upload_filename,
 | 
											
												
													
														|  | 
 |  | +                               file_len, file_data,
 | 
											
												
													
														|  | 
 |  | +                               boundary, upload_filename2,
 | 
											
												
													
														|  | 
 |  | +                               file2_len, file2_data,
 | 
											
												
													
														|  | 
 |  | +                               boundary);
 | 
											
												
													
														|  | 
 |  | +  ASSERT(post_data_len > 0);
 | 
											
												
													
														|  | 
 |  | +  ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1,
 | 
											
												
													
														|  | 
 |  | +                             ebuf, sizeof(ebuf),
 | 
											
												
													
														|  | 
 |  | +                             "POST /upload?2 HTTP/1.1\r\n"
 | 
											
												
													
														|  | 
 |  | +                             "Content-Length: %d\r\n"
 | 
											
												
													
														|  | 
 |  | +                             "Content-Type: multipart/form-data; "
 | 
											
												
													
														|  | 
 |  | +                             "boundary=%s\r\n\r\n"
 | 
											
												
													
														|  | 
 |  | +                             "%.*s", post_data_len, boundary,
 | 
											
												
													
														|  | 
 |  | +                             post_data_len, post_data)) != NULL);
 | 
											
												
													
														|  | 
 |  | +  free(file_data), free(file2_data), free(post_data);
 | 
											
												
													
														|  | 
 |  | +  ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message));
 | 
											
												
													
														|  | 
 |  | +  ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0);
 | 
											
												
													
														|  | 
 |  | +  mg_close_connection(conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    mg_stop(ctx);
 |  |    mg_stop(ctx);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -666,6 +742,7 @@ int __cdecl main(void) {
 | 
											
												
													
														|  |    test_lua();
 |  |    test_lua();
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  printf("%s\n", "PASSED");
 |  | 
 | 
											
												
													
														|  | -  return 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  printf("TOTAL TESTS: %d, FAILED: %d\n", s_total_tests, s_failed_tests);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return s_failed_tests == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
											
												
													
														|  |  }
 |  |  }
 |