Browse Source

H2O: Make several improvements (#2574)

* H2O: Improve error logging

Also, do not include the raw database error messages in the HTTP
response bodies due to security concerns.

* H2O: Support HTTP and HTTPS simultaneously

* H2O: Make several TLS support improvements

* Disable the 3DES and RC4 ciphers because they are weak.
* Enable ECDH in order to add forward secrecy.
* Enable ALPN to support HTTP/2 properly.

The last two changes require that the application be built
and linked against OpenSSL versions greater than or equal
to 1.0.2.
Anton Kirilov 8 years ago
parent
commit
62c7325222

+ 6 - 6
frameworks/C/h2o/src/bitset.h

@@ -37,24 +37,24 @@ typedef uint_fast32_t bitset_base_t;
 	assert(s); \
 	assert(s); \
 	bitset_base_t (b)[((s) - 1) / (sizeof(bitset_base_t) * CHAR_BIT) + 1] = {[0] = 0}
 	bitset_base_t (b)[((s) - 1) / (sizeof(bitset_base_t) * CHAR_BIT) + 1] = {[0] = 0}
 
 
-static inline void bitset_set(size_t i, bitset_base_t *b, size_t num)
+static inline bool bitset_isset(size_t i, bitset_base_t *b, size_t num)
 {
 {
 	assert(i < num);
 	assert(i < num);
 
 
 	IGNORE_FUNCTION_PARAMETER(num);
 	IGNORE_FUNCTION_PARAMETER(num);
 
 
-	const bitset_base_t mask = ((bitset_base_t) 1) << (i % (sizeof(*b) * CHAR_BIT));
-
-	b[i / (sizeof(*b) * CHAR_BIT)] |= mask;
+	return (b[i / (sizeof(*b) * CHAR_BIT)] >> (i % (sizeof(*b) * CHAR_BIT))) & (bitset_base_t) 1;
 }
 }
 
 
-static inline bool bitset_isset(size_t i, bitset_base_t *b, size_t num)
+static inline void bitset_set(size_t i, bitset_base_t *b, size_t num)
 {
 {
 	assert(i < num);
 	assert(i < num);
 
 
 	IGNORE_FUNCTION_PARAMETER(num);
 	IGNORE_FUNCTION_PARAMETER(num);
 
 
-	return (b[i / (sizeof(*b) * CHAR_BIT)] >> (i % (sizeof(*b) * CHAR_BIT))) & (bitset_base_t) 1;
+	const bitset_base_t mask = ((bitset_base_t) 1) << (i % (sizeof(*b) * CHAR_BIT));
+
+	b[i / (sizeof(*b) * CHAR_BIT)] |= mask;
 }
 }
 
 
 #endif // BITSET_H_
 #endif // BITSET_H_

+ 62 - 57
frameworks/C/h2o/src/database.c

@@ -65,13 +65,32 @@ static const struct {
 	const char *query;
 	const char *query;
 } prepared_statement[] = {
 } prepared_statement[] = {
 	{FORTUNE_TABLE_NAME, "SELECT * FROM " FORTUNE_TABLE_NAME ";"},
 	{FORTUNE_TABLE_NAME, "SELECT * FROM " FORTUNE_TABLE_NAME ";"},
-	{WORLD_TABLE_NAME,
-	 "SELECT * FROM " WORLD_TABLE_NAME " WHERE " ID_FIELD_NAME " = $1::integer;"},
+	{WORLD_TABLE_NAME, "SELECT * FROM " WORLD_TABLE_NAME " WHERE " ID_FIELD_NAME " = $1::integer;"},
 	{UPDATE_QUERY_NAME,
 	{UPDATE_QUERY_NAME,
 	 "UPDATE " WORLD_TABLE_NAME " SET randomNumber = $2::integer "
 	 "UPDATE " WORLD_TABLE_NAME " SET randomNumber = $2::integer "
 	 "WHERE " ID_FIELD_NAME " = $1::integer;"},
 	 "WHERE " ID_FIELD_NAME " = $1::integer;"},
 };
 };
 
 
+static int do_database_write(db_conn_t *db_conn)
+{
+	assert(db_conn->param);
+
+	int ret = db_conn->param->on_write_ready(db_conn->param, db_conn->conn);
+
+	if (!ret)
+		db_conn->flags &= ~IS_WRITING;
+	else if (ret < 0) {
+		ERROR(PQerrorMessage(db_conn->conn));
+		on_database_error(db_conn, DB_ERROR);
+	}
+	else if (start_database_write_polling(db_conn))
+		on_database_error(db_conn, DB_ERROR);
+	else
+		ret = 0;
+
+	return ret;
+}
+
 static void do_execute_query(db_conn_t *db_conn)
 static void do_execute_query(db_conn_t *db_conn)
 {
 {
 	const int ec = db_conn->param->flags & IS_PREPARED ?
 	const int ec = db_conn->param->flags & IS_PREPARED ?
@@ -95,8 +114,10 @@ static void do_execute_query(db_conn_t *db_conn)
 		h2o_socket_read_start(db_conn->sock, on_database_read_ready);
 		h2o_socket_read_start(db_conn->sock, on_database_read_ready);
 		on_database_write_ready(&db_conn->on_write_ready);
 		on_database_write_ready(&db_conn->on_write_ready);
 	}
 	}
-	else
-		on_database_error(db_conn, PQerrorMessage(db_conn->conn));
+	else {
+		ERROR(PQerrorMessage(db_conn->conn));
+		on_database_error(db_conn, DB_ERROR);
+	}
 }
 }
 
 
 static void error_notification(thread_context_t *ctx, bool timeout, const char *error_string)
 static void error_notification(thread_context_t *ctx, bool timeout, const char *error_string)
@@ -167,12 +188,14 @@ static void on_database_read_ready(h2o_socket_t *db_sock, const char *err)
 {
 {
 	db_conn_t * const db_conn = db_sock->data;
 	db_conn_t * const db_conn = db_sock->data;
 
 
-	if (!err) {
+	if (err)
+		ERROR(err);
+	else {
 		if (PQconsumeInput(db_conn->conn)) {
 		if (PQconsumeInput(db_conn->conn)) {
 			const int send_status = PQflush(db_conn->conn);
 			const int send_status = PQflush(db_conn->conn);
 
 
 			if (send_status > 0 && start_database_write_polling(db_conn)) {
 			if (send_status > 0 && start_database_write_polling(db_conn)) {
-				on_database_error(db_conn, EPOLL_ERR_MSG);
+				on_database_error(db_conn, DB_ERROR);
 				return;
 				return;
 			}
 			}
 
 
@@ -196,8 +219,12 @@ static void on_database_read_ready(h2o_socket_t *db_sock, const char *err)
 							default:
 							default:
 								break;
 								break;
 						}
 						}
-					else if (result)
+					else if (result) {
+						if (PQresultStatus(result) != PGRES_COMMAND_OK)
+							LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
+
 						PQclear(result);
 						PQclear(result);
+					}
 
 
 					if (!result) {
 					if (!result) {
 						assert(!db_conn->param);
 						assert(!db_conn->param);
@@ -212,10 +239,10 @@ static void on_database_read_ready(h2o_socket_t *db_sock, const char *err)
 			}
 			}
 		}
 		}
 
 
-		err = PQerrorMessage(db_conn->conn);
+		ERROR(PQerrorMessage(db_conn->conn));
 	}
 	}
 
 
