Browse Source

Update H2O to version 2.3.0 (#8069)

Anton Kirilov 2 years ago
parent
commit
ee07fd2481

+ 2 - 2
frameworks/C/h2o/CMakeLists.txt

@@ -27,8 +27,8 @@ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3")
 file(GLOB_RECURSE SOURCES "src/*.c")
 file(GLOB_RECURSE SOURCES "src/*.c")
 add_executable(${PROJECT_NAME} ${SOURCES})
 add_executable(${PROJECT_NAME} ${SOURCES})
 target_link_libraries(${PROJECT_NAME} ${COMMON_OPTIONS})
 target_link_libraries(${PROJECT_NAME} ${COMMON_OPTIONS})
-target_link_libraries(${PROJECT_NAME} ${H2O_LIB} ${MUSTACHE_C_LIB} ${NUMA_LIB} ${PQ_LIB} ${SSL_LIB})
-target_link_libraries(${PROJECT_NAME} ${CRYPTO_LIB} ${YAJL_LIB} ${Z_LIB})
+target_link_libraries(${PROJECT_NAME} ${H2O_LIB} m ${MUSTACHE_C_LIB} ${NUMA_LIB} ${PQ_LIB})
+target_link_libraries(${PROJECT_NAME} ${SSL_LIB} ${CRYPTO_LIB} ${YAJL_LIB} ${Z_LIB})
 install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
 install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
 file(GLOB TEMPLATES "template/*")
 file(GLOB TEMPLATES "template/*")
 install(FILES ${TEMPLATES} DESTINATION share/${PROJECT_NAME}/template)
 install(FILES ${TEMPLATES} DESTINATION share/${PROJECT_NAME}/template)

+ 7 - 3
frameworks/C/h2o/h2o.dockerfile

@@ -13,6 +13,8 @@ RUN apt-get -yqq update && \
       curl \
       curl \
       flex \
       flex \
       g++ \
       g++ \
+      libbrotli-dev \
+      libcap-dev \
       libnuma-dev \
       libnuma-dev \
       libpq-dev \
       libpq-dev \
       libssl-dev \
       libssl-dev \
@@ -23,9 +25,10 @@ RUN apt-get -yqq update && \
       libz-dev \
       libz-dev \
       make \
       make \
       ninja-build \
       ninja-build \
-      pkg-config
+      pkg-config \
+      systemtap-sdt-dev
 
 
-ARG H2O_VERSION=v2.2.6
+ARG H2O_VERSION=71224be1ac250502f27528e988d3a673dcf2055f
 
 
 WORKDIR /tmp/h2o-build
 WORKDIR /tmp/h2o-build
 RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \
 RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \
@@ -38,7 +41,8 @@ RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \
       -G Ninja \
       -G Ninja \
       -S . && \
       -S . && \
     cmake --build build -j && \
     cmake --build build -j && \
-    cmake --install build
+    cmake --install build && \
+    cp -a deps/picotls/include/picotls* deps/quicly/include/quicly* /usr/local/include
 
 
 ARG MUSTACHE_C_REVISION=c1948c599edfe48c6099ed70ab1d5911d8c3ddc8
 ARG MUSTACHE_C_REVISION=c1948c599edfe48c6099ed70ab1d5911d8c3ddc8
 
 

+ 25 - 25
frameworks/C/h2o/src/database.c

@@ -51,7 +51,7 @@ typedef struct {
 	size_t query_num;
 	size_t query_num;
 	uint_fast32_t flags;
 	uint_fast32_t flags;
 	int sd;
 	int sd;
-	h2o_timeout_entry_t timeout;
+	h2o_timer_t timer;
 } db_conn_t;
 } db_conn_t;
 
 
 typedef struct {
 typedef struct {
@@ -65,11 +65,11 @@ static int do_execute_query(db_conn_t *conn, db_query_param_t *param);
 static void error_notification(db_conn_pool_t *pool, bool timeout, const char *error_string);
 static void error_notification(db_conn_pool_t *pool, bool timeout, const char *error_string);
 static void on_database_connect_error(db_conn_t *conn, bool timeout, const char *error_string);
 static void on_database_connect_error(db_conn_t *conn, bool timeout, const char *error_string);
 static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err);
 static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err);
