forked from cory/tildefriends
		
	I think we did some keep-alive.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4684 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		
							
								
								
									
										39
									
								
								src/http.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								src/http.c
									
									
									
									
									
								
							@@ -22,6 +22,7 @@ typedef struct _tf_http_connection_t
 | 
			
		||||
 | 
			
		||||
	const char* method;
 | 
			
		||||
	const char* path;
 | 
			
		||||
	int minor_version;
 | 
			
		||||
 | 
			
		||||
	char headers_buffer[8192];
 | 
			
		||||
	size_t headers_buffer_length;
 | 
			
		||||
@@ -40,6 +41,7 @@ typedef struct _tf_http_connection_t
 | 
			
		||||
	void* body;
 | 
			
		||||
	size_t body_length;
 | 
			
		||||
	size_t content_length;
 | 
			
		||||
	bool connection_close;
 | 
			
		||||
} tf_http_connection_t;
 | 
			
		||||
 | 
			
		||||
typedef struct _tf_http_handler_t
 | 
			
		||||
@@ -147,6 +149,14 @@ static void _http_builtin_404_handler(tf_http_request_t* request)
 | 
			
		||||
	tf_http_respond(request, 404, NULL, 0, k_payload, strlen(k_payload));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _http_reset_connection(tf_http_connection_t* connection)
 | 
			
		||||
{
 | 
			
		||||
	connection->headers_done = false;
 | 
			
		||||
	connection->headers_buffer_length = 0;
 | 
			
		||||
	connection->body_length = 0;
 | 
			
		||||
	connection->content_length = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _http_add_body_bytes(tf_http_connection_t* connection, const void* data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	size_t fit = tf_min(connection->content_length - connection->body_length, size);
 | 
			
		||||
@@ -169,6 +179,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
 | 
			
		||||
			.user_data = connection->user_data,
 | 
			
		||||
		};
 | 
			
		||||
		connection->callback(&request);
 | 
			
		||||
		_http_reset_connection(connection);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -185,10 +196,9 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
 | 
			
		||||
			size_t method_length = 0;
 | 
			
		||||
			const char* path = NULL;
 | 
			
		||||
			size_t path_length = 0;
 | 
			
		||||
			int minor_version = 0;
 | 
			
		||||
			size_t header_count = sizeof(connection->headers) / sizeof(*connection->headers);
 | 
			
		||||
 | 
			
		||||
			int parse_result = phr_parse_request(connection->headers_buffer, connection->headers_buffer_length, &method, &method_length, &path, &path_length, &minor_version, connection->headers, &header_count, connection->parsed_length);
 | 
			
		||||
			int parse_result = phr_parse_request(connection->headers_buffer, connection->headers_buffer_length, &method, &method_length, &path, &path_length, &connection->minor_version, connection->headers, &header_count, connection->parsed_length);
 | 
			
		||||
			connection->parsed_length = connection->headers_buffer_length;
 | 
			
		||||
			if (parse_result > 0)
 | 
			
		||||
			{
 | 
			
		||||
@@ -198,13 +208,23 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
 | 
			
		||||
				connection->path = path;
 | 
			
		||||
				((char*)connection->path)[path_length] = '\0';
 | 
			
		||||
 | 
			
		||||
				connection->connection_close = connection->minor_version == 0;
 | 
			
		||||
 | 
			
		||||
				for (int i = 0; i < (int)header_count; i++)
 | 
			
		||||
				{
 | 
			
		||||
					if (connection->headers[i].name_len == strlen("content-length") &&
 | 
			
		||||
						strncasecmp(connection->headers[i].name, "content-length", connection->headers[i].name_len) == 0)
 | 
			
		||||
					((char*)connection->headers[i].name)[connection->headers[i].name_len] = '\0';
 | 
			
		||||
					((char*)connection->headers[i].value)[connection->headers[i].value_len] = '\0';
 | 
			
		||||
					if (strcasecmp(connection->headers[i].name, "content-length") == 0)
 | 
			
		||||
					{
 | 
			
		||||
						connection->content_length = strtoull(connection->headers[i].value, NULL, 10);
 | 
			
		||||
					}
 | 
			
		||||
					else if (strcasecmp(connection->headers[i].name, "connection") == 0)
 | 
			
		||||
					{
 | 
			
		||||
						if (strcasecmp(connection->headers[i].value, "close") == 0)
 | 
			
		||||
						{
 | 
			
		||||
							connection->connection_close = true;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (connection->content_length)
 | 
			
		||||
@@ -405,7 +425,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
 | 
			
		||||
	uv_write_t* write = tf_malloc(sizeof(uv_write_t) + headers_length + content_length + 1);
 | 
			
		||||
	*write = (uv_write_t) { .data = request->connection };
 | 
			
		||||
	char* buffer = (char*)(write + 1);
 | 
			
		||||
	int offset = snprintf(buffer, headers_length + 1, "HTTP/1.0 %03d %s\r\n", status, status_text);
 | 
			
		||||
	int offset = snprintf(buffer, headers_length + 1, "HTTP/1.%d %03d %s\r\n", request->connection->minor_version, status, status_text);
 | 
			
		||||
	for (int i = 0; i < headers_count; i += 2)
 | 
			
		||||
	{
 | 
			
		||||
		offset += snprintf(buffer + offset, headers_length + 1 - offset, "%s: %s\r\n", headers[i], headers[i + 1]);
 | 
			
		||||
@@ -427,9 +447,12 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
 | 
			
		||||
		tf_printf("uv_write: %s\n", uv_strerror(r));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uv_shutdown_t* shutdown_request = tf_malloc(sizeof(uv_shutdown_t));
 | 
			
		||||
	*shutdown_request = (uv_shutdown_t) { .data = request };
 | 
			
		||||
	uv_shutdown(shutdown_request, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
 | 
			
		||||
	if (request->connection->connection_close)
 | 
			
		||||
	{
 | 
			
		||||
		uv_shutdown_t* shutdown_request = tf_malloc(sizeof(uv_shutdown_t));
 | 
			
		||||
		*shutdown_request = (uv_shutdown_t) { .data = request };
 | 
			
		||||
		uv_shutdown(shutdown_request, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data)
 | 
			
		||||
 
 | 
			
		||||
@@ -697,6 +697,10 @@ static void _test_http_thread(void* data)
 | 
			
		||||
	assert(WEXITSTATUS(r) == 0);
 | 
			
		||||
	tf_printf("curl returned %d\n", WEXITSTATUS(r));
 | 
			
		||||
 | 
			
		||||
	r = system("curl -v http://localhost:23456/hello http://localhost:23456/hello http://localhost:23456/hello");
 | 
			
		||||
	assert(WEXITSTATUS(r) == 0);
 | 
			
		||||
	tf_printf("curl returned %d\n", WEXITSTATUS(r));
 | 
			
		||||
 | 
			
		||||
	test->done = true;
 | 
			
		||||
 | 
			
		||||
	/* All to wake up the loop. */
 | 
			
		||||
@@ -708,7 +712,7 @@ static void _test_http_handler(tf_http_request_t* request)
 | 
			
		||||
{
 | 
			
		||||
	const char* headers[] =
 | 
			
		||||
	{
 | 
			
		||||
		"Connection", "close",
 | 
			
		||||
		"User-Agent", "TildeFriends/1.0",
 | 
			
		||||
	};
 | 
			
		||||
	const char* k_payload = "Hello, world!\n";
 | 
			
		||||
	tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload));
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user