-	on_database_error(db_conn, err);
+	on_database_error(db_conn, DB_ERROR);
 }
 }
 
 
 static void on_database_timeout(h2o_timeout_entry_t *entry)
 static void on_database_timeout(h2o_timeout_entry_t *entry)
@@ -241,10 +268,12 @@ static void on_database_write_ready(void *data)
 			if (db_conn->flags & IS_WRITING && db_conn->param)
 			if (db_conn->flags & IS_WRITING && db_conn->param)
 				do_database_write(db_conn);
 				do_database_write(db_conn);
 		}
 		}
-		else if (send_status < 0)
-			on_database_error(db_conn, PQerrorMessage(db_conn->conn));
+		else if (send_status < 0) {
+			LIBRARY_ERROR("PQflush", PQerrorMessage(db_conn->conn));
+			on_database_error(db_conn, DB_ERROR);
+		}
 		else if (send_status > 0 && start_database_write_polling(db_conn))
 		else if (send_status > 0 && start_database_write_polling(db_conn))
-			on_database_error(db_conn, EPOLL_ERR_MSG);
+			on_database_error(db_conn, DB_ERROR);
 	}
 	}
 	else
 	else
 		poll_database_connection(db_conn->sock, NULL);
 		poll_database_connection(db_conn->sock, NULL);
@@ -254,22 +283,22 @@ static void poll_database_connection(h2o_socket_t *db_sock, const char *err)
 {
 {
 	db_conn_t * const db_conn = db_sock->data;
 	db_conn_t * const db_conn = db_sock->data;
 
 
-	if (!err) {
+	if (err)
+		ERROR(err);
+	else {
 		const PostgresPollingStatusType status = db_conn->flags & IS_RESETTING ?
 		const PostgresPollingStatusType status = db_conn->flags & IS_RESETTING ?
 		                                         PQresetPoll(db_conn->conn) :
 		                                         PQresetPoll(db_conn->conn) :
 		                                         PQconnectPoll(db_conn->conn);
 		                                         PQconnectPoll(db_conn->conn);
 
 
 		switch (status) {
 		switch (status) {
 			case PGRES_POLLING_WRITING:
 			case PGRES_POLLING_WRITING:
-				if (start_database_write_polling(db_conn)) {
-					err = EPOLL_ERR_MSG;
+				if (start_database_write_polling(db_conn))
 					break;
 					break;
-				}
 
 
 				return;
 				return;
 			case PGRES_POLLING_OK:
 			case PGRES_POLLING_OK:
 				if (PQsetnonblocking(db_conn->conn, 1)) {
 				if (PQsetnonblocking(db_conn->conn, 1)) {
-					err = PQerrorMessage(db_conn->conn);
+					LIBRARY_ERROR("PQsetnonblocking", PQerrorMessage(db_conn->conn));
 					break;
 					break;
 				}
 				}
 
 
@@ -280,11 +309,11 @@ static void poll_database_connection(h2o_socket_t *db_sock, const char *err)
 			case PGRES_POLLING_READING:
 			case PGRES_POLLING_READING:
 				return;
 				return;
 			default:
 			default:
-				err = PQerrorMessage(db_conn->conn);
+				ERROR(PQerrorMessage(db_conn->conn));
 		}
 		}
 	}
 	}
 
 
-	on_database_connect_error(db_conn, false, err);
+	on_database_connect_error(db_conn, false, DB_ERROR);
 }
 }
 
 
 static void process_query(db_conn_t *db_conn)
 static void process_query(db_conn_t *db_conn)
@@ -303,8 +332,10 @@ static void process_query(db_conn_t *db_conn)
 			h2o_socket_read_start(db_conn->sock, on_database_read_ready);
 			h2o_socket_read_start(db_conn->sock, on_database_read_ready);
 			on_database_write_ready(&db_conn->on_write_ready);
 			on_database_write_ready(&db_conn->on_write_ready);
 		}
 		}
-		else
-			on_database_connect_error(db_conn, false, PQerrorMessage(db_conn->conn));
+		else {
+			LIBRARY_ERROR("PQsendPrepare", PQerrorMessage(db_conn->conn));
+			on_database_connect_error(db_conn, false, DB_ERROR);
+		}
 	}
 	}
 	else if (db_conn->ctx->db_state.query_num) {
 	else if (db_conn->ctx->db_state.query_num) {
 		db_conn->ctx->db_state.query_num--;
 		db_conn->ctx->db_state.query_num--;
@@ -329,9 +360,6 @@ static void process_query(db_conn_t *db_conn)
 
 
 static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 {
 {
-	char buf[128] = "";
-	const char *error_string = buf;
-
 	if (db_conn) {
 	if (db_conn) {
 		db_conn->prep_stmt_idx = 0;
 		db_conn->prep_stmt_idx = 0;
 		db_conn->flags = IS_RESETTING;
 		db_conn->flags = IS_RESETTING;
@@ -341,8 +369,7 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 		h2o_socket_close(db_conn->sock);
 		h2o_socket_close(db_conn->sock);
 
 
 		if (!PQresetStart(db_conn->conn)) {
 		if (!PQresetStart(db_conn->conn)) {
-			strncpy(buf, PQerrorMessage(db_conn->conn), sizeof(buf));
-			buf[sizeof(buf) - 1] = '\0';
+			LIBRARY_ERROR("PQresetStart", PQerrorMessage(db_conn->conn));
 			goto error_dup;
 			goto error_dup;
 		}
 		}
 	}
 	}
@@ -351,7 +378,7 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 		db_conn = calloc(1, sizeof(*db_conn));
 		db_conn = calloc(1, sizeof(*db_conn));
 
 
 		if (!db_conn) {
 		if (!db_conn) {
-			error_string = MEM_ALLOC_ERR_MSG;
+			STANDARD_ERROR("calloc");
 			goto error;
 			goto error;
 		}
 		}
 
 
@@ -360,13 +387,13 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 		db_conn->conn = PQconnectStart(conninfo);
 		db_conn->conn = PQconnectStart(conninfo);
 
 
 		if (!db_conn->conn) {
 		if (!db_conn->conn) {
-			error_string = MEM_ALLOC_ERR_MSG;
+			errno = ENOMEM;
+			STANDARD_ERROR("PQconnectStart");
 			goto error_connect;
 			goto error_connect;
 		}
 		}
 
 
 		if (PQstatus(db_conn->conn) == CONNECTION_BAD) {
 		if (PQstatus(db_conn->conn) == CONNECTION_BAD) {
-			strncpy(buf, PQerrorMessage(db_conn->conn), sizeof(buf));
-			buf[sizeof(buf) - 1] = '\0';
+			LIBRARY_ERROR("PQstatus", PQerrorMessage(db_conn->conn));
 			goto error_dup;
 			goto error_dup;
 		}
 		}
 	}
 	}
@@ -374,18 +401,14 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 	const int sd = dup(PQsocket(db_conn->conn));
 	const int sd = dup(PQsocket(db_conn->conn));
 
 
 	if (sd < 0) {
 	if (sd < 0) {
-		if (strerror_r(errno, buf, sizeof(buf)))
-			*buf = '\0';
-
+		STANDARD_ERROR("dup");
 		goto error_dup;
 		goto error_dup;
 	}
 	}
 
 
 	const int flags = fcntl(sd, F_GETFD);
 	const int flags = fcntl(sd, F_GETFD);
 
 
 	if (flags < 0 || fcntl(sd, F_SETFD, flags | FD_CLOEXEC)) {
 	if (flags < 0 || fcntl(sd, F_SETFD, flags | FD_CLOEXEC)) {
-		if (strerror_r(errno, buf, sizeof(buf)))
-			*buf = '\0';
-
+		STANDARD_ERROR("fcntl");
 		goto error_dup;
 		goto error_dup;
 	}
 	}
 
 
@@ -408,10 +431,10 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 		h2o_socket_read_stop(db_conn->sock);
 		h2o_socket_read_stop(db_conn->sock);
 		h2o_timeout_unlink(&db_conn->h2o_timeout_entry);
 		h2o_timeout_unlink(&db_conn->h2o_timeout_entry);
 		h2o_socket_close(db_conn->sock);
 		h2o_socket_close(db_conn->sock);
-		error_string = "socket write polling failure";
 	}
 	}
 	else {
 	else {
-		error_string = "could not allocate H2O socket";
+		errno = ENOMEM;
+		STANDARD_ERROR("h2o_evloop_socket_create");
 		close(sd);
 		close(sd);
 	}
 	}
 
 