-static void on_database_connect_timeout(h2o_timeout_entry_t *entry);
+static void on_database_connect_timeout(h2o_timer_t *timer);
 static void on_database_connect_write_ready(h2o_socket_t *sock, const char *err);
 static void on_database_connect_write_ready(h2o_socket_t *sock, const char *err);
 static void on_database_error(db_conn_t *conn, const char *error_string);
 static void on_database_error(db_conn_t *conn, const char *error_string);
 static void on_database_read_ready(h2o_socket_t *sock, const char *err);
 static void on_database_read_ready(h2o_socket_t *sock, const char *err);
-static void on_database_timeout(h2o_timeout_entry_t *timeout);
+static void on_database_timeout(h2o_timer_t *timer);
 static void on_database_write_ready(h2o_socket_t *sock, const char *err);
 static void on_database_write_ready(h2o_socket_t *sock, const char *err);
 static void poll_database_connection(h2o_socket_t *sock, const char *err);
 static void poll_database_connection(h2o_socket_t *sock, const char *err);
 static void prepare_statements(db_conn_t *conn);
 static void prepare_statements(db_conn_t *conn);
@@ -147,9 +147,9 @@ static int do_execute_query(db_conn_t *conn, db_query_param_t *param)
 		h2o_socket_notify_write(conn->sock, on_database_write_ready);
 		h2o_socket_notify_write(conn->sock, on_database_write_ready);
 
 
 	if (!conn->queries.head && !(conn->flags & (EXPECT_SYNC | IGNORE_RESULT))) {
 	if (!conn->queries.head && !(conn->flags & (EXPECT_SYNC | IGNORE_RESULT))) {
-		assert(!h2o_timeout_is_linked(&conn->timeout));
-		conn->timeout.cb = on_database_timeout;
-		h2o_timeout_link(conn->pool->loop, &conn->pool->timeout, &conn->timeout);
+		assert(!h2o_timer_is_linked(&conn->timer));
+		conn->timer.cb = on_database_timeout;
+		h2o_timer_link(conn->pool->loop, conn->pool->config->db_timeout * MS_IN_S, &conn->timer);
 	}
 	}
 
 
 	param->l.next = NULL;
 	param->l.next = NULL;
@@ -191,7 +191,7 @@ static void on_database_connect_error(db_conn_t *conn, bool timeout, const char
 {
 {
 	db_conn_pool_t * const pool = conn->pool;
 	db_conn_pool_t * const pool = conn->pool;
 
 
-	h2o_timeout_unlink(&conn->timeout);
+	h2o_timer_unlink(&conn->timer);
 	h2o_socket_read_stop(conn->sock);
 	h2o_socket_read_stop(conn->sock);
 	h2o_socket_close(conn->sock);
 	h2o_socket_close(conn->sock);
 	PQfinish(conn->conn);
 	PQfinish(conn->conn);
@@ -236,7 +236,7 @@ static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err)
 					break;
 					break;
 				case PGRES_PIPELINE_SYNC:
 				case PGRES_PIPELINE_SYNC:
 					PQclear(result);
 					PQclear(result);
-					h2o_timeout_unlink(&conn->timeout);
+					h2o_timer_unlink(&conn->timer);
 					h2o_socket_read_stop(conn->sock);
 					h2o_socket_read_stop(conn->sock);
 					h2o_socket_read_start(conn->sock, on_database_read_ready);
 					h2o_socket_read_start(conn->sock, on_database_read_ready);
 					process_queries(conn);
 					process_queries(conn);
@@ -253,9 +253,9 @@ static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err)
 	}
 	}
 }
 }
 
 
