|  | @@ -2797,6 +2797,8 @@ START_TEST(test_http_auth)
 | 
											
												
													
														|  |  		"static_file_max_age",
 |  |  		"static_file_max_age",
 | 
											
												
													
														|  |  		"0",
 |  |  		"0",
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  | 
 |  | +		"put_delete_auth_file",
 | 
											
												
													
														|  | 
 |  | +		"put_delete_auth_file.csv",
 | 
											
												
													
														|  |  		NULL,
 |  |  		NULL,
 | 
											
												
													
														|  |  	};
 |  |  	};
 | 
											
												
													
														|  |  	struct mg_context *ctx;
 |  |  	struct mg_context *ctx;
 | 
											
										
											
												
													
														|  | @@ -2843,6 +2845,13 @@ START_TEST(test_http_auth)
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	(void)remove(passwd_file);
 |  |  	(void)remove(passwd_file);
 | 
											
												
													
														|  | 
 |  | +	(void)remove("put_delete_auth_file.csv");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	client_res = mg_modify_passwords_file("put_delete_auth_file.csv",
 | 
											
												
													
														|  | 
 |  | +	                                      domain,
 | 
											
												
													
														|  | 
 |  | +	                                      "admin",
 | 
											
												
													
														|  | 
 |  | +	                                      "adminpass");
 | 
											
												
													
														|  | 
 |  | +	ck_assert_int_eq(client_res, 1);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	/* Read file before a .htpasswd file has been created */
 |  |  	/* Read file before a .htpasswd file has been created */
 | 
											
												
													
														|  |  	memset(client_err, 0, sizeof(client_err));
 |  |  	memset(client_err, 0, sizeof(client_err));
 | 
											
										
											
												
													
														|  | @@ -2959,7 +2968,7 @@ START_TEST(test_http_auth)
 | 
											
												
													
														|  |  	                    NULL);
 |  |  	                    NULL);
 | 
											
												
													
														|  |  	ck_assert_ptr_eq(HA_md5_ret, HA_md5_buf);
 |  |  	ck_assert_ptr_eq(HA_md5_ret, HA_md5_buf);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	/* Retry with Authorization */
 |  | 
 | 
											
												
													
														|  | 
 |  | +	/* Retry with authorization */
 | 
											
												
													
														|  |  	memset(client_err, 0, sizeof(client_err));
 |  |  	memset(client_err, 0, sizeof(client_err));
 | 
											
												
													
														|  |  	client_conn =
 |  |  	client_conn =
 | 
											
												
													
														|  |  	    mg_connect_client("127.0.0.1", 8080, 0, client_err, sizeof(client_err));
 |  |  	    mg_connect_client("127.0.0.1", 8080, 0, client_err, sizeof(client_err));
 | 
											
										
											
												
													
														|  | @@ -2999,6 +3008,41 @@ START_TEST(test_http_auth)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	test_sleep(1);
 |  |  	test_sleep(1);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +	/* Retry DELETE with authorization of a user not authorized for DELETE */
 | 
											
												
													
														|  | 
 |  | +	memset(client_err, 0, sizeof(client_err));
 | 
											
												
													
														|  | 
 |  | +	client_conn =
 | 
											
												
													
														|  | 
 |  | +	    mg_connect_client("127.0.0.1", 8080, 0, client_err, sizeof(client_err));
 | 
											
												
													
														|  | 
 |  | +	ck_assert(client_conn != NULL);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_str_eq(client_err, "");
 | 
											
												
													
														|  | 
 |  | +	mg_printf(client_conn, "DELETE /%s HTTP/1.0\r\n", test_file);
 | 
											
												
													
														|  | 
 |  | +	mg_printf(client_conn,
 | 
											
												
													
														|  | 
 |  | +	          "Authorization: Digest "
 | 
											
												
													
														|  | 
 |  | +	          "username=\"%s\", "
 | 
											
												
													
														|  | 
 |  | +	          "realm=\"%s\", "
 | 
											
												
													
														|  | 
 |  | +	          "nonce=\"%s\", "
 | 
											
												
													
														|  | 
 |  | +	          "uri=\"/%s\", "
 | 
											
												
													
														|  | 
 |  | +	          "qop=auth, "
 | 
											
												
													
														|  | 
 |  | +	          "nc=%s, "
 | 
											
												
													
														|  | 
 |  | +	          "cnonce=\"%s\", "
 | 
											
												
													
														|  | 
 |  | +	          "response=\"%s\"\r\n\r\n",
 | 
											
												
													
														|  | 
 |  | +	          "user",
 | 
											
												
													
														|  | 
 |  | +	          domain,
 | 
											
												
													
														|  | 
 |  | +	          nonce,
 | 
											
												
													
														|  | 
 |  | +	          test_file,
 | 
											
												
													
														|  | 
 |  | +	          nc,
 | 
											
												
													
														|  | 
 |  | +	          cnonce,
 | 
											
												
													
														|  | 
 |  | +	          HA_md5_buf);
 | 
											
												
													
														|  | 
 |  | +	client_res =
 | 
											
												
													
														|  | 
 |  | +	    mg_get_response(client_conn, client_err, sizeof(client_err), 10000);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_int_ge(client_res, 0);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_str_eq(client_err, "");
 | 
											
												
													
														|  | 
 |  | +	client_ri = mg_get_request_info(client_conn);
 | 
											
												
													
														|  | 
 |  | +	ck_assert(client_ri != NULL);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	ck_assert_str_eq(client_ri->local_uri, "401");
 | 
											
												
													
														|  | 
 |  | +	mg_close_connection(client_conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	test_sleep(1);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	/* Remove the user from the .htpasswd file again */
 |  |  	/* Remove the user from the .htpasswd file again */
 | 
											
												
													
														|  |  	client_res = mg_modify_passwords_file(passwd_file, domain, "user", NULL);
 |  |  	client_res = mg_modify_passwords_file(passwd_file, domain, "user", NULL);
 | 
											
										
											
												
													
														|  | @@ -3060,6 +3104,7 @@ START_TEST(test_http_auth)
 | 
											
												
													
														|  |  	test_mg_stop(ctx);
 |  |  	test_mg_stop(ctx);
 | 
											
												
													
														|  |  	(void)remove(test_file);
 |  |  	(void)remove(test_file);
 | 
											
												
													
														|  |  	(void)remove(passwd_file);
 |  |  	(void)remove(passwd_file);
 | 
											
												
													
														|  | 
 |  | +	(void)remove("put_delete_auth_file.csv");
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -3864,6 +3909,153 @@ START_TEST(test_large_file)
 | 
											
												
													
														|  |  END_TEST
 |  |  END_TEST
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +static int test_mg_store_body_con_len = 20000;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static int
 | 
											
												
													
														|  | 
 |  | +test_mg_store_body_put_delete_handler(struct mg_connection *conn, void *_)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	char path[4096] = {0};
 | 
											
												
													
														|  | 
 |  | +	const struct mg_request_info *info = mg_get_request_info(conn);
 | 
											
												
													
														|  | 
 |  | +	long long rc;
 | 
											
												
													
														|  | 
 |  | +	int cerrno;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	sprintf(path, "./%s", info->local_uri);
 | 
											
												
													
														|  | 
 |  | +	rc = mg_store_body(conn, path);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	ck_assert_int_eq(test_mg_store_body_con_len, rc);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (rc < 0) {
 | 
											
												
													
														|  | 
 |  | +		cerrno = errno;
 | 
											
												
													
														|  | 
 |  | +		mg_printf(conn,
 | 
											
												
													
														|  | 
 |  | +		          "HTTP/1.1 500 Internal Server Error\r\n"
 | 
											
												
													
														|  | 
 |  | +		          "Content-Type:text/plain;charset=UTF-8\r\n"
 | 
											
												
													
														|  | 
 |  | +		          "Connection:close\r\n\r\n"
 | 
											
												
													
														|  | 
 |  | +		          "%s (mg: %lld, errno: %d) - %s\n",
 | 
											
												
													
														|  | 
 |  | +		          path,
 | 
											
												
													
														|  | 
 |  | +		          rc,
 | 
											
												
													
														|  | 
 |  | +		          cerrno,
 | 
											
												
													
														|  | 
 |  | +		          strerror(cerrno));
 | 
											
												
													
														|  | 
 |  | +		mg_close_connection(conn);
 | 
											
												
													
														|  | 
 |  | +		return 500;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	mg_printf(conn,
 | 
											
												
													
														|  | 
 |  | +	          "HTTP/1.1 200 OK\r\n"
 | 
											
												
													
														|  | 
 |  | +	          "Content-Type:text/plain;charset=UTF-8\r\n"
 | 
											
												
													
														|  | 
 |  | +	          "Connection:close\r\n\r\n"
 | 
											
												
													
														|  | 
 |  | +	          "%s OK (%lld bytes saved)\n",
 | 
											
												
													
														|  | 
 |  | +	          path,
 | 
											
												
													
														|  | 
 |  | +	          rc);
 | 
											
												
													
														|  | 
 |  | +	mg_close_connection(conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	return 200;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static int
 | 
											
												
													
														|  | 
 |  | +test_mg_store_body_begin_request_callback(struct mg_connection *conn)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	const struct mg_request_info *info = mg_get_request_info(conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (strcmp(info->request_method, "PUT") == 0
 | 
											
												
													
														|  | 
 |  | +	    || strcmp(info->request_method, "DELETE") == 0) {
 | 
											
												
													
														|  | 
 |  | +		return test_mg_store_body_put_delete_handler(conn, NULL);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	return 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +START_TEST(test_mg_store_body)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	/* Client data */
 | 
											
												
													
														|  | 
 |  | +	char client_err_buf[256];
 | 
											
												
													
														|  | 
 |  | +	char client_data_buf[1024];
 | 
											
												
													
														|  | 
 |  | +	struct mg_connection *client;
 | 
											
												
													
														|  | 
 |  | +	const struct mg_request_info *client_ri;
 | 
											
												
													
														|  | 
 |  | +	int r;
 | 
											
												
													
														|  | 
 |  | +	char check_data[256];
 | 
											
												
													
														|  | 
 |  | +	char *check_ptr;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Server context handle */
 | 
											
												
													
														|  | 
 |  | +	struct mg_context *ctx;
 | 
											
												
													
														|  | 
 |  | +	struct mg_callbacks callbacks = {0};
 | 
											
												
													
														|  | 
 |  | +	const char *options[] = {"document_root",
 | 
											
												
													
														|  | 
 |  | +	                         "./",
 | 
											
												
													
														|  | 
 |  | +	                         "static_file_max_age",
 | 
											
												
													
														|  | 
 |  | +	                         "0",
 | 
											
												
													
														|  | 
 |  | +	                         "listening_ports",
 | 
											
												
													
														|  | 
 |  | +	                         "127.0.0.1:9001",
 | 
											
												
													
														|  | 
 |  | +	                         "num_threads",
 | 
											
												
													
														|  | 
 |  | +	                         "1",
 | 
											
												
													
														|  | 
 |  | +	                         NULL};
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	callbacks.begin_request = test_mg_store_body_begin_request_callback;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Initialize the library */
 | 
											
												
													
														|  | 
 |  | +	mg_init_library(0);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Start the server */
 | 
											
												
													
														|  | 
 |  | +	ctx = mg_start(&callbacks, NULL, options);
 | 
											
												
													
														|  | 
 |  | +	ck_assert(ctx != NULL);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Run the server for 15 seconds */
 | 
											
												
													
														|  | 
 |  | +	test_sleep(15);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Call a test client */
 | 
											
												
													
														|  | 
 |  | +	client = mg_connect_client(
 | 
											
												
													
														|  | 
 |  | +	    "127.0.0.1", 9001, 0, client_err_buf, sizeof(client_err_buf));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	ck_assert(client != NULL);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_str_eq(client_err_buf, "");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	mg_printf(client,
 | 
											
												
													
														|  | 
 |  | +	          "PUT /%s HTTP/1.0\r\nContent-Length: %i\r\n\r\n",
 | 
											
												
													
														|  | 
 |  | +	          "test_file_name.txt",
 | 
											
												
													
														|  | 
 |  | +	          test_mg_store_body_con_len);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	r = 0;
 | 
											
												
													
														|  | 
 |  | +	while (r < test_mg_store_body_con_len) {
 | 
											
												
													
														|  | 
 |  | +		int l = mg_write(client, "1234567890", 10);
 | 
											
												
													
														|  | 
 |  | +		ck_assert_int_eq(l, 10);
 | 
											
												
													
														|  | 
 |  | +		r += 10;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	r = mg_get_response(client, client_err_buf, sizeof(client_err_buf), 10000);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_int_ge(r, 0);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_str_eq(client_err_buf, "");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	client_ri = mg_get_request_info(client);
 | 
											
												
													
														|  | 
 |  | +	ck_assert(client_ri != NULL);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Response must be 200 OK  */
 | 
											
												
													
														|  | 
 |  | +	ck_assert_ptr_ne(client_ri->request_uri, NULL);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_str_eq(client_ri->request_uri, "200");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Nothing left to read */
 | 
											
												
													
														|  | 
 |  | +	r = mg_read(client, client_data_buf, sizeof(client_data_buf) - 1);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_int_eq(r, 0);
 | 
											
												
													
														|  | 
 |  | +	client_data_buf[r] = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	sprintf(check_data, "(%i bytes saved)", test_mg_store_body_con_len);
 | 
											
												
													
														|  | 
 |  | +	check_ptr = strstr(client_data_buf, check_data);
 | 
											
												
													
														|  | 
 |  | +	ck_assert_ptr_ne(check_ptr, NULL);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	mg_close_connection(client);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Run the server for 5 seconds */
 | 
											
												
													
														|  | 
 |  | +	test_sleep(5);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Stop the server */
 | 
											
												
													
														|  | 
 |  | +	test_mg_stop(ctx);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	/* Un-initialize the library */
 | 
											
												
													
														|  | 
 |  | +	mg_exit_library();
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +END_TEST
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  #if defined(MG_USE_OPEN_FILE) && !defined(NO_FILES)
 |  |  #if defined(MG_USE_OPEN_FILE) && !defined(NO_FILES)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  #define FILE_IN_MEM_SIZE (1024 * 100)
 |  |  #define FILE_IN_MEM_SIZE (1024 * 100)
 | 
											
										
											
												
													
														|  | @@ -3906,7 +4098,6 @@ START_TEST(test_file_in_memory)
 | 
											
												
													
														|  |  	int64_t data_read;
 |  |  	int64_t data_read;
 | 
											
												
													
														|  |  	int r, i;
 |  |  	int r, i;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  	/* Prepare test data */
 |  |  	/* Prepare test data */
 | 
											
												
													
														|  |  	file_in_mem_data = (char *)malloc(FILE_IN_MEM_SIZE);
 |  |  	file_in_mem_data = (char *)malloc(FILE_IN_MEM_SIZE);
 | 
											
												
													
														|  |  	ck_assert_ptr_ne(file_in_mem_data, NULL);
 |  |  	ck_assert_ptr_ne(file_in_mem_data, NULL);
 | 
											
										
											
												
													
														|  | @@ -3914,7 +4105,6 @@ START_TEST(test_file_in_memory)
 | 
											
												
													
														|  |  		file_in_mem_data[r] = (char)(r);
 |  |  		file_in_mem_data[r] = (char)(r);
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  	/* Set options and start server */
 |  |  	/* Set options and start server */
 | 
											
												
													
														|  |  	OPTIONS[opt_cnt++] = "document_root";
 |  |  	OPTIONS[opt_cnt++] = "document_root";
 | 
											
												
													
														|  |  	OPTIONS[opt_cnt++] = ".";
 |  |  	OPTIONS[opt_cnt++] = ".";
 | 
											
										
											
												
													
														|  | @@ -4188,7 +4378,8 @@ make_public_server_suite(void)
 | 
											
												
													
														|  |  	suite_add_tcase(suite, tcase_serverandclienttls);
 |  |  	suite_add_tcase(suite, tcase_serverandclienttls);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	tcase_add_test(tcase_serverrequests, test_request_handlers);
 |  |  	tcase_add_test(tcase_serverrequests, test_request_handlers);
 | 
											
												
													
														|  | -	tcase_set_timeout(tcase_serverrequests, 120);
 |  | 
 | 
											
												
													
														|  | 
 |  | +	tcase_add_test(tcase_serverrequests, test_mg_store_body);
 | 
											
												
													
														|  | 
 |  | +	tcase_set_timeout(tcase_serverrequests, 180);
 | 
											
												
													
														|  |  	suite_add_tcase(suite, tcase_serverrequests);
 |  |  	suite_add_tcase(suite, tcase_serverrequests);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	tcase_add_test(tcase_handle_form, test_handle_form);
 |  |  	tcase_add_test(tcase_handle_form, test_handle_form);
 | 
											
										
											
												
													
														|  | @@ -4247,6 +4438,7 @@ MAIN_PUBLIC_SERVER(void)
 | 
											
												
													
														|  |  	test_mg_start_stop_http_server(0);
 |  |  	test_mg_start_stop_http_server(0);
 | 
											
												
													
														|  |  	test_mg_start_stop_https_server(0);
 |  |  	test_mg_start_stop_https_server(0);
 | 
											
												
													
														|  |  	test_request_handlers(0);
 |  |  	test_request_handlers(0);
 | 
											
												
													
														|  | 
 |  | +	test_mg_store_body(0);
 | 
											
												
													
														|  |  	test_mg_server_and_client_tls(0);
 |  |  	test_mg_server_and_client_tls(0);
 | 
											
												
													
														|  |  	test_handle_form(0);
 |  |  	test_handle_form(0);
 | 
											
												
													
														|  |  	test_http_auth(0);
 |  |  	test_http_auth(0);
 |