@@ -420,7 +443,7 @@ error_dup:
 error_connect:
 error_connect:
 	free(db_conn);
 	free(db_conn);
 error:
 error:
-	error_notification(ctx, false, error_string);
+	error_notification(ctx, false, DB_ERROR);
 }
 }
 
 
 static int start_database_write_polling(db_conn_t *db_conn)
 static int start_database_write_polling(db_conn_t *db_conn)
@@ -446,24 +469,6 @@ void connect_to_database(thread_context_t *ctx)
 		start_database_connect(ctx, NULL);
 		start_database_connect(ctx, NULL);
 }
 }
 
 
-static int do_database_write(db_conn_t *db_conn)
-{
-	assert(db_conn->param);
-
-	int ret = db_conn->param->on_write_ready(db_conn->param, db_conn->conn);
-
-	if (!ret)
-		db_conn->flags &= ~IS_WRITING;
-	else if (ret < 0)
-		on_database_error(db_conn, PQerrorMessage(db_conn->conn));
-	else if (start_database_write_polling(db_conn))
-		on_database_error(db_conn, EPOLL_ERR_MSG);
-	else
-		ret = 0;
-
-	return ret;
-}
-
 int execute_query(thread_context_t *ctx, db_query_param_t *param)
 int execute_query(thread_context_t *ctx, db_query_param_t *param)
 {
 {
 	int ret = EXIT_SUCCESS;
 	int ret = EXIT_SUCCESS;

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

@@ -29,6 +29,7 @@
 #include "list.h"
 #include "list.h"
 #include "utility.h"
 #include "utility.h"
 
 
+#define DB_ERROR "database error\n"
 #define DB_REQ_ERROR "too many concurrent database requests\n"
 #define DB_REQ_ERROR "too many concurrent database requests\n"
 #define DB_TIMEOUT_ERROR "database timeout\n"
 #define DB_TIMEOUT_ERROR "database timeout\n"
 #define FORTUNE_TABLE_NAME "Fortune"
 #define FORTUNE_TABLE_NAME "Fortune"

+ 2 - 1
frameworks/C/h2o/src/error.c

@@ -30,7 +30,8 @@
 void print_error(const char *file,
 void print_error(const char *file,
                  unsigned line,
                  unsigned line,
                  const char *function,
                  const char *function,
-                 const char *error_string, ...)
+                 const char *error_string,
+                 ...)
 {
 {
 	char * const file_name = strdup(file);
 	char * const file_name = strdup(file);
 
 

+ 4 - 5
frameworks/C/h2o/src/error.h

@@ -25,9 +25,6 @@
 #include <stdarg.h>
 #include <stdarg.h>
 #include <yajl/yajl_gen.h>
 #include <yajl/yajl_gen.h>
 
 
-#define EPOLL_ERR_MSG "epoll_ctl() failure\n"
-#define MEM_ALLOC_ERR_MSG "memory allocation failure\n"
-
 #define CHECK_ERRNO(function, ...) \
 #define CHECK_ERRNO(function, ...) \
 	do { \
 	do { \
 		const int error_code = (function)(__VA_ARGS__); \
 		const int error_code = (function)(__VA_ARGS__); \
@@ -71,12 +68,14 @@
 	} while(0)
 	} while(0)
 
 
 #define ERROR(...) print_error(__FILE__, __LINE__, __func__, __VA_ARGS__)
 #define ERROR(...) print_error(__FILE__, __LINE__, __func__, __VA_ARGS__)
-#define LIBRARY_ERROR(function) print_library_error(__FILE__, __LINE__, (function), errno)
+#define LIBRARY_ERROR(function, ...) print_error(__FILE__, __LINE__, (function), __VA_ARGS__)
+#define STANDARD_ERROR(function) print_library_error(__FILE__, __LINE__, (function), errno)
 
 
 void print_error(const char *file,
 void print_error(const char *file,
                  unsigned line,
                  unsigned line,
                  const char *function,
                  const char *function,
-                 const char *error_string, ...);
+                 const char *error_string,
+                 ...);
 void print_library_error(const char *file,
 void print_library_error(const char *file,
                          unsigned line,
                          unsigned line,
                          const char *function,
                          const char *function,

+ 82 - 22
frameworks/C/h2o/src/event_loop.c

@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <h2o.h>
 #include <h2o.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -32,14 +33,21 @@
 #include "utility.h"
 #include "utility.h"
 
 
 static void accept_connection(h2o_socket_t *listener, const char *err);
 static void accept_connection(h2o_socket_t *listener, const char *err);
+static void accept_http_connection(h2o_socket_t *listener, const char *err);
 static void do_epoll_wait(h2o_socket_t *epoll_sock, const char *err);
 static void do_epoll_wait(h2o_socket_t *epoll_sock, const char *err);
 static void on_close_connection(void *data);
 static void on_close_connection(void *data);
 static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages);
 static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages);
 static void shutdown_server(h2o_socket_t *listener, const char *err);
 static void shutdown_server(h2o_socket_t *listener, const char *err);
+static void start_accept_polling(bool is_main_thread,
+                                 bool is_https,
+                                 global_data_t *global_data,
+                                 event_loop_t *loop);
 
 
 static void accept_connection(h2o_socket_t *listener, const char *err)
 static void accept_connection(h2o_socket_t *listener, const char *err)
 {
 {
-	if (!err) {
+	if (err)
+		ERROR(err);
+	else {
 		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,
 		                                                      event_loop,
 		                                                      listener->data);
 		                                                      listener->data);
@@ -62,9 +70,24 @@ static void accept_connection(h2o_socket_t *listener, const char *err)
 	}
 	}
 }
 }
 
 
+static void accept_http_connection(h2o_socket_t *listener, const char *err)
+{
+	// Assume that err is most often NULL.
+	thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
+	                                                      event_loop,
+	                                                      listener->data);
+	SSL_CTX * const ssl_ctx = ctx->event_loop.h2o_accept_ctx.ssl_ctx;
+
+	ctx->event_loop.h2o_accept_ctx.ssl_ctx = NULL;
+	accept_connection(listener, err);
+	ctx->event_loop.h2o_accept_ctx.ssl_ctx = ssl_ctx;
+}
+
 static void do_epoll_wait(h2o_socket_t *epoll_sock, const char *err)
 static void do_epoll_wait(h2o_socket_t *epoll_sock, const char *err)
 {
 {
-	if (!err) {
+	if (err)
+		ERROR(err);
+	else {
 		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,
 		                                                      event_loop,
 		                                                      epoll_sock->data);
 		                                                      epoll_sock->data);
@@ -105,7 +128,9 @@ static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_
 
 
 static void shutdown_server(h2o_socket_t *listener, const char *err)
 static void shutdown_server(h2o_socket_t *listener, const char *err)
 {
 {
-	if (!err) {
+	if (err)
+		ERROR(err);
+	else {
 		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,
 		                                                      event_loop,
 		                                                      listener->data);
 		                                                      listener->data);
@@ -118,6 +143,43 @@ static void shutdown_server(h2o_socket_t *listener, const char *err)
 	}
 	}
 }
 }
 
 
+static void start_accept_polling(bool is_main_thread,
+                                 bool is_https,
+                                 global_data_t *global_data,
+                                 event_loop_t *loop)
+{
+	int listener_sd = is_https ? global_data->https_listener_sd : global_data->listener_sd;
+
+	if (!is_main_thread) {
+		int flags;
+
+		CHECK_ERRNO_RETURN(listener_sd, dup, listener_sd);
+		CHECK_ERRNO_RETURN(flags, fcntl, listener_sd, F_GETFD);
+		CHECK_ERRNO(fcntl, listener_sd, F_SETFD, flags | FD_CLOEXEC);
+	}
+
+	// Let all the threads race to call accept() on the socket; since the latter is
+	// non-blocking, that will effectively act as load balancing.
+	h2o_socket_t * const h2o_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop,
+	                                                           listener_sd,
+	                                                           H2O_SOCKET_FLAG_DONT_READ);
+
+	if (is_https)
+		loop->h2o_https_socket = h2o_socket;
+	else
+		loop->h2o_socket = h2o_socket;
+
+	h2o_socket->data = loop;
+
+	// Assume that the majority of the connections use HTTPS, so HTTP can take a few
+	// extra operations.
+	const h2o_socket_cb accept_cb = !global_data->ssl_ctx || is_https ?
+	                                accept_connection :
+	                                accept_http_connection;
+
+	h2o_socket_read_start(h2o_socket, accept_cb);
+}
+
 void event_loop(thread_context_t *ctx)
 void event_loop(thread_context_t *ctx)
 {
 {
 	while (!ctx->global_data->shutdown || ctx->event_loop.conn_num)
 	while (!ctx->global_data->shutdown || ctx->event_loop.conn_num)
@@ -126,6 +188,9 @@ void event_loop(thread_context_t *ctx)
 
 
 void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver)
 void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver)
 {
 {
+	if (event_loop->h2o_https_socket)
+		h2o_socket_close(event_loop->h2o_https_socket);
+
 	h2o_multithread_unregister_receiver(event_loop->h2o_ctx.queue, h2o_receiver);
 	h2o_multithread_unregister_receiver(event_loop->h2o_ctx.queue, h2o_receiver);
 	h2o_socket_close(event_loop->h2o_socket);
 	h2o_socket_close(event_loop->h2o_socket);
 	h2o_socket_close(event_loop->epoll_socket);
 	h2o_socket_close(event_loop->epoll_socket);
@@ -141,27 +206,13 @@ void initialize_event_loop(bool is_main_thread,
 	h2o_context_init(&loop->h2o_ctx, h2o_evloop_create(), &global_data->h2o_config);
 	h2o_context_init(&loop->h2o_ctx, h2o_evloop_create(), &global_data->h2o_config);
 	loop->h2o_accept_ctx.ctx = &loop->h2o_ctx;
 	loop->h2o_accept_ctx.ctx = &loop->h2o_ctx;
 	loop->h2o_accept_ctx.hosts = global_data->h2o_config.hosts;
 	loop->h2o_accept_ctx.hosts = global_data->h2o_config.hosts;
-	loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx;
-
-	int listener_sd;
 
 
-	if (is_main_thread)
-		listener_sd = global_data->listener_sd;
-	else {
-		int flags;
-
-		CHECK_ERRNO_RETURN(listener_sd, dup, global_data->listener_sd);
-		CHECK_ERRNO_RETURN(flags, fcntl, listener_sd, F_GETFD);
-		CHECK_ERRNO(fcntl, listener_sd, F_SETFD, flags | FD_CLOEXEC);
+	if (global_data->ssl_ctx) {
+		loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx;
+		start_accept_polling(is_main_thread, true, global_data, loop);
 	}
 	}
 
 
-	// Let all the threads race to call accept() on the socket; since the latter is
-	// non-blocking, that will effectively act as load balancing.
-	loop->h2o_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop,
-	                                            listener_sd,
-	                                            H2O_SOCKET_FLAG_DONT_READ);
-	loop->h2o_socket->data = loop;
-	h2o_socket_read_start(loop->h2o_socket, accept_connection);
+	start_accept_polling(is_main_thread, false, global_data, loop);
 	h2o_multithread_register_receiver(loop->h2o_ctx.queue,
 	h2o_multithread_register_receiver(loop->h2o_ctx.queue,
 	                                  h2o_receiver,
 	                                  h2o_receiver,
 	                                  process_messages);
 	                                  process_messages);
@@ -194,7 +245,16 @@ int start_write_polling(int fd,
 	memset(&event, 0, sizeof(event));
 	memset(&event, 0, sizeof(event));
 	event.data.ptr = on_write_ready;
 	event.data.ptr = on_write_ready;
 	event.events = EPOLLET | EPOLLONESHOT | EPOLLOUT | EPOLLRDHUP;
 	event.events = EPOLLET | EPOLLONESHOT | EPOLLOUT | EPOLLRDHUP;
-	return epoll_ctl(event_loop->epoll_fd, rearm ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &event);
+
+	const int ret = epoll_ctl(event_loop->epoll_fd,
+	                          rearm ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
+	                          fd,
+	                          &event);
+
+	if (ret)
+		STANDARD_ERROR("epoll_ctl");
+
+	return ret;
 }
 }
 
 
 void stop_write_polling(int fd, event_loop_t *event_loop)
 void stop_write_polling(int fd, event_loop_t *event_loop)

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

@@ -30,6 +30,7 @@ typedef struct thread_context_t thread_context_t;
 
 
 typedef struct {
 typedef struct {
 	h2o_socket_t *epoll_socket;
 	h2o_socket_t *epoll_socket;
+	h2o_socket_t *h2o_https_socket;
 	h2o_socket_t *h2o_socket;
 	h2o_socket_t *h2o_socket;
 	size_t conn_num;
 	size_t conn_num;
 	int epoll_fd;
 	int epoll_fd;

+ 10 - 17
frameworks/C/h2o/src/fortune.c

@@ -142,9 +142,7 @@ 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 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);
+	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,
 	iovec_list_t * const iovec_list = H2O_STRUCT_FROM_MEMBER(iovec_list_t,
 	                                                         l,
 	                                                         l,
 	                                                         fortune_ctx->iovec_list);
 	                                                         fortune_ctx->iovec_list);
@@ -201,18 +199,14 @@ static list_t *merge_lists(list_t *head1, list_t *head2)
 
 
 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)
 {
 {
-	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t,
-	                                                           param,
-	                                                           param);
+	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, param, param);
 
 
 	send_error(BAD_GATEWAY, error_string, fortune_ctx->req);
 	send_error(BAD_GATEWAY, error_string, fortune_ctx->req);
 }
 }
 
 
 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)
 {
 {
-	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t,
-	                                                           param,
-	                                                           param);
+	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, param, param);
 	int ret = DONE;
 	int ret = DONE;
 	const ExecStatusType status = PQresultStatus(result);
 	const ExecStatusType status = PQresultStatus(result);
 
 