-static void on_database_connect_timeout(h2o_timeout_entry_t *entry)
+static void on_database_connect_timeout(h2o_timer_t *timer)
 {
 {
-	db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, timeout, entry);
+	db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, timer, timer);
 
 
 	ERROR(DB_TIMEOUT_ERROR);
 	ERROR(DB_TIMEOUT_ERROR);
 	on_database_connect_error(conn, true, DB_TIMEOUT_ERROR);
 	on_database_connect_error(conn, true, DB_TIMEOUT_ERROR);
@@ -356,9 +356,11 @@ static void on_database_read_ready(h2o_socket_t *sock, const char *err)
 
 
 			if (param->on_result(param, result) == DONE) {
 			if (param->on_result(param, result) == DONE) {
 				conn->query_num++;
 				conn->query_num++;
-				h2o_timeout_unlink(&conn->timeout);
-				conn->timeout.cb = on_database_timeout;
-				h2o_timeout_link(conn->pool->loop, &conn->pool->timeout, &conn->timeout);
+				h2o_timer_unlink(&conn->timer);
+				conn->timer.cb = on_database_timeout;
+				h2o_timer_link(conn->pool->loop,
+				               conn->pool->config->db_timeout * MS_IN_S,
+				               &conn->timer);
 				conn->flags |= EXPECT_SYNC;
 				conn->flags |= EXPECT_SYNC;
 				conn->queries.head = next;
 				conn->queries.head = next;
 
 
@@ -373,7 +375,7 @@ static void on_database_read_ready(h2o_socket_t *sock, const char *err)
 		}
 		}
 		else {
 		else {
 			assert(!result);
 			assert(!result);
-			h2o_timeout_unlink(&conn->timeout);
+			h2o_timer_unlink(&conn->timer);
 			break;
 			break;
 		}
 		}
 	}
 	}
@@ -384,9 +386,9 @@ static void on_database_read_ready(h2o_socket_t *sock, const char *err)
 	process_queries(conn);
 	process_queries(conn);
 }
 }
 
 
-static void on_database_timeout(h2o_timeout_entry_t *timeout)
+static void on_database_timeout(h2o_timer_t *timer)
 {
 {
-	db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, timeout, timeout);
+	db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, timer, timer);
 
 
 	ERROR(DB_TIMEOUT_ERROR);
 	ERROR(DB_TIMEOUT_ERROR);
 
 
@@ -456,7 +458,7 @@ static void poll_database_connection(h2o_socket_t *sock, const char *err)
 
 
 				return;
 				return;
 			case PGRES_POLLING_OK:
 			case PGRES_POLLING_OK:
-				h2o_timeout_unlink(&conn->timeout);
+				h2o_timer_unlink(&conn->timer);
 				h2o_socket_read_stop(conn->sock);
 				h2o_socket_read_stop(conn->sock);
 
 
 				if (PQsetnonblocking(conn->conn, 1)) {
 				if (PQsetnonblocking(conn->conn, 1)) {
@@ -532,8 +534,8 @@ static void prepare_statements(db_conn_t *conn)
 		}
 		}
 
 
 		conn->prepared_statement = NULL;
 		conn->prepared_statement = NULL;
-		conn->timeout.cb = on_database_connect_timeout;
-		h2o_timeout_link(conn->pool->loop, &conn->pool->timeout, &conn->timeout);
+		conn->timer.cb = on_database_connect_timeout;
+		h2o_timer_link(conn->pool->loop, conn->pool->config->db_timeout * MS_IN_S, &conn->timer);
 		h2o_socket_read_start(conn->sock, on_database_connect_read_ready);
 		h2o_socket_read_start(conn->sock, on_database_connect_read_ready);
 		on_database_connect_write_ready(conn->sock, NULL);
 		on_database_connect_write_ready(conn->sock, NULL);
 	}
 	}
