forked from cory/tildefriends
		
	Fix some http request lifetime issues, and follow the same lowercase convention for headers.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4690 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		
							
								
								
									
										34
									
								
								src/http.c
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/http.c
									
									
									
									
									
								
							@@ -21,6 +21,8 @@ typedef struct _tf_http_connection_t
 | 
				
			|||||||
	uv_tcp_t tcp;
 | 
						uv_tcp_t tcp;
 | 
				
			||||||
	uv_shutdown_t shutdown;
 | 
						uv_shutdown_t shutdown;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int ref_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char* method;
 | 
						const char* method;
 | 
				
			||||||
	const char* path;
 | 
						const char* path;
 | 
				
			||||||
	int minor_version;
 | 
						int minor_version;
 | 
				
			||||||
@@ -127,7 +129,7 @@ static void _http_connection_destroy(tf_http_connection_t* connection)
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
 | 
							uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else if (connection->ref_count == 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		tf_http_t* http = connection->http;
 | 
							tf_http_t* http = connection->http;
 | 
				
			||||||
		for (int i = 0; i < http->connections_count; i++)
 | 
							for (int i = 0; i < http->connections_count; i++)
 | 
				
			||||||
@@ -182,7 +184,9 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
 | 
				
			|||||||
			.headers_count = connection->headers_length,
 | 
								.headers_count = connection->headers_length,
 | 
				
			||||||
			.user_data = connection->user_data,
 | 
								.user_data = connection->user_data,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
							tf_http_request_ref(request);
 | 
				
			||||||
		connection->callback(request);
 | 
							connection->callback(request);
 | 
				
			||||||
 | 
							tf_http_request_release(request);
 | 
				
			||||||
		_http_reset_connection(connection);
 | 
							_http_reset_connection(connection);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -207,6 +211,7 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
 | 
				
			|||||||
			if (parse_result > 0)
 | 
								if (parse_result > 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				connection->headers_done = true;
 | 
									connection->headers_done = true;
 | 
				
			||||||
 | 
									connection->headers_length = header_count;
 | 
				
			||||||
				connection->method = method;
 | 
									connection->method = method;
 | 
				
			||||||
				((char*)connection->method)[method_length] = '\0';
 | 
									((char*)connection->method)[method_length] = '\0';
 | 
				
			||||||
				connection->path = path;
 | 
									connection->path = path;
 | 
				
			||||||
@@ -216,6 +221,14 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				for (int i = 0; i < (int)header_count; i++)
 | 
									for (int i = 0; i < (int)header_count; i++)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
										for (size_t j = 0; j < connection->headers[i].name_len; j++)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (connection->headers[i].name[j] >= 'A' &&
 | 
				
			||||||
 | 
												connection->headers[i].name[j] <= 'Z')
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												((char*)connection->headers[i].name)[j] += 'a' - 'A';
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
					((char*)connection->headers[i].name)[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';
 | 
										((char*)connection->headers[i].value)[connection->headers[i].value_len] = '\0';
 | 
				
			||||||
					if (strcasecmp(connection->headers[i].name, "content-length") == 0)
 | 
										if (strcasecmp(connection->headers[i].name, "content-length") == 0)
 | 
				
			||||||
@@ -464,7 +477,6 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
 | 
				
			|||||||
		request->connection->shutdown.data = request->connection;
 | 
							request->connection->shutdown.data = request->connection;
 | 
				
			||||||
		uv_shutdown(&request->connection->shutdown, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
 | 
							uv_shutdown(&request->connection->shutdown, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf_free(request);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data)
 | 
					size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data)
 | 
				
			||||||
@@ -472,3 +484,21 @@ size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data)
 | 
				
			|||||||
	*out_data = request->connection->body;
 | 
						*out_data = request->connection->body;
 | 
				
			||||||
	return request->connection->content_length;
 | 
						return request->connection->content_length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tf_http_request_ref(tf_http_request_t* request)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						request->ref_count++;
 | 
				
			||||||
 | 
						request->connection->ref_count++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tf_http_request_release(tf_http_request_t* request)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (--request->connection->ref_count == 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Reset the connection? */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (--request->ref_count == 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							tf_free(request);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ typedef struct _tf_http_request_t
 | 
				
			|||||||
	struct phr_header* headers;
 | 
						struct phr_header* headers;
 | 
				
			||||||
	int headers_count;
 | 
						int headers_count;
 | 
				
			||||||
	void* user_data;
 | 
						void* user_data;
 | 
				
			||||||
 | 
						int ref_count;
 | 
				
			||||||
} tf_http_request_t;
 | 
					} tf_http_request_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (tf_http_callback_t)(tf_http_request_t* request);
 | 
					typedef void (tf_http_callback_t)(tf_http_request_t* request);
 | 
				
			||||||
@@ -31,3 +32,6 @@ void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_
 | 
				
			|||||||
void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length);
 | 
					void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length);
 | 
				
			||||||
size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data);
 | 
					size_t tf_http_get_body(const tf_http_request_t* request, const void** out_data);
 | 
				
			||||||
void tf_http_destroy(tf_http_t* http);
 | 
					void tf_http_destroy(tf_http_t* http);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tf_http_request_ref(tf_http_request_t* request);
 | 
				
			||||||
 | 
					void tf_http_request_release(tf_http_request_t* request);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static JSClassID _httpd_class_id;
 | 
					static JSClassID _httpd_class_id;
 | 
				
			||||||