@@ -240,7 +234,7 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 					fortune->data = result;
 					fortune->data = result;
 			}
 			}
 			else {
 			else {
-				send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, fortune_ctx->req);
+				send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, fortune_ctx->req);
 				ret = DONE;
 				ret = DONE;
 
 
 				if (!i)
 				if (!i)
@@ -251,8 +245,9 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 		}
 		}
 	}
 	}
 	else if (result) {
 	else if (result) {
+		LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
+		send_error(BAD_GATEWAY, DB_ERROR, fortune_ctx->req);
 		PQclear(result);
 		PQclear(result);
-		send_error(BAD_GATEWAY, PQresultErrorMessage(result), fortune_ctx->req);
 	}
 	}
 	else {
 	else {
 		mustache_api_t api = {.sectget = on_fortune_section,
 		mustache_api_t api = {.sectget = on_fortune_section,
@@ -281,7 +276,7 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 			         !fortune_ctx->iovec_list);
 			         !fortune_ctx->iovec_list);
 		}
 		}
 		else
 		else
-			send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, fortune_ctx->req);
+			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, fortune_ctx->req);
 	}
 	}
 
 
 	return ret;
 	return ret;
@@ -315,9 +310,7 @@ static uintmax_t on_fortune_section(mustache_api_t *api,
 
 
 static void on_fortune_timeout(db_query_param_t *param)
 static void on_fortune_timeout(db_query_param_t *param)
 {
 {
-	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t,
-	                                                           param,
-	                                                           param);
+	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, param, param);
 
 
 	send_error(GATEWAY_TIMEOUT, DB_TIMEOUT_ERROR, fortune_ctx->req);
 	send_error(GATEWAY_TIMEOUT, DB_TIMEOUT_ERROR, fortune_ctx->req);
 }
 }