@@ -579,7 +581,7 @@ static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn)
 	if (conn) {
 	if (conn) {
 		PGconn * const c = conn->conn;
 		PGconn * const c = conn->conn;
 
 
-		h2o_timeout_unlink(&conn->timeout);
+		h2o_timer_unlink(&conn->timer);
 		h2o_socket_read_stop(conn->sock);
 		h2o_socket_read_stop(conn->sock);
 		h2o_socket_close(conn->sock);
 		h2o_socket_close(conn->sock);
 
 
@@ -620,8 +622,8 @@ static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn)
 		conn->prepared_statement = pool->prepared_statements;
 		conn->prepared_statement = pool->prepared_statements;
 		conn->queries.tail = &conn->queries.head;
 		conn->queries.tail = &conn->queries.head;
 		conn->query_num = pool->config->max_pipeline_query_num;
 		conn->query_num = pool->config->max_pipeline_query_num;
-		conn->timeout.cb = on_database_connect_timeout;
-		h2o_timeout_link(pool->loop, &pool->timeout, &conn->timeout);
+		conn->timer.cb = on_database_connect_timeout;
+		h2o_timer_link(pool->loop, pool->config->db_timeout * MS_IN_S, &conn->timer);
 		h2o_socket_notify_write(conn->sock, poll_database_connection);
 		h2o_socket_notify_write(conn->sock, poll_database_connection);
 		return;
 		return;
 	}
 	}
@@ -697,7 +699,7 @@ void free_database_connection_pool(db_conn_pool_t *pool)
 			assert(conn->query_num == pool->config->max_pipeline_query_num);
 			assert(conn->query_num == pool->config->max_pipeline_query_num);
 			assert(conn->flags & IDLE);
 			assert(conn->flags & IDLE);
 			assert(!(conn->flags & (EXPECT_SYNC | IGNORE_RESULT | RESET)));
 			assert(!(conn->flags & (EXPECT_SYNC | IGNORE_RESULT | RESET)));
-			assert(!h2o_timeout_is_linked(&conn->timeout));
+			assert(!h2o_timer_is_linked(&conn->timer));
 			h2o_socket_read_stop(conn->sock);
 			h2o_socket_read_stop(conn->sock);
 			h2o_socket_close(conn->sock);
 			h2o_socket_close(conn->sock);
 			PQfinish(conn->conn);
 			PQfinish(conn->conn);
@@ -707,7 +709,6 @@ void free_database_connection_pool(db_conn_pool_t *pool)
 		} while (pool->conn);
 		} while (pool->conn);
 
 
 	assert(num + pool->conn_num == pool->config->max_db_conn_num);
 	assert(num + pool->conn_num == pool->config->max_db_conn_num);
-	h2o_timeout_dispose(pool->loop, &pool->timeout);
 }
 }
 
 
 void initialize_database_connection_pool(const char *conninfo,
 void initialize_database_connection_pool(const char *conninfo,
@@ -724,7 +725,6 @@ void initialize_database_connection_pool(const char *conninfo,
 	pool->queries.tail = &pool->queries.head;
 	pool->queries.tail = &pool->queries.head;
 	pool->conn_num = config->max_db_conn_num;
 	pool->conn_num = config->max_db_conn_num;
 	pool->query_num = config->max_query_num;
 	pool->query_num = config->max_query_num;
-	h2o_timeout_init(loop, &pool->timeout, config->db_timeout * MS_IN_S);
 }
 }
 
 
 void remove_prepared_statements(list_t *prepared_statements)
 void remove_prepared_statements(list_t *prepared_statements)

+ 0 - 1
frameworks/C/h2o/src/database.h

@@ -68,7 +68,6 @@ typedef struct {
 	queue_t queries;
 	queue_t queries;
 	size_t conn_num;
 	size_t conn_num;
 	size_t query_num;
 	size_t query_num;
-	h2o_timeout_t timeout;
 } db_conn_pool_t;
 } db_conn_pool_t;
 
 
 void add_prepared_statement(const char *name, const char *query, list_t **prepared_statements);
 void add_prepared_statement(const char *name, const char *query, list_t **prepared_statements);