static JSClassID _httpd_response_class_id;
 | 
					static JSClassID _httpd_request_class_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _http_handler_data_t
 | 
					typedef struct _http_handler_data_t
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -32,7 +32,7 @@ static JSValue _httpd_response_write_head(JSContext* context, JSValueConst this_
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static JSValue _httpd_response_end(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
 | 
					static JSValue _httpd_response_end(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	tf_http_request_t* request = JS_GetOpaque(this_val, _httpd_response_class_id);
 | 
						tf_http_request_t* request = JS_GetOpaque(this_val, _httpd_request_class_id);
 | 
				
			||||||
	size_t length = 0;
 | 
						size_t length = 0;
 | 
				
			||||||
	const void* data = NULL;
 | 
						const void* data = NULL;
 | 
				
			||||||
	JSValue buffer;
 | 
						JSValue buffer;
 | 
				
			||||||
@@ -104,17 +104,18 @@ static void _httpd_callback(tf_http_request_t* request)
 | 
				
			|||||||
	JSValue request_object = JS_NewObject(context);
 | 
						JSValue request_object = JS_NewObject(context);
 | 
				
			||||||
	JS_SetPropertyStr(context, request_object, "uri", JS_NewString(context, request->path));
 | 
						JS_SetPropertyStr(context, request_object, "uri", JS_NewString(context, request->path));
 | 
				
			||||||
	JSValue headers = JS_NewObject(context);
 | 
						JSValue headers = JS_NewObject(context);
 | 
				
			||||||
	JS_SetPropertyStr(context, request_object, "headers", headers);
 | 
					 | 
				
			||||||
	for (int i = 0; i < request->headers_count; i++)
 | 
						for (int i = 0; i < request->headers_count; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		JS_SetPropertyStr(context, headers, request->headers[i].name, JS_NewString(context, request->headers[i].value));
 | 
							JS_SetPropertyStr(context, headers, request->headers[i].name, JS_NewString(context, request->headers[i].value));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						JS_SetPropertyStr(context, request_object, "headers", headers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	JSValue client = JS_NewObject(context);
 | 
						JSValue client = JS_NewObject(context);
 | 
				
			||||||
	JS_SetPropertyStr(context, client, "tls", JS_FALSE);
 | 
						JS_SetPropertyStr(context, client, "tls", JS_FALSE);
 | 
				
			||||||
	JS_SetPropertyStr(context, request_object, "client", client);
 | 
						JS_SetPropertyStr(context, request_object, "client", client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	JSValue response_object = JS_NewObjectClass(context, _httpd_response_class_id);
 | 
						JSValue response_object = JS_NewObjectClass(context, _httpd_request_class_id);
 | 
				
			||||||
 | 
						tf_http_request_ref(request);
 | 
				
			||||||
	JS_SetOpaque(response_object, request);
 | 
						JS_SetOpaque(response_object, request);
 | 
				
			||||||
	JS_SetPropertyStr(context, response_object, "writeHead", JS_NewCFunction(context, _httpd_response_write_head, "writeHead", 2));
 | 
						JS_SetPropertyStr(context, response_object, "writeHead", JS_NewCFunction(context, _httpd_response_write_head, "writeHead", 2));
 | 
				
			||||||
	JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
 | 
						JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
 | 
				
			||||||
@@ -161,19 +162,34 @@ void _httpd_finalizer(JSRuntime* runtime, JSValue value)
 | 
				
			|||||||
	tf_http_destroy(http);
 | 
						tf_http_destroy(http);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _httpd_request_finalizer(JSRuntime* runtime, JSValue value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						tf_http_request_t* request = JS_GetOpaque(value, _httpd_request_class_id);
 | 
				
			||||||
 | 
						tf_http_request_release(request);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void tf_httpd_register(JSContext* context)
 | 
					void tf_httpd_register(JSContext* context)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	JS_NewClassID(&_httpd_class_id);
 | 
						JS_NewClassID(&_httpd_class_id);
 | 
				
			||||||
	JS_NewClassID(&_httpd_response_class_id);
 | 
						JS_NewClassID(&_httpd_request_class_id);
 | 
				
			||||||
	JSClassDef def =
 | 
						JSClassDef httpd_def =
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.class_name = "Httpd",
 | 
							.class_name = "Httpd",
 | 
				
			||||||
		.finalizer = &_httpd_finalizer,
 | 
							.finalizer = &_httpd_finalizer,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	if (JS_NewClass(JS_GetRuntime(context), _httpd_class_id, &def) != 0)
 | 
						if (JS_NewClass(JS_GetRuntime(context), _httpd_class_id, &httpd_def) != 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		fprintf(stderr, "Failed to register Httpd.\n");
 | 
							fprintf(stderr, "Failed to register Httpd.\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						JSClassDef request_def =
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.class_name = "Request",
 | 
				
			||||||
 | 
							.finalizer = &_httpd_request_finalizer,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						if (JS_NewClass(JS_GetRuntime(context), _httpd_request_class_id, &request_def) != 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "Failed to register Request.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	JSValue global = JS_GetGlobalObject(context);
 | 
						JSValue global = JS_GetGlobalObject(context);
 | 
				
			||||||
	JSValue httpd = JS_NewObjectClass(context, _httpd_class_id);
 | 
						JSValue httpd = JS_NewObjectClass(context, _httpd_class_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user