@@ -399,10 +392,10 @@ int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
 				send_service_unavailable_error(DB_REQ_ERROR, req);
 				send_service_unavailable_error(DB_REQ_ERROR, req);
 		}
 		}
 		else
 		else
-			send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	}
 	}
 	else
 	else
-		send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 
 
 	return 0;
 	return 0;
 }
 }

+ 27 - 13
frameworks/C/h2o/src/main.c

@@ -25,6 +25,7 @@
 #include <signal.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -53,10 +54,10 @@
 	"[-k <private key file>] [-l <log path>] " \
 	"[-k <private key file>] [-l <log path>] " \
 	"[-m <max database connections per thread>] [-p <port>] " \
 	"[-m <max database connections per thread>] [-p <port>] " \
 	"[-q <max enqueued database queries per thread>] [-r <root directory>] " \
 	"[-q <max enqueued database queries per thread>] [-r <root directory>] " \
-	"[-t <thread number>]\n"
+	"[-s <HTTPS port>] [-t <thread number>]\n"
 
 
 static void free_global_data(global_data_t *global_data);
 static void free_global_data(global_data_t *global_data);
-static int get_listener_socket(const config_t *config);
+static int get_listener_socket(const char *bind_address, uint16_t port);
 static size_t get_maximum_cache_line_size(void);
 static size_t get_maximum_cache_line_size(void);
 static int initialize_global_data(const config_t *config, global_data_t *global_data);
 static int initialize_global_data(const config_t *config, global_data_t *global_data);
 static int parse_options(int argc, char *argv[], config_t *config);
 static int parse_options(int argc, char *argv[], config_t *config);
@@ -87,22 +88,22 @@ static void free_global_data(global_data_t *global_data)
 		cleanup_openssl(global_data);
 		cleanup_openssl(global_data);
 }
 }
 
 