+ 1 - 0
frameworks/C/h2o/src/global_data.h

@@ -59,6 +59,7 @@ typedef struct {
 	SSL_CTX *ssl_ctx;
 	SSL_CTX *ssl_ctx;
 	size_t memory_alignment;
 	size_t memory_alignment;
 	int signal_fd;
 	int signal_fd;
+	h2o_buffer_prototype_t buffer_prototype;
 	h2o_globalconf_t h2o_config;
 	h2o_globalconf_t h2o_config;
 	request_handler_data_t request_handler_data;
 	request_handler_data_t request_handler_data;
 } global_data_t;
 } global_data_t;

+ 14 - 62
frameworks/C/h2o/src/handlers/fortune.c

@@ -41,7 +41,6 @@
 #define FORTUNE_TABLE_NAME "Fortune"
 #define FORTUNE_TABLE_NAME "Fortune"
 #define FORTUNE_QUERY "SELECT * FROM " FORTUNE_TABLE_NAME ";"
 #define FORTUNE_QUERY "SELECT * FROM " FORTUNE_TABLE_NAME ";"
 #define ID_FIELD_NAME "id"
 #define ID_FIELD_NAME "id"
-#define MAX_IOVEC 128
 #define MESSAGE_FIELD_NAME "message"
 #define MESSAGE_FIELD_NAME "message"
 #define NEW_FORTUNE_ID "0"
 #define NEW_FORTUNE_ID "0"
 #define NEW_FORTUNE_MESSAGE "Additional fortune added at request time."
 #define NEW_FORTUNE_MESSAGE "Additional fortune added at request time."
@@ -54,20 +53,10 @@ typedef struct {
 } fortune_t;
 } fortune_t;
 
 
 typedef struct {
 typedef struct {
-	list_t l;
-	size_t iovcnt;
-	size_t max_iovcnt;
-	h2o_iovec_t iov[];
-} iovec_list_t;
-
-typedef struct {
-	PGresult *data;
+	h2o_buffer_t *buffer;
 	const fortune_t *fortune_iter;
 	const fortune_t *fortune_iter;
-	list_t *iovec_list;
-	iovec_list_t *iovec_list_iter;
 	h2o_req_t *req;
 	h2o_req_t *req;
 	list_t *result;
 	list_t *result;
-	size_t content_length;
 	size_t num_result;
 	size_t num_result;
 	bool cleanup;
 	bool cleanup;
 	db_query_param_t param;
 	db_query_param_t param;
@@ -86,7 +75,6 @@ static uintmax_t add_iovec(mustache_api_t *api,
 static void cleanup_fortunes(fortune_ctx_t *fortune_ctx);
 static void cleanup_fortunes(fortune_ctx_t *fortune_ctx);
 static void cleanup_request(void *data);
 static void cleanup_request(void *data);
 static int compare_fortunes(const list_t *x, const list_t *y);
 static int compare_fortunes(const list_t *x, const list_t *y);
-static void complete_fortunes(struct st_h2o_generator_t *self, h2o_req_t *req);
 static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req);
 static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req);
 static void on_fortune_error(db_query_param_t *param, const char *error_string);
 static void on_fortune_error(db_query_param_t *param, const char *error_string);
 static result_return_t on_fortune_result(db_query_param_t *param, PGresult *result);
 static result_return_t on_fortune_result(db_query_param_t *param, PGresult *result);
@@ -120,29 +108,15 @@ static uintmax_t add_iovec(mustache_api_t *api,
 	IGNORE_FUNCTION_PARAMETER(api);
 	IGNORE_FUNCTION_PARAMETER(api);
 
 
 	fortune_ctx_t * const fortune_ctx = userdata;
 	fortune_ctx_t * const fortune_ctx = userdata;
-	iovec_list_t *iovec_list = fortune_ctx->iovec_list_iter;
-
-	if (iovec_list->iovcnt >= iovec_list->max_iovcnt) {
-		const size_t sz = offsetof(iovec_list_t, iov) + MAX_IOVEC * sizeof(h2o_iovec_t);
-
-		iovec_list = h2o_mem_alloc_pool(&fortune_ctx->req->pool, sz);
-		memset(iovec_list, 0, offsetof(iovec_list_t, iov));
-		iovec_list->max_iovcnt = MAX_IOVEC;
-		fortune_ctx->iovec_list_iter->l.next = &iovec_list->l;
-		fortune_ctx->iovec_list_iter = iovec_list;
-	}
 
 
-	memset(iovec_list->iov + iovec_list->iovcnt, 0, sizeof(*iovec_list->iov));
-	iovec_list->iov[iovec_list->iovcnt].base = (char *) buffer;
-	iovec_list->iov[iovec_list->iovcnt++].len = buffer_size;
-	fortune_ctx->content_length += buffer_size;
+	h2o_buffer_append(&fortune_ctx->buffer, buffer, buffer_size);
 	return 1;
 	return 1;
 }
 }
 
 
 static void cleanup_fortunes(fortune_ctx_t *fortune_ctx)
 static void cleanup_fortunes(fortune_ctx_t *fortune_ctx)
 {
 {
-	if (fortune_ctx->data)
-		PQclear(fortune_ctx->data);
+	if (fortune_ctx->buffer)
+		h2o_buffer_dispose(&fortune_ctx->buffer);
 
 
 	free(fortune_ctx);
 	free(fortune_ctx);
 }
 }
