|  | @@ -1,409 +1,411 @@
 | 
	
		
			
				|  |  | -#include "civetweb.h"
 | 
	
		
			
				|  |  | -#include <errno.h>
 | 
	
		
			
				|  |  | -#include <stdint.h>
 | 
	
		
			
				|  |  | -#include <stdlib.h>
 | 
	
		
			
				|  |  | -#include <string.h>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if defined(_WIN32)
 | 
	
		
			
				|  |  | -#error "Currently not supported"
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#include <unistd.h>
 | 
	
		
			
				|  |  | -#define test_sleep(x) (sleep(x))
 | 
	
		
			
				|  |  | -#include <arpa/inet.h>
 | 
	
		
			
				|  |  | -#include <netinet/in.h>
 | 
	
		
			
				|  |  | -#include <netinet/ip.h>
 | 
	
		
			
				|  |  | -#include <pthread.h>
 | 
	
		
			
				|  |  | -#include <sys/socket.h>
 | 
	
		
			
				|  |  | -#include <sys/types.h>
 | 
	
		
			
				|  |  | -typedef int SOCKET;
 | 
	
		
			
				|  |  | -#define closesocket(a) (close(a))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static uint64_t call_count = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static struct mg_context *ctx;
 | 
	
		
			
				|  |  | -static const char *OPTIONS[] = {"listening_ports",
 | 
	
		
			
				|  |  | -                                "8080,8443s",
 | 
	
		
			
				|  |  | -                                "document_root",
 | 
	
		
			
				|  |  | -                                "fuzztest/docroot",
 | 
	
		
			
				|  |  | -                                "ssl_certificate",
 | 
	
		
			
				|  |  | -                                "resources/cert/server.pem",
 | 
	
		
			
				|  |  | -                                NULL,
 | 
	
		
			
				|  |  | -                                NULL};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void
 | 
	
		
			
				|  |  | -init_civetweb(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	struct mg_callbacks callbacks;
 | 
	
		
			
				|  |  | -	memset(&callbacks, 0, sizeof(callbacks));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	ctx = mg_start(&callbacks, 0, OPTIONS);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if (!ctx) {
 | 
	
		
			
				|  |  | -		fprintf(stderr, "\nCivetWeb test server failed to start\n");
 | 
	
		
			
				|  |  | -		abort();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* Give server 5 seconds to start, before flooding with requests.
 | 
	
		
			
				|  |  | -	 * Don't know if this is required for fuzz-tests, but it was helpful
 | 
	
		
			
				|  |  | -	 * when testing starting/stopping the server multiple times in test
 | 
	
		
			
				|  |  | -	 * container environments. */
 | 
	
		
			
				|  |  | -	test_sleep(5);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -struct tcp_func_prm {
 | 
	
		
			
				|  |  | -	SOCKET sock;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -struct tRESPONSE {
 | 
	
		
			
				|  |  | -	char data[4096];
 | 
	
		
			
				|  |  | -	size_t size;
 | 
	
		
			
				|  |  | -} RESPONSE;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void *
 | 
	
		
			
				|  |  | -tcp_func(void *arg)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	char req[1024 * 16];
 | 
	
		
			
				|  |  | -	struct tcp_func_prm *ptcp_func_prm = (struct tcp_func_prm *)arg;
 | 
	
		
			
				|  |  | -	SOCKET svr = ptcp_func_prm->sock;
 | 
	
		
			
				|  |  | -	printf("Server ready, sock %i\n", svr);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -next_request : {
 | 
	
		
			
				|  |  | -	struct sockaddr_in cliadr;
 | 
	
		
			
				|  |  | -	socklen_t adrlen = sizeof(cliadr);
 | 
	
		
			
				|  |  | -	int buf_filled = 0;
 | 
	
		
			
				|  |  | -	int req_ready = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	memset(&cliadr, 0, sizeof(cliadr));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	SOCKET cli = accept(svr, (struct sockaddr *)&cliadr, &adrlen);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if (cli == -1) {
 | 
	
		
			
				|  |  | -		int er = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Accept failed [%s]\n", strerror(er));
 | 
	
		
			
				|  |  | -		test_sleep(1);
 | 
	
		
			
				|  |  | -		goto next_request;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* Read request */
 | 
	
		
			
				|  |  | -	do {
 | 
	
		
			
				|  |  | -		int r = recv(cli, req + buf_filled, sizeof(req) - buf_filled - 1, 0);
 | 
	
		
			
				|  |  | -		if (r > 0) {
 | 
	
		
			
				|  |  | -			buf_filled += r;
 | 
	
		
			
				|  |  | -			req[buf_filled] = 0;
 | 
	
		
			
				|  |  | -			if (strstr(req, "\r\n\r\n") != NULL) {
 | 
	
		
			
				|  |  | -				req_ready = 1;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			/* some error */
 | 
	
		
			
				|  |  | -			int er = errno;
 | 
	
		
			
				|  |  | -			fprintf(stderr, "Error: Recv failed [%s]\n", strerror(er));
 | 
	
		
			
				|  |  | -			test_sleep(1);
 | 
	
		
			
				|  |  | -			goto next_request;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	} while (!req_ready);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* Request is complete here.
 | 
	
		
			
				|  |  | -	 * Now send response */
 | 
	
		
			
				|  |  | -	send(cli, RESPONSE.data, RESPONSE.size, MSG_NOSIGNAL);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* Close connection. */
 | 
	
		
			
				|  |  | -	shutdown(cli, SHUT_RDWR);
 | 
	
		
			
				|  |  | -	closesocket(cli);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* done */
 | 
	
		
			
				|  |  | -	goto next_request;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	free(arg);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void
 | 
	
		
			
				|  |  | -init_tcp(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	int r;
 | 
	
		
			
				|  |  | -	SOCKET sock = socket(AF_INET, SOCK_STREAM, 6);
 | 
	
		
			
				|  |  | -	if (sock == -1) {
 | 
	
		
			
				|  |  | -		r = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Cannot create socket [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | -		abort();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	struct sockaddr_in sin;
 | 
	
		
			
				|  |  | -	memset(&sin, 0, sizeof(sin));
 | 
	
		
			
				|  |  | -	sin.sin_family = AF_INET;
 | 
	
		
			
				|  |  | -	sin.sin_addr.s_addr = inet_addr("127.0.0.1");
 | 
	
		
			
				|  |  | -	sin.sin_port = htons(8080);
 | 
	
		
			
				|  |  | -	r = bind(sock, (struct sockaddr *)&sin, sizeof(sin));
 | 
	
		
			
				|  |  | -	if (r != 0) {
 | 
	
		
			
				|  |  | -		r = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Cannot bind [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | -		closesocket(sock);
 | 
	
		
			
				|  |  | -		abort();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	r = listen(sock, 128);
 | 
	
		
			
				|  |  | -	if (r != 0) {
 | 
	
		
			
				|  |  | -		r = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Cannot listen [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | -		closesocket(sock);
 | 
	
		
			
				|  |  | -		abort();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	pthread_t thread_id;
 | 
	
		
			
				|  |  | -	pthread_attr_t attr;
 | 
	
		
			
				|  |  | -	int result;
 | 
	
		
			
				|  |  | -	struct tcp_func_prm *thread_prm;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	thread_prm = (struct tcp_func_prm *)malloc(sizeof(struct tcp_func_prm));
 | 
	
		
			
				|  |  | -	if (!thread_prm) {
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Out of memory\n");
 | 
	
		
			
				|  |  | -		closesocket(sock);
 | 
	
		
			
				|  |  | -		abort();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	thread_prm->sock = sock;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	(void)pthread_attr_init(&attr);
 | 
	
		
			
				|  |  | -	(void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 | 
	
		
			
				|  |  | -	result = pthread_create(&thread_id, &attr, tcp_func, (void *)thread_prm);
 | 
	
		
			
				|  |  | -	(void)pthread_attr_destroy(&attr);
 | 
	
		
			
				|  |  | -	if (result != 0) {
 | 
	
		
			
				|  |  | -		r = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Cannot create thread [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | -		closesocket(sock);
 | 
	
		
			
				|  |  | -		abort();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	test_sleep(5);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int
 | 
	
		
			
				|  |  | -test_http_request(const char *server,
 | 
	
		
			
				|  |  | -                  uint16_t port,
 | 
	
		
			
				|  |  | -                  int use_ssl,
 | 
	
		
			
				|  |  | -                  const char *uri)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	/* Client var */
 | 
	
		
			
				|  |  | -	struct mg_connection *client;
 | 
	
		
			
				|  |  | -	char client_err_buf[256];
 | 
	
		
			
				|  |  | -	char client_data_buf[4096];
 | 
	
		
			
				|  |  | -	const struct mg_response_info *client_ri;
 | 
	
		
			
				|  |  | -	int64_t data_read;
 | 
	
		
			
				|  |  | -	int r;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	client = mg_connect_client(
 | 
	
		
			
				|  |  | -	    server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if ((client == NULL) || (0 != strcmp(client_err_buf, ""))) {
 | 
	
		
			
				|  |  | -		fprintf(stderr,
 | 
	
		
			
				|  |  | -		        "%s connection to server [%s] port [%u] failed: [%s]\n",
 | 
	
		
			
				|  |  | -		        use_ssl ? "HTTPS" : "HTTP",
 | 
	
		
			
				|  |  | -		        server,
 | 
	
		
			
				|  |  | -		        port,
 | 
	
		
			
				|  |  | -		        client_err_buf);
 | 
	
		
			
				|  |  | -		if (client) {
 | 
	
		
			
				|  |  | -			mg_close_connection(client);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/* In heavy fuzz testing, sometimes we run out of available sockets.
 | 
	
		
			
				|  |  | -		 * Wait for some seconds, and retry. */
 | 
	
		
			
				|  |  | -		test_sleep(5);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/* retry once */
 | 
	
		
			
				|  |  | -		client = mg_connect_client(
 | 
	
		
			
				|  |  | -		    server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
 | 
	
		
			
				|  |  | -		if (!client) {
 | 
	
		
			
				|  |  | -			fprintf(stderr, "Retry: error\n");
 | 
	
		
			
				|  |  | -			return 1;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Retry: success\n");
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	mg_printf(client, "GET %s HTTP/1.0\r\n\r\n", uri);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	r = mg_get_response(client, client_err_buf, sizeof(client_err_buf), 10000);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if ((r < 0) || (0 != strcmp(client_err_buf, ""))) {
 | 
	
		
			
				|  |  | -		mg_close_connection(client);
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	client_ri = mg_get_response_info(client);
 | 
	
		
			
				|  |  | -	if (client_ri == NULL) {
 | 
	
		
			
				|  |  | -		mg_close_connection(client);
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	data_read = 0;
 | 
	
		
			
				|  |  | -	while (data_read < client_ri->content_length) {
 | 
	
		
			
				|  |  | -		/* store the first sizeof(client_data_buf) bytes
 | 
	
		
			
				|  |  | -		 * of the HTTP response. */
 | 
	
		
			
				|  |  | -		r = mg_read(client,
 | 
	
		
			
				|  |  | -		            client_data_buf + data_read,
 | 
	
		
			
				|  |  | -		            sizeof(client_data_buf) - (size_t)data_read);
 | 
	
		
			
				|  |  | -		if (r > 0) {
 | 
	
		
			
				|  |  | -			data_read += r;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/* buffer filled? */
 | 
	
		
			
				|  |  | -		if (sizeof(client_data_buf) == (size_t)data_read) {
 | 
	
		
			
				|  |  | -			/* ignore the rest */
 | 
	
		
			
				|  |  | -			while (r > 0) {
 | 
	
		
			
				|  |  | -				char trash[1024];
 | 
	
		
			
				|  |  | -				r = mg_read(client, trash, sizeof(trash));
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			break;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* Nothing left to read */
 | 
	
		
			
				|  |  | -	r = mg_read(client, client_data_buf, sizeof(client_data_buf));
 | 
	
		
			
				|  |  | -	if (r != 0) {
 | 
	
		
			
				|  |  | -		mg_close_connection(client);
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	mg_close_connection(client);
 | 
	
		
			
				|  |  | -	return 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int
 | 
	
		
			
				|  |  | -LLVMFuzzerTestOneInput_URI(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	static char URI[1024 * 64]; /* static, to avoid stack overflow */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if (call_count == 0) {
 | 
	
		
			
				|  |  | -		memset(URI, 0, sizeof(URI));
 | 
	
		
			
				|  |  | -		init_civetweb();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	call_count++;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if (size < sizeof(URI)) {
 | 
	
		
			
				|  |  | -		memcpy(URI, data, size);
 | 
	
		
			
				|  |  | -		URI[size] = 0;
 | 
	
		
			
				|  |  | -	} else {
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	return test_http_request("127.0.0.1", 8080, 0, URI);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int
 | 
	
		
			
				|  |  | -LLVMFuzzerTestOneInput_REQUEST(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	if (call_count == 0) {
 | 
	
		
			
				|  |  | -		init_civetweb();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	call_count++;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	int r;
 | 
	
		
			
				|  |  | -	SOCKET sock = socket(AF_INET, SOCK_STREAM, 6);
 | 
	
		
			
				|  |  | -	if (sock == -1) {
 | 
	
		
			
				|  |  | -		r = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Cannot create socket [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	struct sockaddr_in sin;
 | 
	
		
			
				|  |  | -	memset(&sin, 0, sizeof(sin));
 | 
	
		
			
				|  |  | -	sin.sin_family = AF_INET;
 | 
	
		
			
				|  |  | -	sin.sin_addr.s_addr = inet_addr("127.0.0.1");
 | 
	
		
			
				|  |  | -	sin.sin_port = htons(8080);
 | 
	
		
			
				|  |  | -	r = connect(sock, (struct sockaddr *)&sin, sizeof(sin));
 | 
	
		
			
				|  |  | -	if (r != 0) {
 | 
	
		
			
				|  |  | -		r = errno;
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Error: Cannot connect [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | -		closesocket(sock);
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	char trash[1024];
 | 
	
		
			
				|  |  | -	r = send(sock, data, size, 0);
 | 
	
		
			
				|  |  | -	if (r != size) {
 | 
	
		
			
				|  |  | -		fprintf(stderr, "Warning: %i bytes sent (TODO: Repeat)\n", r);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	int data_read = 0;
 | 
	
		
			
				|  |  | -	while ((r = recv(sock, trash, sizeof(trash), 0)) > 0) {
 | 
	
		
			
				|  |  | -		data_read += r;
 | 
	
		
			
				|  |  | -	};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	shutdown(sock, SHUT_RDWR);
 | 
	
		
			
				|  |  | -	closesocket(sock);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	static int max_data_read = 0;
 | 
	
		
			
				|  |  | -	if (data_read > max_data_read) {
 | 
	
		
			
				|  |  | -		max_data_read = data_read;
 | 
	
		
			
				|  |  | -		printf("GOT data: %i\n", data_read);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static int
 | 
	
		
			
				|  |  | -LLVMFuzzerTestOneInput_RESPONSE(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	if (call_count == 0) {
 | 
	
		
			
				|  |  | -		init_tcp();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	call_count++;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if (size > sizeof(RESPONSE.data)) {
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	memcpy(RESPONSE.data, data, size);
 | 
	
		
			
				|  |  | -	RESPONSE.size = size;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	char errbuf[256];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	struct mg_connection *conn =
 | 
	
		
			
				|  |  | -	    mg_connect_client("127.0.0.1", 8080, 0, errbuf, sizeof(errbuf));
 | 
	
		
			
				|  |  | -	if (!conn) {
 | 
	
		
			
				|  |  | -		printf("Connect error: %s\n", errbuf);
 | 
	
		
			
				|  |  | -		test_sleep(1);
 | 
	
		
			
				|  |  | -		return 1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	mg_printf(conn, "GET / HTTP/1.0\r\n\r\n");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	int r = mg_get_response(conn, errbuf, sizeof(errbuf), 1000);
 | 
	
		
			
				|  |  | -	const struct mg_response_info *ri = mg_get_response_info(conn);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	mg_close_connection(conn);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	return 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#if defined(TEST_FUZZ1)
 | 
	
		
			
				|  |  | -	/* fuzz target 1: different URI for HTTP/1 server */
 | 
	
		
			
				|  |  | -	return LLVMFuzzerTestOneInput_URI(data, size);
 | 
	
		
			
				|  |  | -#elif defined(TEST_FUZZ2)
 | 
	
		
			
				|  |  | -	/* fuzz target 2: different requests for HTTP/1 server */
 | 
	
		
			
				|  |  | -	return LLVMFuzzerTestOneInput_REQUEST(data, size);
 | 
	
		
			
				|  |  | -#elif defined(TEST_FUZZ3)
 | 
	
		
			
				|  |  | -	/* fuzz target 3: different responses for HTTP/1 client */
 | 
	
		
			
				|  |  | -	return LLVMFuzzerTestOneInput_RESPONSE(data, size);
 | 
	
		
			
				|  |  | -#elif defined(TEST_FUZZ4)
 | 
	
		
			
				|  |  | -/* fuzz target 4: different requests for HTTP/2 server */
 | 
	
		
			
				|  |  | -#error "Only useful in HTTP/2 feature branch"
 | 
	
		
			
				|  |  | -#elif defined(TEST_FUZZ5)
 | 
	
		
			
				|  |  | -/* fuzz target 5: calling an internal server test function,
 | 
	
		
			
				|  |  | - *                bypassing network sockets */
 | 
	
		
			
				|  |  | -#error "Not implemented yet"
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -/* planned targets */
 | 
	
		
			
				|  |  | -#error "Unknown fuzz target"
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +#include "civetweb.h"
 | 
	
		
			
				|  |  | +#include <errno.h>
 | 
	
		
			
				|  |  | +#include <stdint.h>
 | 
	
		
			
				|  |  | +#include <stdlib.h>
 | 
	
		
			
				|  |  | +#include <string.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(_WIN32)
 | 
	
		
			
				|  |  | +#error "Currently not supported"
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <unistd.h>
 | 
	
		
			
				|  |  | +#define test_sleep(x) (sleep(x))
 | 
	
		
			
				|  |  | +#include <arpa/inet.h>
 | 
	
		
			
				|  |  | +#include <netinet/in.h>
 | 
	
		
			
				|  |  | +#include <netinet/ip.h>
 | 
	
		
			
				|  |  | +#include <pthread.h>
 | 
	
		
			
				|  |  | +#include <sys/socket.h>
 | 
	
		
			
				|  |  | +#include <sys/types.h>
 | 
	
		
			
				|  |  | +typedef int SOCKET;
 | 
	
		
			
				|  |  | +#define closesocket(a) (close(a))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static uint64_t call_count = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static struct mg_context *ctx;
 | 
	
		
			
				|  |  | +static const char *OPTIONS[] = {"listening_ports",
 | 
	
		
			
				|  |  | +                                "8080,8443s",
 | 
	
		
			
				|  |  | +                                "document_root",
 | 
	
		
			
				|  |  | +                                "fuzztest/docroot",
 | 
	
		
			
				|  |  | +                                "ssl_certificate",
 | 
	
		
			
				|  |  | +                                "resources/cert/server.pem",
 | 
	
		
			
				|  |  | +                                NULL,
 | 
	
		
			
				|  |  | +                                NULL};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +init_civetweb(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct mg_callbacks callbacks;
 | 
	
		
			
				|  |  | +	memset(&callbacks, 0, sizeof(callbacks));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ctx = mg_start(&callbacks, 0, OPTIONS);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!ctx) {
 | 
	
		
			
				|  |  | +		fprintf(stderr, "\nCivetWeb test server failed to start\n");
 | 
	
		
			
				|  |  | +		abort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Give server 5 seconds to start, before flooding with requests.
 | 
	
		
			
				|  |  | +	 * Don't know if this is required for fuzz-tests, but it was helpful
 | 
	
		
			
				|  |  | +	 * when testing starting/stopping the server multiple times in test
 | 
	
		
			
				|  |  | +	 * container environments. */
 | 
	
		
			
				|  |  | +	test_sleep(5);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct tcp_func_prm {
 | 
	
		
			
				|  |  | +	SOCKET sock;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct tRESPONSE {
 | 
	
		
			
				|  |  | +	char data[4096];
 | 
	
		
			
				|  |  | +	size_t size;
 | 
	
		
			
				|  |  | +} RESPONSE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void *
 | 
	
		
			
				|  |  | +tcp_func(void *arg)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	char req[1024 * 16];
 | 
	
		
			
				|  |  | +	struct tcp_func_prm *ptcp_func_prm = (struct tcp_func_prm *)arg;
 | 
	
		
			
				|  |  | +	SOCKET svr = ptcp_func_prm->sock;
 | 
	
		
			
				|  |  | +	printf("Server ready, sock %i\n", svr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +next_request : {
 | 
	
		
			
				|  |  | +	struct sockaddr_in cliadr;
 | 
	
		
			
				|  |  | +	socklen_t adrlen = sizeof(cliadr);
 | 
	
		
			
				|  |  | +	int buf_filled = 0;
 | 
	
		
			
				|  |  | +	int req_ready = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memset(&cliadr, 0, sizeof(cliadr));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	SOCKET cli = accept(svr, (struct sockaddr *)&cliadr, &adrlen);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (cli == -1) {
 | 
	
		
			
				|  |  | +		int er = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Accept failed [%s]\n", strerror(er));
 | 
	
		
			
				|  |  | +		test_sleep(1);
 | 
	
		
			
				|  |  | +		goto next_request;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Read request */
 | 
	
		
			
				|  |  | +	do {
 | 
	
		
			
				|  |  | +		int r = recv(cli, req + buf_filled, sizeof(req) - buf_filled - 1, 0);
 | 
	
		
			
				|  |  | +		if (r > 0) {
 | 
	
		
			
				|  |  | +			buf_filled += r;
 | 
	
		
			
				|  |  | +			req[buf_filled] = 0;
 | 
	
		
			
				|  |  | +			if (strstr(req, "\r\n\r\n") != NULL) {
 | 
	
		
			
				|  |  | +				req_ready = 1;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		} else {
 | 
	
		
			
				|  |  | +			/* some error */
 | 
	
		
			
				|  |  | +			int er = errno;
 | 
	
		
			
				|  |  | +			fprintf(stderr, "Error: Recv failed [%s]\n", strerror(er));
 | 
	
		
			
				|  |  | +			test_sleep(1);
 | 
	
		
			
				|  |  | +			goto next_request;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	} while (!req_ready);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Request is complete here.
 | 
	
		
			
				|  |  | +	 * Now send response */
 | 
	
		
			
				|  |  | +	send(cli, RESPONSE.data, RESPONSE.size, MSG_NOSIGNAL);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Close connection. */
 | 
	
		
			
				|  |  | +	shutdown(cli, SHUT_RDWR);
 | 
	
		
			
				|  |  | +	closesocket(cli);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* done */
 | 
	
		
			
				|  |  | +	goto next_request;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	free(arg);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +init_tcp(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int r;
 | 
	
		
			
				|  |  | +	SOCKET sock = socket(AF_INET, SOCK_STREAM, 6);
 | 
	
		
			
				|  |  | +	if (sock == -1) {
 | 
	
		
			
				|  |  | +		r = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Cannot create socket [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | +		abort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	struct sockaddr_in sin;
 | 
	
		
			
				|  |  | +	memset(&sin, 0, sizeof(sin));
 | 
	
		
			
				|  |  | +	sin.sin_family = AF_INET;
 | 
	
		
			
				|  |  | +	sin.sin_addr.s_addr = inet_addr("127.0.0.1");
 | 
	
		
			
				|  |  | +	sin.sin_port = htons(8080);
 | 
	
		
			
				|  |  | +	r = bind(sock, (struct sockaddr *)&sin, sizeof(sin));
 | 
	
		
			
				|  |  | +	if (r != 0) {
 | 
	
		
			
				|  |  | +		r = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Cannot bind [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | +		closesocket(sock);
 | 
	
		
			
				|  |  | +		abort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	r = listen(sock, 128);
 | 
	
		
			
				|  |  | +	if (r != 0) {
 | 
	
		
			
				|  |  | +		r = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Cannot listen [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | +		closesocket(sock);
 | 
	
		
			
				|  |  | +		abort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pthread_t thread_id;
 | 
	
		
			
				|  |  | +	pthread_attr_t attr;
 | 
	
		
			
				|  |  | +	int result;
 | 
	
		
			
				|  |  | +	struct tcp_func_prm *thread_prm;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	thread_prm = (struct tcp_func_prm *)malloc(sizeof(struct tcp_func_prm));
 | 
	
		
			
				|  |  | +	if (!thread_prm) {
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Out of memory\n");
 | 
	
		
			
				|  |  | +		closesocket(sock);
 | 
	
		
			
				|  |  | +		abort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	thread_prm->sock = sock;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	(void)pthread_attr_init(&attr);
 | 
	
		
			
				|  |  | +	(void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 | 
	
		
			
				|  |  | +	result = pthread_create(&thread_id, &attr, tcp_func, (void *)thread_prm);
 | 
	
		
			
				|  |  | +	(void)pthread_attr_destroy(&attr);
 | 
	
		
			
				|  |  | +	if (result != 0) {
 | 
	
		
			
				|  |  | +		r = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Cannot create thread [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | +		closesocket(sock);
 | 
	
		
			
				|  |  | +		abort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	test_sleep(5);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +test_http_request(const char *server,
 | 
	
		
			
				|  |  | +                  uint16_t port,
 | 
	
		
			
				|  |  | +                  int use_ssl,
 | 
	
		
			
				|  |  | +                  const char *uri)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* Client var */
 | 
	
		
			
				|  |  | +	struct mg_connection *client;
 | 
	
		
			
				|  |  | +	char client_err_buf[256];
 | 
	
		
			
				|  |  | +	char client_data_buf[4096];
 | 
	
		
			
				|  |  | +	const struct mg_response_info *client_ri;
 | 
	
		
			
				|  |  | +	int64_t data_read;
 | 
	
		
			
				|  |  | +	int r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	client = mg_connect_client(
 | 
	
		
			
				|  |  | +	    server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if ((client == NULL) || (0 != strcmp(client_err_buf, ""))) {
 | 
	
		
			
				|  |  | +		fprintf(stderr,
 | 
	
		
			
				|  |  | +		        "%s connection to server [%s] port [%u] failed: [%s]\n",
 | 
	
		
			
				|  |  | +		        use_ssl ? "HTTPS" : "HTTP",
 | 
	
		
			
				|  |  | +		        server,
 | 
	
		
			
				|  |  | +		        port,
 | 
	
		
			
				|  |  | +		        client_err_buf);
 | 
	
		
			
				|  |  | +		if (client) {
 | 
	
		
			
				|  |  | +			mg_close_connection(client);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* In heavy fuzz testing, sometimes we run out of available sockets.
 | 
	
		
			
				|  |  | +		 * Wait for some seconds, and retry. */
 | 
	
		
			
				|  |  | +		test_sleep(5);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* retry once */
 | 
	
		
			
				|  |  | +		client = mg_connect_client(
 | 
	
		
			
				|  |  | +		    server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
 | 
	
		
			
				|  |  | +		if (!client) {
 | 
	
		
			
				|  |  | +			fprintf(stderr, "Retry: error\n");
 | 
	
		
			
				|  |  | +			return 1;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Retry: success\n");
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mg_printf(client, "GET %s HTTP/1.0\r\n\r\n", uri);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	r = mg_get_response(client, client_err_buf, sizeof(client_err_buf), 10000);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if ((r < 0) || (0 != strcmp(client_err_buf, ""))) {
 | 
	
		
			
				|  |  | +		mg_close_connection(client);
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	client_ri = mg_get_response_info(client);
 | 
	
		
			
				|  |  | +	if (client_ri == NULL) {
 | 
	
		
			
				|  |  | +		mg_close_connection(client);
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	data_read = 0;
 | 
	
		
			
				|  |  | +	while (data_read < client_ri->content_length) {
 | 
	
		
			
				|  |  | +		/* store the first sizeof(client_data_buf) bytes
 | 
	
		
			
				|  |  | +		 * of the HTTP response. */
 | 
	
		
			
				|  |  | +		r = mg_read(client,
 | 
	
		
			
				|  |  | +		            client_data_buf + data_read,
 | 
	
		
			
				|  |  | +		            sizeof(client_data_buf) - (size_t)data_read);
 | 
	
		
			
				|  |  | +		if (r > 0) {
 | 
	
		
			
				|  |  | +			data_read += r;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* buffer filled? */
 | 
	
		
			
				|  |  | +		if (sizeof(client_data_buf) == (size_t)data_read) {
 | 
	
		
			
				|  |  | +			/* ignore the rest */
 | 
	
		
			
				|  |  | +			while (r > 0) {
 | 
	
		
			
				|  |  | +				char trash[1024];
 | 
	
		
			
				|  |  | +				r = mg_read(client, trash, sizeof(trash));
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Nothing left to read */
 | 
	
		
			
				|  |  | +	r = mg_read(client, client_data_buf, sizeof(client_data_buf));
 | 
	
		
			
				|  |  | +	if (r != 0) {
 | 
	
		
			
				|  |  | +		mg_close_connection(client);
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mg_close_connection(client);
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +LLVMFuzzerTestOneInput_URI(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	static char URI[1024 * 64]; /* static, to avoid stack overflow */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (call_count == 0) {
 | 
	
		
			
				|  |  | +		memset(URI, 0, sizeof(URI));
 | 
	
		
			
				|  |  | +		init_civetweb();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	call_count++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (size < sizeof(URI)) {
 | 
	
		
			
				|  |  | +		memcpy(URI, data, size);
 | 
	
		
			
				|  |  | +		URI[size] = 0;
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return test_http_request("127.0.0.1", 8080, 0, URI);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +LLVMFuzzerTestOneInput_REQUEST(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (call_count == 0) {
 | 
	
		
			
				|  |  | +		init_civetweb();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	call_count++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	int r;
 | 
	
		
			
				|  |  | +	SOCKET sock = socket(AF_INET, SOCK_STREAM, 6);
 | 
	
		
			
				|  |  | +	if (sock == -1) {
 | 
	
		
			
				|  |  | +		r = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Cannot create socket [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	struct sockaddr_in sin;
 | 
	
		
			
				|  |  | +	memset(&sin, 0, sizeof(sin));
 | 
	
		
			
				|  |  | +	sin.sin_family = AF_INET;
 | 
	
		
			
				|  |  | +	sin.sin_addr.s_addr = inet_addr("127.0.0.1");
 | 
	
		
			
				|  |  | +	sin.sin_port = htons(8080);
 | 
	
		
			
				|  |  | +	r = connect(sock, (struct sockaddr *)&sin, sizeof(sin));
 | 
	
		
			
				|  |  | +	if (r != 0) {
 | 
	
		
			
				|  |  | +		r = errno;
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Error: Cannot connect [%s]\n", strerror(r));
 | 
	
		
			
				|  |  | +		closesocket(sock);
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	char trash[1024];
 | 
	
		
			
				|  |  | +	r = send(sock, data, size, 0);
 | 
	
		
			
				|  |  | +	if (r != size) {
 | 
	
		
			
				|  |  | +		fprintf(stderr, "Warning: %i bytes sent (TODO: Repeat)\n", r);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	int data_read = 0;
 | 
	
		
			
				|  |  | +	while ((r = recv(sock, trash, sizeof(trash), 0)) > 0) {
 | 
	
		
			
				|  |  | +		data_read += r;
 | 
	
		
			
				|  |  | +	};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	shutdown(sock, SHUT_RDWR);
 | 
	
		
			
				|  |  | +	closesocket(sock);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	static int max_data_read = 0;
 | 
	
		
			
				|  |  | +	if (data_read > max_data_read) {
 | 
	
		
			
				|  |  | +		max_data_read = data_read;
 | 
	
		
			
				|  |  | +		printf("GOT data: %i\n", data_read);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +LLVMFuzzerTestOneInput_RESPONSE(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (call_count == 0) {
 | 
	
		
			
				|  |  | +		init_tcp();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	call_count++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (size > sizeof(RESPONSE.data)) {
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memcpy(RESPONSE.data, data, size);
 | 
	
		
			
				|  |  | +	RESPONSE.size = size;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	char errbuf[256];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	struct mg_connection *conn =
 | 
	
		
			
				|  |  | +	    mg_connect_client("127.0.0.1", 8080, 0, errbuf, sizeof(errbuf));
 | 
	
		
			
				|  |  | +	if (!conn) {
 | 
	
		
			
				|  |  | +		printf("Connect error: %s\n", errbuf);
 | 
	
		
			
				|  |  | +		test_sleep(1);
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	mg_printf(conn, "GET / HTTP/1.0\r\n\r\n");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	int r = mg_get_response(conn, errbuf, sizeof(errbuf), 1000);
 | 
	
		
			
				|  |  | +	const struct mg_response_info *ri = mg_get_response_info(conn);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mg_close_connection(conn);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* MAIN for fuzztest */
 | 
	
		
			
				|  |  | +int
 | 
	
		
			
				|  |  | +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +#if defined(TEST_FUZZ1)
 | 
	
		
			
				|  |  | +	/* fuzz target 1: different URI for HTTP/1 server */
 | 
	
		
			
				|  |  | +	return LLVMFuzzerTestOneInput_URI(data, size);
 | 
	
		
			
				|  |  | +#elif defined(TEST_FUZZ2)
 | 
	
		
			
				|  |  | +	/* fuzz target 2: different requests for HTTP/1 server */
 | 
	
		
			
				|  |  | +	return LLVMFuzzerTestOneInput_REQUEST(data, size);
 | 
	
		
			
				|  |  | +#elif defined(TEST_FUZZ3)
 | 
	
		
			
				|  |  | +	/* fuzz target 3: different responses for HTTP/1 client */
 | 
	
		
			
				|  |  | +	return LLVMFuzzerTestOneInput_RESPONSE(data, size);
 | 
	
		
			
				|  |  | +#elif defined(TEST_FUZZ4)
 | 
	
		
			
				|  |  | +#error "Only useful in HTTP/2 feature branch"
 | 
	
		
			
				|  |  | +	/* fuzz target 4: different requests for HTTP/2 server */
 | 
	
		
			
				|  |  | +	return LLVMFuzzerTestOneInput_REQUEST_HTTP2(data, size);
 | 
	
		
			
				|  |  | +#elif defined(TEST_FUZZ5)
 | 
	
		
			
				|  |  | +	/* fuzz target 5: calling an internal server test function,
 | 
	
		
			
				|  |  | +	 *                bypassing network sockets */
 | 
	
		
			
				|  |  | +	return LLVMFuzzerTestOneInput_process_new_connection(data, size);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +/* planned targets */
 | 
	
		
			
				|  |  | +#error "Unknown fuzz target"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +}
 |