-static int get_listener_socket(const config_t *config)
+static int get_listener_socket(const char *bind_address, uint16_t port)
 {
 {
 	int ret = -1;
 	int ret = -1;
-	char port[16];
+	char buf[16];
 
 
-	if ((size_t) snprintf(port, sizeof(port), "%u", (unsigned) config->port) >= sizeof(port)) {
-		print_error(__FILE__, __LINE__, "snprintf", "Truncated output.");
+	if ((size_t) snprintf(buf, sizeof(buf), "%" PRIu16, port) >= sizeof(buf)) {
+		LIBRARY_ERROR("snprintf", "Truncated output.");
 		return ret;
 		return ret;
 	}
 	}
 
 
 	struct addrinfo *res = NULL;
 	struct addrinfo *res = NULL;
 	struct addrinfo hints = {.ai_socktype = SOCK_STREAM, .ai_flags = AI_PASSIVE};
 	struct addrinfo hints = {.ai_socktype = SOCK_STREAM, .ai_flags = AI_PASSIVE};
-	const int error_code = getaddrinfo(config->bind_address, port, &hints, &res);
+	const int error_code = getaddrinfo(bind_address, buf, &hints, &res);
 
 
 	if (error_code) {
 	if (error_code) {
-		print_error(__FILE__, __LINE__, "getaddrinfo", gai_strerror(error_code));
+		LIBRARY_ERROR("getaddrinfo", gai_strerror(error_code));
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -114,7 +115,7 @@ static int get_listener_socket(const config_t *config)
 		                     iter->ai_protocol);
 		                     iter->ai_protocol);
 
 
 		if (s == -1) {
 		if (s == -1) {
-			LIBRARY_ERROR("socket");
+			STANDARD_ERROR("socket");
 			continue;
 			continue;
 		}
 		}
 
 
@@ -166,7 +167,7 @@ static size_t get_maximum_cache_line_size(void)
 
 
 		if (rc < 0) {
 		if (rc < 0) {
 			if (errno)
 			if (errno)
-				LIBRARY_ERROR("sysconf");
+				STANDARD_ERROR("sysconf");
 		}
 		}
 		else if ((size_t) rc > ret)
 		else if ((size_t) rc > ret)
 			ret = rc;
 			ret = rc;
@@ -192,13 +193,20 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
 	CHECK_ERRNO_RETURN(global_data->signal_fd, signalfd, -1, &signals, SFD_NONBLOCK | SFD_CLOEXEC);
 	CHECK_ERRNO_RETURN(global_data->signal_fd, signalfd, -1, &signals, SFD_NONBLOCK | SFD_CLOEXEC);
 	global_data->fortunes_template = get_fortunes_template(config->template_path);
 	global_data->fortunes_template = get_fortunes_template(config->template_path);
 	h2o_config_init(&global_data->h2o_config);
 	h2o_config_init(&global_data->h2o_config);
-	global_data->listener_sd = get_listener_socket(config);
+	global_data->listener_sd = get_listener_socket(config->bind_address, config->port);
 
 
 	if (global_data->listener_sd == -1)
 	if (global_data->listener_sd == -1)
 		goto error;
 		goto error;
 
 
-	if (config->cert && config->key)
+	if (config->cert && config->key) {
+		global_data->https_listener_sd = get_listener_socket(config->bind_address,
+		                                                     config->https_port);
+
+		if (global_data->https_listener_sd == -1)
+			goto error;
+
 		initialize_openssl(config, global_data);
 		initialize_openssl(config, global_data);
+	}
 
 
 	const h2o_iovec_t host = h2o_iovec_init(H2O_STRLIT("default"));
 	const h2o_iovec_t host = h2o_iovec_init(H2O_STRLIT("default"));
 	h2o_hostconf_t * const hostconf = h2o_config_register_host(&global_data->h2o_config,
 	h2o_hostconf_t * const hostconf = h2o_config_register_host(&global_data->h2o_config,
@@ -244,7 +252,7 @@ static int parse_options(int argc, char *argv[], config_t *config)
 	opterr = 0;
 	opterr = 0;
 
 
 	while (1) {
 	while (1) {
-		const int opt = getopt(argc, argv, "?a:b:c:d:f:k:l:m:p:q:r:t:");
+		const int opt = getopt(argc, argv, "?a:b:c:d:f:k:l:m:p:q:r:s:t:");
 
 
 		if (opt == -1)
 		if (opt == -1)
 			break;
 			break;
@@ -298,6 +306,9 @@ static int parse_options(int argc, char *argv[], config_t *config)
 			case 'r':
 			case 'r':
 				config->root = optarg;
 				config->root = optarg;
 				break;
 				break;
+			case 's':
+				PARSE_NUMBER(config->https_port);
+				break;
 			case 't':
 			case 't':
 				PARSE_NUMBER(config->thread_num);
 				PARSE_NUMBER(config->thread_num);
 				break;
 				break;
@@ -329,6 +340,9 @@ static void set_default_options(config_t *config)
 
 
 	if (!config->thread_num)
 	if (!config->thread_num)
 		config->thread_num = h2o_numproc();
 		config->thread_num = h2o_numproc();
+
+	if (!config->https_port)
+		config->https_port = 4443;
 }
 }
 
 
 static void setup_process(void)
 static void setup_process(void)

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

@@ -58,7 +58,7 @@ error_yajl:
 		yajl_gen_free(gen);
 		yajl_gen_free(gen);
 	}
 	}
 
 
-	send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+	send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 0
frameworks/C/h2o/src/request_handler.h

@@ -25,6 +25,8 @@
 #include <stdbool.h>
 #include <stdbool.h>
 #include <yajl/yajl_gen.h>
 #include <yajl/yajl_gen.h>
 
 
+#define REQ_ERROR "request error\n"
+
 typedef enum {
 typedef enum {
 	HTML,
 	HTML,
 	JSON,
 	JSON,

+ 1 - 1
frameworks/C/h2o/src/template.c

@@ -138,7 +138,7 @@ mustache_template_t *get_fortunes_template(const char *path)
 		fclose(template_input.input);
 		fclose(template_input.input);
 	}
 	}
 	else
 	else
-		LIBRARY_ERROR("fopen");
+		STANDARD_ERROR("fopen");
 
 
 	return ret;
 	return ret;
 }
 }

+ 11 - 1
frameworks/C/h2o/src/tls.c

@@ -18,12 +18,14 @@
 */
 */
 
 
 #include <assert.h>
 #include <assert.h>
+#include <h2o.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <stddef.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <openssl/conf.h>
 #include <openssl/conf.h>
 #include <openssl/crypto.h>
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/err.h>
+#include <openssl/opensslv.h>
 #include <openssl/ssl.h>
 #include <openssl/ssl.h>
 
 
 #include "error.h"
 #include "error.h"
@@ -112,7 +114,10 @@ static void locking_function(int mode, int n, const char *file, int line)
 	static_assert(!offsetof(struct CRYPTO_dynlock_value, mutex),
 	static_assert(!offsetof(struct CRYPTO_dynlock_value, mutex),
 	              "The mutex must be the first field in struct CRYPTO_dynlock_value.");
 	              "The mutex must be the first field in struct CRYPTO_dynlock_value.");
 
 
-	dyn_lock_function(mode, (struct CRYPTO_dynlock_value *) (openssl_global_data.lock + n), file, line);
+	dyn_lock_function(mode,
+	                  (struct CRYPTO_dynlock_value *) (openssl_global_data.lock + n),
+	                  file,
+	                  line);
 }
 }
 
 
 void cleanup_openssl(global_data_t *global_data)
 void cleanup_openssl(global_data_t *global_data)