@@ -170,22 +144,6 @@ static int compare_fortunes(const list_t *x, const list_t *y)
 	return ret;
 	return ret;
 }
 }
 
 
-static void complete_fortunes(struct st_h2o_generator_t *self, h2o_req_t *req)
-{
-	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, generator, self);
-	iovec_list_t * const iovec_list = H2O_STRUCT_FROM_MEMBER(iovec_list_t,
-	                                                         l,
-	                                                         fortune_ctx->iovec_list);
-
-	fortune_ctx->iovec_list = iovec_list->l.next;
-
-	const h2o_send_state_t state = fortune_ctx->iovec_list ?
-	                               H2O_SEND_STATE_IN_PROGRESS :
-	                               H2O_SEND_STATE_FINAL;
-
-	h2o_send(req, iovec_list->iov, iovec_list->iovcnt, state);
-}
-
 static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
 static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
 {
 {
 	IGNORE_FUNCTION_PARAMETER(self);
 	IGNORE_FUNCTION_PARAMETER(self);
@@ -194,7 +152,7 @@ static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
 	                                                      event_loop.h2o_ctx,
 	                                                      event_loop.h2o_ctx,
 	                                                      req->conn->ctx);
 	                                                      req->conn->ctx);
 	fortune_ctx_t * const fortune_ctx = h2o_mem_alloc(sizeof(*fortune_ctx));
 	fortune_ctx_t * const fortune_ctx = h2o_mem_alloc(sizeof(*fortune_ctx));
-	fortune_t * const fortune = h2o_mem_alloc_pool(&req->pool, sizeof(*fortune));
+	fortune_t * const fortune = h2o_mem_alloc_pool(&req->pool, fortune_t, 1);
 	fortune_ctx_t ** const p = h2o_mem_alloc_shared(&req->pool, sizeof(*p), cleanup_request);
 	fortune_ctx_t ** const p = h2o_mem_alloc_shared(&req->pool, sizeof(*p), cleanup_request);
 
 
 	*p = fortune_ctx;
 	*p = fortune_ctx;
@@ -204,7 +162,6 @@ static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
 	fortune->message.base = NEW_FORTUNE_MESSAGE;
 	fortune->message.base = NEW_FORTUNE_MESSAGE;
 	fortune->message.len = sizeof(NEW_FORTUNE_MESSAGE) - 1;
 	fortune->message.len = sizeof(NEW_FORTUNE_MESSAGE) - 1;
 	memset(fortune_ctx, 0, sizeof(*fortune_ctx));
 	memset(fortune_ctx, 0, sizeof(*fortune_ctx));
-	fortune_ctx->generator.proceed = complete_fortunes;
 	fortune_ctx->num_result = 1;
 	fortune_ctx->num_result = 1;
 	fortune_ctx->param.command = FORTUNE_TABLE_NAME;
 	fortune_ctx->param.command = FORTUNE_TABLE_NAME;
 	fortune_ctx->param.on_error = on_fortune_error;
 	fortune_ctx->param.on_error = on_fortune_error;
@@ -240,7 +197,6 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 	const bool cleanup = fortune_ctx->cleanup;
 	const bool cleanup = fortune_ctx->cleanup;
 
 
 	fortune_ctx->cleanup = true;
 	fortune_ctx->cleanup = true;
-	fortune_ctx->data = result;
 
 
 	if (cleanup)
 	if (cleanup)
 		cleanup_fortunes(fortune_ctx);
 		cleanup_fortunes(fortune_ctx);
@@ -251,7 +207,8 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 
 
 		for (size_t i = 0; i < num_rows; i++) {
 		for (size_t i = 0; i < num_rows; i++) {
 			fortune_t * const fortune = h2o_mem_alloc_pool(&fortune_ctx->req->pool,
 			fortune_t * const fortune = h2o_mem_alloc_pool(&fortune_ctx->req->pool,
-			                                               sizeof(*fortune));
+			                                               fortune_t,
+			                                               1);
 			char * const id = PQgetvalue(result, i, 0);
 			char * const id = PQgetvalue(result, i, 0);
 			char * const message = PQgetvalue(result, i, 1);
 			char * const message = PQgetvalue(result, i, 1);
 			const size_t id_len = PQgetlength(result, i, 0);
 			const size_t id_len = PQgetlength(result, i, 0);
@@ -275,28 +232,22 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
 		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
 		                                                      event_loop.h2o_ctx,
 		                                                      event_loop.h2o_ctx,
 		                                                      fortune_ctx->req->conn->ctx);
 		                                                      fortune_ctx->req->conn->ctx);
-		const size_t iovcnt = MIN(MAX_IOVEC, fortune_ctx->num_result * 5 + 2);
-		const size_t sz = offsetof(iovec_list_t, iov) + iovcnt * sizeof(h2o_iovec_t);
-		iovec_list_t * const iovec_list = h2o_mem_alloc_pool(&fortune_ctx->req->pool, sz);
 
 
-		memset(iovec_list, 0, offsetof(iovec_list_t, iov));
-		iovec_list->max_iovcnt = iovcnt;
-		fortune_ctx->iovec_list_iter = iovec_list;
+		h2o_buffer_init(&fortune_ctx->buffer,
+		                &ctx->global_thread_data->global_data->buffer_prototype);
 		fortune_ctx->result = sort_list(fortune_ctx->result, compare_fortunes);
 		fortune_ctx->result = sort_list(fortune_ctx->result, compare_fortunes);
 
 
 		struct mustache_token_t * const fortunes_template =
 		struct mustache_token_t * const fortunes_template =
 			ctx->global_thread_data->global_data->request_handler_data.fortunes_template;
 			ctx->global_thread_data->global_data->request_handler_data.fortunes_template;
 
 
 		if (mustache_render(&api, fortune_ctx, fortunes_template)) {
 		if (mustache_render(&api, fortune_ctx, fortunes_template)) {
-			fortune_ctx->iovec_list = iovec_list->l.next;
-			set_default_response_param(HTML, fortune_ctx->content_length, fortune_ctx->req);
+			set_default_response_param(HTML, fortune_ctx->buffer->size, fortune_ctx->req);
 			h2o_start_response(fortune_ctx->req, &fortune_ctx->generator);
 			h2o_start_response(fortune_ctx->req, &fortune_ctx->generator);
 
 
-			const h2o_send_state_t state = fortune_ctx->iovec_list ?
-			                               H2O_SEND_STATE_IN_PROGRESS :
-			                               H2O_SEND_STATE_FINAL;
+			h2o_iovec_t body = {.base = fortune_ctx->buffer->bytes,
+			                    .len = fortune_ctx->buffer->size};
 
 
-			h2o_send(fortune_ctx->req, iovec_list->iov, iovec_list->iovcnt, state);
+			h2o_send(fortune_ctx->req, &body, 1, H2O_SEND_STATE_FINAL);
 		}
 		}
 		else
 		else
 			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, fortune_ctx->req);
 			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, fortune_ctx->req);