@@ -158,6 +163,11 @@ void initialize_openssl(const config_t *config, global_data_t *global_data)
 	CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
 	CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
 	CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
 	CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
 	global_data->ssl_ctx = SSL_CTX_new(TLSv1_2_server_method());
 	global_data->ssl_ctx = SSL_CTX_new(TLSv1_2_server_method());
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+	SSL_CTX_set_ecdh_auto(global_data->ssl_ctx, 1);
+	h2o_ssl_register_alpn_protocols(global_data->ssl_ctx, h2o_http2_alpn_protocols);
+#endif
+	SSL_CTX_set_cipher_list(global_data->ssl_ctx, "DEFAULT:!3DES:!RC4");
 	CHECK_OPENSSL_ERROR(SSL_CTX_use_certificate_file,
 	CHECK_OPENSSL_ERROR(SSL_CTX_use_certificate_file,
 	                    global_data->ssl_ctx,
 	                    global_data->ssl_ctx,
 	                    config->cert,
 	                    config->cert,

+ 2 - 0
frameworks/C/h2o/src/utility.h

@@ -50,6 +50,7 @@ typedef struct {
 	size_t max_db_conn_num;
 	size_t max_db_conn_num;
 	size_t max_query_num;
 	size_t max_query_num;
 	size_t thread_num;
 	size_t thread_num;
+	uint16_t https_port;
 	uint16_t port;
 	uint16_t port;
 } config_t;
 } config_t;
 
 
@@ -60,6 +61,7 @@ typedef struct {
 	SSL_CTX *ssl_ctx;
 	SSL_CTX *ssl_ctx;
 	global_thread_data_t *global_thread_data;
 	global_thread_data_t *global_thread_data;
 	size_t memory_alignment;
 	size_t memory_alignment;
+	int https_listener_sd;
 	int listener_sd;
 	int listener_sd;
 	int signal_fd;
 	int signal_fd;
 	bool shutdown;
 	bool shutdown;

+ 43 - 65
frameworks/C/h2o/src/world.c

@@ -172,9 +172,7 @@ static void initialize_ids(size_t num_query, query_result_t *res, unsigned int *
 
 
 static void on_multiple_query_error(db_query_param_t *param, const char *error_string)
 static void on_multiple_query_error(db_query_param_t *param, const char *error_string)
 {
 {
-	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t,
-	                                                                 param,
-	                                                                 param);
+	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
 
 	if (query_ctx->gen) {
 	if (query_ctx->gen) {
@@ -189,9 +187,7 @@ static void on_multiple_query_error(db_query_param_t *param, const char *error_s
 
 
 static result_return_t on_multiple_query_result(db_query_param_t *param, PGresult *result)
 static result_return_t on_multiple_query_result(db_query_param_t *param, PGresult *result)
 {
 {
-	query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t,
-	                                                           param,
-	                                                           param);
+	query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
 
 	if (query_ctx->gen && PQresultStatus(result) == PGRES_TUPLES_OK) {
 	if (query_ctx->gen && PQresultStatus(result) == PGRES_TUPLES_OK) {
@@ -221,15 +217,16 @@ static result_return_t on_multiple_query_result(db_query_param_t *param, PGresul
 			send_service_unavailable_error(DB_REQ_ERROR, query_ctx->req);
 			send_service_unavailable_error(DB_REQ_ERROR, query_ctx->req);
 		}
 		}
 		else if (query_ctx->num_result == query_ctx->num_query)
 		else if (query_ctx->num_result == query_ctx->num_query)
-			serialize_items(query_ctx->res,
-			                query_ctx->num_result,
-			                query_ctx->gen,
-			                query_ctx->req);
+			serialize_items(query_ctx->res, query_ctx->num_result, query_ctx->gen, query_ctx->req);
 
 
 		h2o_mem_release_shared(query_ctx);
 		h2o_mem_release_shared(query_ctx);
 	}
 	}
-	else
-		on_multiple_query_error(param, PQresultErrorMessage(result));
+	else {
+		if (query_ctx->gen)
+			LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
+
+		on_multiple_query_error(param, DB_ERROR);
+	}
 
 
 	PQclear(result);
 	PQclear(result);
 	return DONE;
 	return DONE;
@@ -237,9 +234,7 @@ static result_return_t on_multiple_query_result(db_query_param_t *param, PGresul
 
 
 static void on_multiple_query_timeout(db_query_param_t *param)
 static void on_multiple_query_timeout(db_query_param_t *param)
 {
 {
-	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t,
-	                                                                 param,
-	                                                                 param);
+	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
 
 	if (query_ctx->gen) {
 	if (query_ctx->gen) {
@@ -254,18 +249,14 @@ static void on_multiple_query_timeout(db_query_param_t *param)
 
 
 static void on_single_query_error(db_query_param_t *param, const char *error_string)
 static void on_single_query_error(db_query_param_t *param, const char *error_string)
 {
 {
-	single_query_ctx_t * const query_ctx = H2O_STRUCT_FROM_MEMBER(single_query_ctx_t,
-	                                                              param,
-	                                                              param);
+	single_query_ctx_t * const query_ctx = H2O_STRUCT_FROM_MEMBER(single_query_ctx_t, param, param);
 
 
 	send_error(BAD_GATEWAY, error_string, query_ctx->req);
 	send_error(BAD_GATEWAY, error_string, query_ctx->req);
 }
 }
 
 
 static result_return_t on_single_query_result(db_query_param_t *param, PGresult *result)
 static result_return_t on_single_query_result(db_query_param_t *param, PGresult *result)
 {
 {
-	single_query_ctx_t * const query_ctx = H2O_STRUCT_FROM_MEMBER(single_query_ctx_t,
-	                                                              param,
-	                                                              param);
+	single_query_ctx_t * const query_ctx = H2O_STRUCT_FROM_MEMBER(single_query_ctx_t, param, param);
 
 
 	if (PQresultStatus(result) == PGRES_TUPLES_OK) {
 	if (PQresultStatus(result) == PGRES_TUPLES_OK) {
 		uint32_t random_number;
 		uint32_t random_number;
@@ -291,10 +282,11 @@ static result_return_t on_single_query_result(db_query_param_t *param, PGresult
 			yajl_gen_free(gen);
 			yajl_gen_free(gen);
 		}
 		}
 
 
-		send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, query_ctx->req);
+		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req);
 	}
 	}
 	else {
 	else {
-		send_error(BAD_GATEWAY, PQresultErrorMessage(result), query_ctx->req);
+		LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
+		send_error(BAD_GATEWAY, DB_ERROR, query_ctx->req);
 		PQclear(result);
 		PQclear(result);
 	}
 	}
 
 
@@ -303,18 +295,14 @@ static result_return_t on_single_query_result(db_query_param_t *param, PGresult
 
 
 static void on_single_query_timeout(db_query_param_t *param)
 static void on_single_query_timeout(db_query_param_t *param)
 {
 {
-	single_query_ctx_t * const query_ctx = H2O_STRUCT_FROM_MEMBER(single_query_ctx_t,
-	                                                              param,
-	                                                              param);
+	single_query_ctx_t * const query_ctx = H2O_STRUCT_FROM_MEMBER(single_query_ctx_t, param, param);
 
 
 	send_error(GATEWAY_TIMEOUT, DB_TIMEOUT_ERROR, query_ctx->req);
 	send_error(GATEWAY_TIMEOUT, DB_TIMEOUT_ERROR, query_ctx->req);
 }
 }
 
 
 static void on_update_error(db_query_param_t *param, const char *error_string)
 static void on_update_error(db_query_param_t *param, const char *error_string)
 {
 {
-	const update_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(update_param_t,
-	                                                                  param,
-	                                                                  param);
+	const update_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(update_param_t, param, param);
 	update_ctx_t * const update_ctx = query_param->ctx;
 	update_ctx_t * const update_ctx = query_param->ctx;
 
 
 	if (update_ctx->gen) {
 	if (update_ctx->gen) {
@@ -329,9 +317,7 @@ static void on_update_error(db_query_param_t *param, const char *error_string)
 
 
 static result_return_t on_update_result(db_query_param_t *param, PGresult *result)
 static result_return_t on_update_result(db_query_param_t *param, PGresult *result)
 {
 {
-	update_param_t * const update_param = H2O_STRUCT_FROM_MEMBER(update_param_t,
-	                                                             param,
-	                                                             param);
+	update_param_t * const update_param = H2O_STRUCT_FROM_MEMBER(update_param_t, param, param);
 	update_ctx_t * const update_ctx = update_param->ctx;
 	update_ctx_t * const update_ctx = update_param->ctx;
 	result_return_t ret = DONE;
 	result_return_t ret = DONE;
 
 
@@ -342,17 +328,14 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul
 					H2O_STRUCT_FROM_MEMBER(thread_context_t,
 					H2O_STRUCT_FROM_MEMBER(thread_context_t,
 					                       event_loop.h2o_ctx,
 					                       event_loop.h2o_ctx,
 					                       update_ctx->req->conn->ctx);
 					                       update_ctx->req->conn->ctx);
-				const size_t num_query_remaining =
-					update_ctx->num_query - update_ctx->num_result;
+				const size_t num_query_remaining = update_ctx->num_query - update_ctx->num_result;
 
 
 				update_ctx->num_query_in_progress--;
 				update_ctx->num_query_in_progress--;
 
 
 				if (update_ctx->num_query_in_progress < num_query_remaining) {
 				if (update_ctx->num_query_in_progress < num_query_remaining) {
-					const size_t idx = update_ctx->num_result +
-					                   update_ctx->num_query_in_progress;
+					const size_t idx = update_ctx->num_result + update_ctx->num_query_in_progress;
 
 
-					update_param->random_number =
-						get_random_number(MAX_ID, &ctx->random_seed) + 1;
+					update_param->random_number = get_random_number(MAX_ID, &ctx->random_seed) + 1;
 					update_param->update = false;
 					update_param->update = false;
 					snprintf(update_param->command,
 					snprintf(update_param->command,
 					         MAX_UPDATE_QUERY_LEN,
 					         MAX_UPDATE_QUERY_LEN,
@@ -369,8 +352,7 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul
 
 
 					yajl_gen_free(update_ctx->gen);
 					yajl_gen_free(update_ctx->gen);
 					update_ctx->gen = NULL;
 					update_ctx->gen = NULL;
-					send_service_unavailable_error(DB_REQ_ERROR,
-					                               update_ctx->req);
+					send_service_unavailable_error(DB_REQ_ERROR, update_ctx->req);
 				}
 				}
 				else if (update_ctx->num_result == update_ctx->num_query)
 				else if (update_ctx->num_result == update_ctx->num_query)
 					serialize_items(update_ctx->res,
 					serialize_items(update_ctx->res,
@@ -380,19 +362,22 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul
 
 
 				h2o_mem_release_shared(update_ctx);
 				h2o_mem_release_shared(update_ctx);
 			}
 			}
-			else
-				on_update_error(param, PQresultErrorMessage(result));
+			else {
+				LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
+				on_update_error(param, DB_ERROR);
+			}
 		}
 		}
 		else if (PQresultStatus(result) == PGRES_TUPLES_OK) {
 		else if (PQresultStatus(result) == PGRES_TUPLES_OK) {
 			process_result(result, update_ctx->res + update_ctx->num_result);
 			process_result(result, update_ctx->res + update_ctx->num_result);
-			update_ctx->res[update_ctx->num_result].random_number =
-				update_param->random_number;
+			update_ctx->res[update_ctx->num_result].random_number = update_param->random_number;
 			update_ctx->num_result++;
 			update_ctx->num_result++;
 			update_param->update = true;
 			update_param->update = true;
 			ret = SUCCESS;
 			ret = SUCCESS;
 		}
 		}
-		else
-			on_update_error(param, PQresultErrorMessage(result));
+		else {
+			LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
+			on_update_error(param, DB_ERROR);
+		}
 	}
 	}
 	else {
 	else {
 		update_ctx->num_query_in_progress--;
 		update_ctx->num_query_in_progress--;
@@ -405,9 +390,7 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul
 
 
 static void on_update_timeout(db_query_param_t *param)
 static void on_update_timeout(db_query_param_t *param)
 {
 {
-	const update_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(update_param_t,
-	                                                                  param,
-	                                                                  param);
+	const update_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(update_param_t, param, param);
 	update_ctx_t * const update_ctx = query_param->ctx;
 	update_ctx_t * const update_ctx = query_param->ctx;
 
 
 	if (update_ctx->gen) {
 	if (update_ctx->gen) {
@@ -478,7 +461,7 @@ static void serialize_items(const query_result_t *res,
 		return;
 		return;
 
 
 error_yajl:
 error_yajl:
-	send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+	send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 }
 }
 
 
 int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
 int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
@@ -517,19 +500,15 @@ int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
 			query_ctx->query_param[i].id = htonl(query_ctx->res[i].id);
 			query_ctx->query_param[i].id = htonl(query_ctx->res[i].id);
 			query_ctx->query_param[i].id_format = 1;
 			query_ctx->query_param[i].id_format = 1;
 			query_ctx->query_param[i].id_len = sizeof(query_ctx->query_param[i].id);
 			query_ctx->query_param[i].id_len = sizeof(query_ctx->query_param[i].id);
-			query_ctx->query_param[i].id_pointer =
-				(const char *) &query_ctx->query_param[i].id;
+			query_ctx->query_param[i].id_pointer = (const char *) &query_ctx->query_param[i].id;
 			query_ctx->query_param[i].param.command = WORLD_TABLE_NAME;
 			query_ctx->query_param[i].param.command = WORLD_TABLE_NAME;
 			query_ctx->query_param[i].param.nParams = 1;
 			query_ctx->query_param[i].param.nParams = 1;
 			query_ctx->query_param[i].param.on_error = on_multiple_query_error;
 			query_ctx->query_param[i].param.on_error = on_multiple_query_error;
 			query_ctx->query_param[i].param.on_result = on_multiple_query_result;
 			query_ctx->query_param[i].param.on_result = on_multiple_query_result;
 			query_ctx->query_param[i].param.on_timeout = on_multiple_query_timeout;
 			query_ctx->query_param[i].param.on_timeout = on_multiple_query_timeout;
-			query_ctx->query_param[i].param.paramFormats =
-				&query_ctx->query_param[i].id_format;
-			query_ctx->query_param[i].param.paramLengths =
-				&query_ctx->query_param[i].id_len;
-			query_ctx->query_param[i].param.paramValues =
-				&query_ctx->query_param[i].id_pointer;
+			query_ctx->query_param[i].param.paramFormats = &query_ctx->query_param[i].id_format;
+			query_ctx->query_param[i].param.paramLengths = &query_ctx->query_param[i].id_len;
+			query_ctx->query_param[i].param.paramValues = &query_ctx->query_param[i].id_pointer;
 			query_ctx->query_param[i].param.flags = IS_PREPARED;
 			query_ctx->query_param[i].param.flags = IS_PREPARED;
 			query_ctx->query_param[i].param.resultFormat = 1;
 			query_ctx->query_param[i].param.resultFormat = 1;
 
 
@@ -546,10 +525,10 @@ int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
 		query_ctx->gen = get_json_generator(&req->pool);
 		query_ctx->gen = get_json_generator(&req->pool);
 
 
 		if (!query_ctx->gen)
 		if (!query_ctx->gen)
-			send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	}
 	}
 	else
 	else
-		send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -585,7 +564,7 @@ int single_query(struct st_h2o_handler_t *self, h2o_req_t *req)
 			send_service_unavailable_error(DB_REQ_ERROR, req);
 			send_service_unavailable_error(DB_REQ_ERROR, req);
 	}
 	}
 	else
 	else
-		send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -623,8 +602,7 @@ int updates(struct st_h2o_handler_t *self, h2o_req_t *req)
 			update_ctx->update_param[i].command = command;
 			update_ctx->update_param[i].command = command;
 			command += MAX_UPDATE_QUERY_LEN;
 			command += MAX_UPDATE_QUERY_LEN;
 			update_ctx->update_param[i].ctx = update_ctx;
 			update_ctx->update_param[i].ctx = update_ctx;
-			update_ctx->update_param[i].param.command =
-				update_ctx->update_param[i].command;
+			update_ctx->update_param[i].param.command = update_ctx->update_param[i].command;
 			update_ctx->update_param[i].param.on_error = on_update_error;
 			update_ctx->update_param[i].param.on_error = on_update_error;
 			update_ctx->update_param[i].param.on_result = on_update_result;
 			update_ctx->update_param[i].param.on_result = on_update_result;
 			update_ctx->update_param[i].param.on_timeout = on_update_timeout;
 			update_ctx->update_param[i].param.on_timeout = on_update_timeout;
@@ -651,10 +629,10 @@ int updates(struct st_h2o_handler_t *self, h2o_req_t *req)
 		update_ctx->gen = get_json_generator(&req->pool);
 		update_ctx->gen = get_json_generator(&req->pool);
 
 
 		if (!update_ctx->gen)
 		if (!update_ctx->gen)
-			send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	}
 	}
 	else
 	else
-		send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
+		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 
 
 	return 0;
 	return 0;
 }
 }