@@ -306,6 +257,7 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 		send_error(BAD_GATEWAY, DB_ERROR, fortune_ctx->req);
 		send_error(BAD_GATEWAY, DB_ERROR, fortune_ctx->req);
 	}
 	}
 
 
+	PQclear(result);
 	return DONE;
 	return DONE;
 }
 }
 
 

+ 1 - 0
frameworks/C/h2o/src/main.c

@@ -97,6 +97,7 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
 	sigset_t signals;
 	sigset_t signals;
 
 
 	memset(global_data, 0, sizeof(*global_data));
 	memset(global_data, 0, sizeof(*global_data));
+	global_data->buffer_prototype._initial_buf.capacity = H2O_SOCKET_INITIAL_INPUT_BUFFER_SIZE;
 	global_data->memory_alignment = get_maximum_cache_line_size();
 	global_data->memory_alignment = get_maximum_cache_line_size();
 	CHECK_ERRNO(sigemptyset, &signals);
 	CHECK_ERRNO(sigemptyset, &signals);
 #ifdef NDEBUG
 #ifdef NDEBUG

+ 1 - 0
frameworks/C/h2o/src/request_handler.c

@@ -188,6 +188,7 @@ void set_default_response_param(content_type_t content_type, size_t content_leng
 	req->res.content_length = content_length;
 	req->res.content_length = content_length;
 	req->res.status = OK;
 	req->res.status = OK;
 	req->res.reason = status_code_to_string(req->res.status);
 	req->res.reason = status_code_to_string(req->res.status);
+	h2o_resp_add_date_header(req);
 
 
 	switch (content_type) {
 	switch (content_type) {
 		case JSON:
 		case JSON:

+ 8 - 8
frameworks/C/h2o/src/thread.c

@@ -38,26 +38,26 @@
 #include "thread.h"
 #include "thread.h"
 
 
 static void *run_thread(void *arg);
 static void *run_thread(void *arg);
-static void set_thread_memory_allocation_policy(size_t thread_num);
+static void set_thread_memory_allocation_policy(void);
 
 
 static void *run_thread(void *arg)
 static void *run_thread(void *arg)
 {
 {
 	thread_context_t ctx;
 	thread_context_t ctx;
 
 
 	initialize_thread_context(arg, false, &ctx);
 	initialize_thread_context(arg, false, &ctx);
-	set_thread_memory_allocation_policy(ctx.global_thread_data->config->thread_num);
+
+	// There is no need to set a memory allocation policy unless
+	// the application controls the processor affinity as well.
+	if (!(ctx.global_thread_data->config->thread_num % h2o_numproc()))
+		set_thread_memory_allocation_policy();
+
 	event_loop(&ctx);
 	event_loop(&ctx);
 	free_thread_context(&ctx);
 	free_thread_context(&ctx);
 	pthread_exit(NULL);
 	pthread_exit(NULL);
 }
 }
 
 
-static void set_thread_memory_allocation_policy(size_t thread_num)
+static void set_thread_memory_allocation_policy(void)
 {
 {
-	// There is no need to set a memory allocation policy unless
-	// the application controls the processor affinity as well.
-	if (thread_num % h2o_numproc())
-		return;
-
 	void *stack_addr;
 	void *stack_addr;
 	size_t stack_size;
 	size_t stack_size;
 	unsigned memory_node;
 	unsigned memory_node;