summaryrefslogtreecommitdiffstats
path: root/debian/vendor-h2o/examples/libh2o
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/vendor-h2o/examples/libh2o/http1client.c179
-rw-r--r--debian/vendor-h2o/examples/libh2o/latency-optimization.c381
-rw-r--r--debian/vendor-h2o/examples/libh2o/simple.c264
-rw-r--r--debian/vendor-h2o/examples/libh2o/socket-client.c163
-rw-r--r--debian/vendor-h2o/examples/libh2o/websocket.c143
5 files changed, 1130 insertions, 0 deletions
diff --git a/debian/vendor-h2o/examples/libh2o/http1client.c b/debian/vendor-h2o/examples/libh2o/http1client.c
new file mode 100644
index 0000000..bcf9b94
--- /dev/null
+++ b/debian/vendor-h2o/examples/libh2o/http1client.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "h2o.h"
+
+static h2o_socketpool_t *sockpool;
+static h2o_mem_pool_t pool;
+static const char *url;
+static int cnt_left = 3;
+
+static h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, size_t *reqbufcnt,
+ int *method_is_head);
+static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status,
+ h2o_iovec_t msg, h2o_header_t *headers, size_t num_headers);
+
+static void start_request(h2o_http1client_ctx_t *ctx)
+{
+ h2o_url_t url_parsed;
+ h2o_iovec_t *req;
+ int is_ssl;
+
+ /* clear memory pool */
+ h2o_mem_clear_pool(&pool);
+
+ /* parse URL */
+ if (h2o_url_parse(url, SIZE_MAX, &url_parsed) != 0) {
+ fprintf(stderr, "unrecognized type of URL: %s\n", url);
+ exit(1);
+ }
+ is_ssl = url_parsed.scheme == &H2O_URL_SCHEME_HTTPS;
+
+ /* build request */
+ req = h2o_mem_alloc_pool(&pool, sizeof(*req));
+ req->base = h2o_mem_alloc_pool(&pool, 1024);
+ req->len = snprintf(req->base, 1024, "GET %.*s HTTP/1.1\r\nhost: %.*s\r\n\r\n", (int)url_parsed.path.len, url_parsed.path.base,
+ (int)url_parsed.authority.len, url_parsed.authority.base);
+ assert(req->len < 1024);
+
+ /* initiate the request */
+ if (1) {
+ if (sockpool == NULL) {
+ sockpool = h2o_mem_alloc(sizeof(*sockpool));
+ h2o_socketpool_init_by_hostport(sockpool, url_parsed.host, h2o_url_get_port(&url_parsed), is_ssl, 10);
+ h2o_socketpool_set_timeout(sockpool, ctx->loop, 5000 /* in msec */);
+ }
+ h2o_http1client_connect_with_pool(NULL, req, ctx, sockpool, on_connect);
+ } else {
+ h2o_http1client_connect(NULL, req, ctx, url_parsed.host, h2o_url_get_port(&url_parsed), is_ssl, on_connect);
+ }
+}
+
+static int on_body(h2o_http1client_t *client, const char *errstr)
+{
+ if (errstr != NULL && errstr != h2o_http1client_error_is_eos) {
+ fprintf(stderr, "%s\n", errstr);
+ exit(1);
+ return -1;
+ }
+
+ fwrite(client->sock->input->bytes, 1, client->sock->input->size, stdout);
+ h2o_buffer_consume(&client->sock->input, client->sock->input->size);
+
+ if (errstr == h2o_http1client_error_is_eos) {
+ if (--cnt_left != 0) {
+ /* next attempt */
+ h2o_mem_clear_pool(&pool);
+ start_request(client->ctx);
+ }
+ }
+
+ return 0;
+}
+
+h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, h2o_iovec_t msg,
+ h2o_header_t *headers, size_t num_headers)
+{
+ size_t i;
+
+ if (errstr != NULL && errstr != h2o_http1client_error_is_eos) {
+ fprintf(stderr, "%s\n", errstr);
+ exit(1);
+ return NULL;
+ }
+
+ printf("HTTP/1.%d %d %.*s\n", minor_version, status, (int)msg.len, msg.base);
+ for (i = 0; i != num_headers; ++i)
+ printf("%.*s: %.*s\n", (int)headers[i].name->len, headers[i].name->base, (int)headers[i].value.len, headers[i].value.base);
+ printf("\n");
+
+ if (errstr == h2o_http1client_error_is_eos) {
+ fprintf(stderr, "no body\n");
+ exit(1);
+ return NULL;
+ }
+
+ return on_body;
+}
+
+h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, size_t *reqbufcnt,
+ int *method_is_head)
+{
+ if (errstr != NULL) {
+ fprintf(stderr, "%s\n", errstr);
+ exit(1);
+ return NULL;
+ }
+
+ *reqbufs = (h2o_iovec_t *)client->data;
+ *reqbufcnt = 1;
+ *method_is_head = 0;
+
+ return on_head;
+}
+
+int main(int argc, char **argv)
+{
+ h2o_multithread_queue_t *queue;
+ h2o_multithread_receiver_t getaddr_receiver;
+ h2o_timeout_t io_timeout;
+ h2o_http1client_ctx_t ctx = {NULL, &getaddr_receiver, &io_timeout};
+
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ ctx.ssl_ctx = SSL_CTX_new(TLSv1_client_method());
+ SSL_CTX_load_verify_locations(ctx.ssl_ctx, H2O_TO_STR(H2O_ROOT) "/share/h2o/ca-bundle.crt", NULL);
+ SSL_CTX_set_verify(ctx.ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <url>\n", argv[0]);
+ return 1;
+ }
+ url = argv[1];
+
+ h2o_mem_init_pool(&pool);
+
+/* setup context */
+#if H2O_USE_LIBUV
+ ctx.loop = uv_loop_new();
+#else
+ ctx.loop = h2o_evloop_create();
+#endif
+ queue = h2o_multithread_create_queue(ctx.loop);
+ h2o_multithread_register_receiver(queue, ctx.getaddr_receiver, h2o_hostinfo_getaddr_receiver);
+ h2o_timeout_init(ctx.loop, &io_timeout, 5000); /* 5 seconds */
+
+ /* setup the first request */
+ start_request(&ctx);
+
+ while (cnt_left != 0) {
+#if H2O_USE_LIBUV
+ uv_run(ctx.loop, UV_RUN_ONCE);
+#else
+ h2o_evloop_run(ctx.loop, INT32_MAX);
+#endif
+ }
+
+ return 0;
+}
diff --git a/debian/vendor-h2o/examples/libh2o/latency-optimization.c b/debian/vendor-h2o/examples/libh2o/latency-optimization.c
new file mode 100644
index 0000000..de34bc9
--- /dev/null
+++ b/debian/vendor-h2o/examples/libh2o/latency-optimization.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include "h2o/socket.h"
+#include "h2o/string_.h"
+
+/* configuration */
+static char *host, *port;
+static SSL_CTX *ssl_ctx;
+static int mode_server, server_flag_received;
+static h2o_socket_latency_optimization_conditions_t latopt_cond = {.min_rtt = 50, .max_additional_delay = 10, .max_cwnd = 65535};
+size_t write_block_size = 65536;
+
+/* globals */
+static h2o_loop_t *loop;
+static h2o_socket_t *sock;
+static struct {
+ uint64_t resp_start_at;
+ uint64_t sig_received_at;
+ uint64_t bytes_received;
+ uint64_t bytes_before_sig;
+} client_stats;
+
+static void server_write(h2o_socket_t *sock);
+
+static h2o_iovec_t prepare_write_buf(void)
+{
+ static h2o_iovec_t buf;
+ if (buf.base == NULL) {
+ buf.base = h2o_mem_alloc(write_block_size);
+ buf.len = write_block_size;
+ memset(buf.base, '0', buf.len);
+ }
+ return buf;
+}
+
+static void server_on_write_ready(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ fprintf(stderr, "socket unexpected closed by peer:%s\n", err);
+ exit(1);
+ return;
+ }
+ server_write(sock);
+}
+
+static void server_on_write_complete(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ fprintf(stderr, "write failed:%s\n", err);
+ exit(1);
+ return;
+ }
+ h2o_socket_notify_write(sock, server_on_write_ready);
+}
+
+void server_write(h2o_socket_t *sock)
+{
+ size_t sz = h2o_socket_prepare_for_latency_optimized_write(sock, &latopt_cond);
+ h2o_iovec_t buf = prepare_write_buf();
+
+ if (server_flag_received)
+ buf.base[0] = '1';
+ if (sz < buf.len)
+ buf.len = sz;
+
+ fprintf(stderr, "writing %zu bytes\n", buf.len);
+ h2o_socket_write(sock, &buf, 1, server_on_write_complete);
+}
+
+static void server_on_read_second(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ fprintf(stderr, "connection closed unexpectedly:%s\n", err);
+ exit(1);
+ return;
+ }
+
+ fprintf(stderr, "received the flag\n");
+ server_flag_received = 1;
+}
+
+static void server_on_read_first(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ fprintf(stderr, "connection closed unexpectedly:%s\n", err);
+ exit(1);
+ return;
+ }
+
+ server_write(sock);
+ h2o_socket_read_start(sock, server_on_read_second);
+}
+
+static void client_on_write_complete(h2o_socket_t *sock, const char *err)
+{
+ if (err == NULL)
+ return;
+ /* handle error */
+ fprintf(stderr, "write failed:%s\n", err);
+ h2o_socket_close(sock);
+ exit(1);
+}
+
+static void client_on_read_second(h2o_socket_t *sock, const char *err)
+{
+ size_t i;
+
+ if (err != NULL) {
+ fprintf(stderr, "connection closed unexpectedly:%s\n", err);
+ exit(1);
+ return;
+ }
+
+ if (client_stats.sig_received_at == 0) {
+ for (i = 0; i != sock->input->size; ++i) {
+ if (sock->input->bytes[i] != '0') {
+ client_stats.sig_received_at = h2o_now(h2o_socket_get_loop(sock));
+ break;
+ }
+ ++client_stats.bytes_before_sig;
+ }
+ }
+ client_stats.bytes_received += sock->input->size;
+ h2o_buffer_consume(&sock->input, sock->input->size);
+
+ if (client_stats.bytes_received >= 1024 * 1024) {
+ uint64_t now = h2o_now(h2o_socket_get_loop(sock));
+ printf("Delay: %" PRIu64 " octets, %" PRIu64 " ms\n", client_stats.bytes_before_sig,
+ client_stats.sig_received_at - client_stats.resp_start_at);
+ printf("Total: %" PRIu64 " octets, %" PRIu64 " ms\n", client_stats.bytes_received, now - client_stats.resp_start_at);
+ exit(0);
+ }
+}
+
+static void client_on_read_first(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ fprintf(stderr, "connection closed unexpectedly:%s\n", err);
+ exit(1);
+ return;
+ }
+
+ client_stats.resp_start_at = h2o_now(h2o_socket_get_loop(sock));
+ client_stats.bytes_before_sig = sock->input->size;
+ client_stats.bytes_received = sock->input->size;
+ h2o_buffer_consume(&sock->input, sock->input->size);
+
+ h2o_iovec_t data = {H2O_STRLIT("!")};
+ h2o_socket_write(sock, &data, 1, client_on_write_complete);
+ h2o_socket_read_start(sock, client_on_read_second);
+}
+
+static void on_handshake_complete(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL && err != h2o_socket_error_ssl_cert_name_mismatch) {
+ /* TLS handshake failed */
+ fprintf(stderr, "TLS handshake failure:%s\n", err);
+ ERR_print_errors_fp(stderr);
+ h2o_socket_close(sock);
+ exit(1);
+ return;
+ }
+
+ if (mode_server) {
+ h2o_socket_read_start(sock, server_on_read_first);
+ } else {
+ h2o_iovec_t buf = {H2O_STRLIT("0")};
+ h2o_socket_write(sock, &buf, 1, client_on_write_complete);
+ h2o_socket_read_start(sock, client_on_read_first);
+ }
+}
+
+static void on_connect(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ /* connection failed */
+ fprintf(stderr, "failed to connect to host:%s\n", err);
+ h2o_socket_close(sock);
+ exit(1);
+ return;
+ }
+
+ if (ssl_ctx != NULL) {
+ h2o_socket_ssl_handshake(sock, ssl_ctx, mode_server ? NULL : "blahblah", on_handshake_complete);
+ } else {
+ on_handshake_complete(sock, NULL);
+ }
+}
+
+static void on_accept(h2o_socket_t *listener, const char *err)
+{
+ if (err != NULL)
+ return;
+
+ if ((sock = h2o_evloop_socket_accept(listener)) != NULL) {
+ h2o_socket_close(listener);
+ if (ssl_ctx != NULL) {
+ h2o_socket_ssl_handshake(sock, ssl_ctx, mode_server ? NULL : "blahblah", on_handshake_complete);
+ } else {
+ on_handshake_complete(sock, NULL);
+ }
+ }
+}
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr, "Usage: %s [opts] [<host>:]<port>\n"
+ "Options: --listen if set, waits for incoming connection. Otherwise,\n"
+ " connects to the server running at given address\n"
+ " --reverse-role if set, reverses the role bet. server and the\n"
+ " client once the connection is established\n"
+ " --tls use TLS\n"
+ " --block-size=octets default write block size\n"
+ " --min-rtt=ms minimum RTT to enable latency optimization\n"
+ " --max-cwnd=octets maximum size of CWND to enable latency\n"
+ " optimization\n",
+ cmd);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ static const struct option longopts[] = {{"listen", no_argument, NULL, 'l'},
+ {"reverse-role", no_argument, NULL, 'r'},
+ {"tls", no_argument, NULL, 't'},
+ {"block-size", no_argument, NULL, 'b'},
+ {"min-rtt", required_argument, NULL, 'R'},
+ {"max-cwnd", required_argument, NULL, 'c'},
+ {}};
+ int opt_ch, mode_listen = 0, mode_reverse_role = 0, mode_tls = 0;
+ struct addrinfo hints, *res = NULL;
+ int err;
+
+ while ((opt_ch = getopt_long(argc, argv, "lrtb:R:c:", longopts, NULL)) != -1) {
+ switch (opt_ch) {
+ case 'l':
+ mode_listen = 1;
+ break;
+ case 'r':
+ mode_reverse_role = 1;
+ break;
+ case 't':
+ mode_tls = 1;
+ break;
+ case 'b':
+ if (sscanf(optarg, "%zu", &write_block_size) != 1) {
+ fprintf(stderr, "write block size (-b) must be a non-negative number of octets\n");
+ exit(1);
+ }
+ break;
+ case 'R':
+ if (sscanf(optarg, "%u", &latopt_cond.min_rtt) != 1) {
+ fprintf(stderr, "min RTT (-m) must be a non-negative number in milliseconds\n");
+ exit(1);
+ }
+ break;
+ case 'c':
+ if (sscanf(optarg, "%u", &latopt_cond.max_cwnd) != 1) {
+ fprintf(stderr, "max CWND size must be a non-negative number of octets\n");
+ exit(1);
+ }
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ mode_server = mode_listen;
+ if (mode_reverse_role)
+ mode_server = !mode_server;
+
+ if (argc == optind) {
+ usage(argv[0]);
+ } else {
+ char *hostport = argv[optind], *colon;
+ if ((colon = strchr(hostport, ':')) != NULL) {
+ hostport = argv[optind];
+ host = strdup(hostport);
+ host[colon - hostport] = '\0';
+ port = colon + 1;
+ } else {
+ host = "0.0.0.0";
+ port = argv[optind];
+ }
+ }
+
+ if (mode_tls) {
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ if (mode_server) {
+ ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ SSL_CTX_use_certificate_file(ssl_ctx, "examples/h2o/server.crt", SSL_FILETYPE_PEM);
+ SSL_CTX_use_PrivateKey_file(ssl_ctx, "examples/h2o/server.key", SSL_FILETYPE_PEM);
+ } else {
+ ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+ }
+ int nid = NID_X9_62_prime256v1;
+ EC_KEY *key = EC_KEY_new_by_curve_name(nid);
+ if (key == NULL) {
+ fprintf(stderr, "Failed to create curve \"%s\"\n", OBJ_nid2sn(nid));
+ exit(1);
+ }
+ SSL_CTX_set_tmp_ecdh(ssl_ctx, key);
+ EC_KEY_free(key);
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+ SSL_CTX_set_cipher_list(ssl_ctx, "ECDHE-RSA-AES128-GCM-SHA256");
+ }
+
+#if H2O_USE_LIBUV
+ loop = uv_loop_new();
+#else
+ loop = h2o_evloop_create();
+#endif
+
+ /* resolve host:port (FIXME use the function supplied by the loop) */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = AI_ADDRCONFIG;
+ if ((err = getaddrinfo(host, port, &hints, &res)) != 0) {
+ fprintf(stderr, "failed to resolve %s:%s:%s\n", host, port, gai_strerror(err));
+ exit(1);
+ }
+
+ if (mode_listen) {
+ int fd, reuseaddr_flag = 1;
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ||
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_flag, sizeof(reuseaddr_flag)) != 0 ||
+ bind(fd, res->ai_addr, res->ai_addrlen) != 0 || listen(fd, SOMAXCONN) != 0) {
+ fprintf(stderr, "failed to listen to %s:%s:%s\n", host, port, strerror(errno));
+ exit(1);
+ }
+ h2o_socket_t *listen_sock = h2o_evloop_socket_create(loop, fd, H2O_SOCKET_FLAG_DONT_READ);
+ h2o_socket_read_start(listen_sock, on_accept);
+ } else {
+ if ((sock = h2o_socket_connect(loop, res->ai_addr, res->ai_addrlen, on_connect)) == NULL) {
+ fprintf(stderr, "failed to create socket:%s\n", strerror(errno));
+ exit(1);
+ }
+ }
+
+ while (1) {
+#if H2O_USE_LIBUV
+ uv_run(loop, UV_RUN_DEFAULT);
+#else
+ h2o_evloop_run(loop, INT32_MAX);
+#endif
+ }
+
+ return 0;
+}
diff --git a/debian/vendor-h2o/examples/libh2o/simple.c b/debian/vendor-h2o/examples/libh2o/simple.c
new file mode 100644
index 0000000..bb72bf6
--- /dev/null
+++ b/debian/vendor-h2o/examples/libh2o/simple.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <errno.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include "h2o.h"
+#include "h2o/http1.h"
+#include "h2o/http2.h"
+#include "h2o/memcached.h"
+
+#define USE_HTTPS 0
+#define USE_MEMCACHED 0
+
+static h2o_pathconf_t *register_handler(h2o_hostconf_t *hostconf, const char *path, int (*on_req)(h2o_handler_t *, h2o_req_t *))
+{
+ h2o_pathconf_t *pathconf = h2o_config_register_path(hostconf, path, 0);
+ h2o_handler_t *handler = h2o_create_handler(pathconf, sizeof(*handler));
+ handler->on_req = on_req;
+ return pathconf;
+}
+
+static int chunked_test(h2o_handler_t *self, h2o_req_t *req)
+{
+ static h2o_generator_t generator = {NULL, NULL};
+
+ if (!h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET")))
+ return -1;
+
+ h2o_iovec_t body = h2o_strdup(&req->pool, "hello world\n", SIZE_MAX);
+ req->res.status = 200;
+ req->res.reason = "OK";
+ h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain"));
+ h2o_start_response(req, &generator);
+ h2o_send(req, &body, 1, 1);
+
+ return 0;
+}
+
+static int reproxy_test(h2o_handler_t *self, h2o_req_t *req)
+{
+ if (!h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET")))
+ return -1;
+
+ req->res.status = 200;
+ req->res.reason = "OK";
+ h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_X_REPROXY_URL, NULL, H2O_STRLIT("http://www.ietf.org/"));
+ h2o_send_inline(req, H2O_STRLIT("you should never see this!\n"));
+
+ return 0;
+}
+
+static int post_test(h2o_handler_t *self, h2o_req_t *req)
+{
+ if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST")) &&
+ h2o_memis(req->path_normalized.base, req->path_normalized.len, H2O_STRLIT("/post-test/"))) {
+ static h2o_generator_t generator = {NULL, NULL};
+ req->res.status = 200;
+ req->res.reason = "OK";
+ h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain; charset=utf-8"));
+ h2o_start_response(req, &generator);
+ h2o_send(req, &req->entity, 1, 1);
+ return 0;
+ }
+
+ return -1;
+}
+
+static h2o_globalconf_t config;
+static h2o_context_t ctx;
+static h2o_multithread_receiver_t libmemcached_receiver;
+static h2o_accept_ctx_t accept_ctx;
+
+#if H2O_USE_LIBUV
+
+static void on_accept(uv_stream_t *listener, int status)
+{
+ uv_tcp_t *conn;
+ h2o_socket_t *sock;
+
+ if (status != 0)
+ return;
+
+ conn = h2o_mem_alloc(sizeof(*conn));
+ uv_tcp_init(listener->loop, conn);
+
+ if (uv_accept(listener, (uv_stream_t *)conn) != 0) {
+ uv_close((uv_handle_t *)conn, (uv_close_cb)free);
+ return;
+ }
+
+ sock = h2o_uv_socket_create((uv_stream_t *)conn, (uv_close_cb)free);
+ h2o_accept(&accept_ctx, sock);
+}
+
+static int create_listener(void)
+{
+ static uv_tcp_t listener;
+ struct sockaddr_in addr;
+ int r;
+
+ uv_tcp_init(ctx.loop, &listener);
+ uv_ip4_addr("127.0.0.1", 7890, &addr);
+ if ((r = uv_tcp_bind(&listener, (struct sockaddr *)&addr, 0)) != 0) {
+ fprintf(stderr, "uv_tcp_bind:%s\n", uv_strerror(r));
+ goto Error;
+ }
+ if ((r = uv_listen((uv_stream_t *)&listener, 128, on_accept)) != 0) {
+ fprintf(stderr, "uv_listen:%s\n", uv_strerror(r));
+ goto Error;
+ }
+
+ return 0;
+Error:
+ uv_close((uv_handle_t *)&listener, NULL);
+ return r;
+}
+
+#else
+
+static void on_accept(h2o_socket_t *listener, const char *err)
+{
+ h2o_socket_t *sock;
+
+ if (err != NULL) {
+ return;
+ }
+
+ if ((sock = h2o_evloop_socket_accept(listener)) == NULL)
+ return;
+ h2o_accept(&accept_ctx, sock);
+}
+
+static int create_listener(void)
+{
+ struct sockaddr_in addr;
+ int fd, reuseaddr_flag = 1;
+ h2o_socket_t *sock;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ addr.sin_port = htons(7890);
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ||
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_flag, sizeof(reuseaddr_flag)) != 0 ||
+ bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 || listen(fd, SOMAXCONN) != 0) {
+ return -1;
+ }
+
+ sock = h2o_evloop_socket_create(ctx.loop, fd, H2O_SOCKET_FLAG_DONT_READ);
+ h2o_socket_read_start(sock, on_accept);
+
+ return 0;
+}
+
+#endif
+
+static int setup_ssl(const char *cert_file, const char *key_file)
+{
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+
+ accept_ctx.ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ SSL_CTX_set_options(accept_ctx.ssl_ctx, SSL_OP_NO_SSLv2);
+
+ if (USE_MEMCACHED) {
+ accept_ctx.libmemcached_receiver = &libmemcached_receiver;
+ h2o_accept_setup_async_ssl_resumption(h2o_memcached_create_context("127.0.0.1", 11211, 0, 1, "h2o:ssl-resumption:"), 86400);
+ h2o_socket_ssl_async_resumption_setup_ctx(accept_ctx.ssl_ctx);
+ }
+
+ /* load certificate and private key */
+ if (SSL_CTX_use_certificate_file(accept_ctx.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) {
+ fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file);
+ return -1;
+ }
+ if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
+ fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file);
+ return -1;
+ }
+
+/* setup protocol negotiation methods */
+#if H2O_USE_NPN
+ h2o_ssl_register_npn_protocols(accept_ctx.ssl_ctx, h2o_http2_npn_protocols);
+#endif
+#if H2O_USE_ALPN
+ h2o_ssl_register_alpn_protocols(accept_ctx.ssl_ctx, h2o_http2_alpn_protocols);
+#endif
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ h2o_hostconf_t *hostconf;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ h2o_config_init(&config);
+ hostconf = h2o_config_register_host(&config, h2o_iovec_init(H2O_STRLIT("default")), 65535);
+ register_handler(hostconf, "/post-test", post_test);
+ register_handler(hostconf, "/chunked-test", chunked_test);
+ h2o_reproxy_register(register_handler(hostconf, "/reproxy-test", reproxy_test));
+ h2o_file_register(h2o_config_register_path(hostconf, "/", 0), "examples/doc_root", NULL, NULL, 0);
+
+#if H2O_USE_LIBUV
+ uv_loop_t loop;
+ uv_loop_init(&loop);
+ h2o_context_init(&ctx, &loop, &config);
+#else
+ h2o_context_init(&ctx, h2o_evloop_create(), &config);
+#endif
+ if (USE_MEMCACHED)
+ h2o_multithread_register_receiver(ctx.queue, &libmemcached_receiver, h2o_memcached_receiver);
+
+ if (USE_HTTPS && setup_ssl("examples/h2o/server.crt", "examples/h2o/server.key") != 0)
+ goto Error;
+
+ /* disabled by default: uncomment the line below to enable access logging */
+ /* h2o_access_log_register(&config.default_host, "/dev/stdout", NULL); */
+
+ accept_ctx.ctx = &ctx;
+ accept_ctx.hosts = config.hosts;
+
+ if (create_listener() != 0) {
+ fprintf(stderr, "failed to listen to 127.0.0.1:7890:%s\n", strerror(errno));
+ goto Error;
+ }
+
+#if H2O_USE_LIBUV
+ uv_run(ctx.loop, UV_RUN_DEFAULT);
+#else
+ while (h2o_evloop_run(ctx.loop, INT32_MAX) == 0)
+ ;
+#endif
+
+Error:
+ return 1;
+}
diff --git a/debian/vendor-h2o/examples/libh2o/socket-client.c b/debian/vendor-h2o/examples/libh2o/socket-client.c
new file mode 100644
index 0000000..591d389
--- /dev/null
+++ b/debian/vendor-h2o/examples/libh2o/socket-client.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include "h2o/socket.h"
+#include "h2o/string_.h"
+
+static h2o_loop_t *loop;
+const char *host;
+static SSL_CTX *ssl_ctx;
+static int exit_loop;
+
+static void on_read(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ /* read failed */
+ fprintf(stderr, "read failed:%s\n", err);
+ h2o_socket_close(sock);
+ exit_loop = 1;
+ return;
+ }
+
+ fwrite(sock->input->bytes, 1, sock->input->size, stdout);
+}
+
+static void on_write(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ /* write failed */
+ fprintf(stderr, "write failed:%s\n", err);
+ h2o_socket_close(sock);
+ exit_loop = 1;
+ return;
+ }
+
+ h2o_socket_read_start(sock, on_read);
+}
+
+static void on_handshake_complete(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ /* TLS handshake failed */
+ fprintf(stderr, "TLS handshake failure:%s\n", err);
+ h2o_socket_close(sock);
+ exit_loop = 1;
+ return;
+ }
+
+ h2o_socket_write(sock, sock->data, 1, on_write);
+}
+
+static void on_connect(h2o_socket_t *sock, const char *err)
+{
+ if (err != NULL) {
+ /* connection failed */
+ fprintf(stderr, "failed to connect to host:%s\n", err);
+ h2o_socket_close(sock);
+ exit_loop = 1;
+ return;
+ }
+
+ if (ssl_ctx != NULL) {
+ h2o_socket_ssl_handshake(sock, ssl_ctx, host, on_handshake_complete);
+ } else {
+ h2o_socket_write(sock, sock->data, 1, on_write);
+ }
+}
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr, "Usage: %s [--tls] <host> <port>\n", cmd);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ struct addrinfo hints, *res = NULL;
+ int err, ret = 1;
+ h2o_socket_t *sock;
+ h2o_iovec_t send_data = {H2O_STRLIT("GET / HTTP/1.0\r\n\r\n")};
+
+ const char *cmd = (--argc, *argv++);
+ if (argc < 2)
+ usage(cmd);
+ if (strcmp(*argv, "-t") == 0 || strcmp(*argv, "--tls") == 0) {
+ --argc, ++argv;
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ ssl_ctx = SSL_CTX_new(TLSv1_client_method());
+ SSL_CTX_load_verify_locations(ssl_ctx, H2O_TO_STR(H2O_ROOT) "/share/h2o/ca-bundle.crt", NULL);
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
+ }
+ if (argc != 2)
+ usage(cmd);
+ host = (--argc, *argv++);
+ const char *port = (--argc, *argv++);
+
+#if H2O_USE_LIBUV
+ loop = uv_loop_new();
+#else
+ loop = h2o_evloop_create();
+#endif
+
+ /* resolve destination (FIXME use the function supplied by the loop) */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = AI_ADDRCONFIG;
+ if ((err = getaddrinfo(host, port, &hints, &res)) != 0) {
+ fprintf(stderr, "failed to resolve %s:%s:%s\n", host, port, gai_strerror(err));
+ goto Exit;
+ }
+
+ if ((sock = h2o_socket_connect(loop, res->ai_addr, res->ai_addrlen, on_connect)) == NULL) {
+ fprintf(stderr, "failed to create socket:%s\n", strerror(errno));
+ goto Exit;
+ }
+ sock->data = &send_data;
+
+ while (!exit_loop) {
+#if H2O_USE_LIBUV
+ uv_run(loop, UV_RUN_DEFAULT);
+#else
+ h2o_evloop_run(loop, INT32_MAX);
+#endif
+ }
+
+ ret = 0;
+
+Exit:
+ if (loop != NULL) {
+#if H2O_USE_LIBUV
+ uv_loop_delete(loop);
+#else
+// FIXME
+// h2o_evloop_destroy(loop);
+#endif
+ }
+ return ret;
+}
diff --git a/debian/vendor-h2o/examples/libh2o/websocket.c b/debian/vendor-h2o/examples/libh2o/websocket.c
new file mode 100644
index 0000000..c977bbd
--- /dev/null
+++ b/debian/vendor-h2o/examples/libh2o/websocket.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <uv.h>
+#include "h2o.h"
+#include "h2o/websocket.h"
+
+static void on_ws_message(h2o_websocket_conn_t *conn, const struct wslay_event_on_msg_recv_arg *arg)
+{
+ if (arg == NULL) {
+ h2o_websocket_close(conn);
+ return;
+ }
+
+ if (!wslay_is_ctrl_frame(arg->opcode)) {
+ struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
+ wslay_event_queue_msg(conn->ws_ctx, &msgarg);
+ }
+}
+
+static int on_req(h2o_handler_t *self, h2o_req_t *req)
+{
+ const char *client_key;
+
+ if (h2o_is_websocket_handshake(req, &client_key) != 0 || client_key == NULL) {
+ return -1;
+ }
+ h2o_upgrade_to_websocket(req, client_key, NULL, on_ws_message);
+ return 0;
+}
+
+static h2o_globalconf_t config;
+static h2o_context_t ctx;
+static h2o_accept_ctx_t accept_ctx;
+
+static void on_connect(uv_stream_t *server, int status)
+{
+ uv_tcp_t *conn;
+ h2o_socket_t *sock;
+
+ if (status != 0)
+ return;
+
+ conn = h2o_mem_alloc(sizeof(*conn));
+ uv_tcp_init(server->loop, conn);
+ if (uv_accept(server, (uv_stream_t *)conn) != 0) {
+ uv_close((uv_handle_t *)conn, (uv_close_cb)free);
+ return;
+ }
+
+ sock = h2o_uv_socket_create((uv_stream_t *)conn, (uv_close_cb)free);
+ h2o_accept(&accept_ctx, sock);
+}
+
+static int setup_ssl(const char *cert_file, const char *key_file)
+{
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+
+ accept_ctx.ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ SSL_CTX_set_options(accept_ctx.ssl_ctx, SSL_OP_NO_SSLv2);
+
+ /* load certificate and private key */
+ if (SSL_CTX_use_certificate_file(accept_ctx.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) {
+ fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file);
+ return -1;
+ }
+ if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
+ fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file);
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ uv_loop_t *loop = uv_default_loop();
+ uv_tcp_t listener;
+ struct sockaddr_in sockaddr;
+ h2o_hostconf_t *hostconf;
+ h2o_pathconf_t *pathconf;
+ int r;
+
+ if ((r = uv_tcp_init(loop, &listener)) != 0) {
+ fprintf(stderr, "uv_tcp_init:%s\n", uv_strerror(r));
+ goto Error;
+ }
+ uv_ip4_addr("127.0.0.1", 7890, &sockaddr);
+ if ((r = uv_tcp_bind(&listener, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) != 0) {
+ fprintf(stderr, "uv_tcp_bind:%s\n", uv_strerror(r));
+ goto Error;
+ }
+ if ((r = uv_listen((uv_stream_t *)&listener, 128, on_connect)) != 0) {
+ fprintf(stderr, "uv_listen:%s\n", uv_strerror(r));
+ goto Error;
+ }
+
+ h2o_config_init(&config);
+ hostconf = h2o_config_register_host(&config, h2o_iovec_init(H2O_STRLIT("default")), 65535);
+ pathconf = h2o_config_register_path(hostconf, "/", 0);
+ h2o_create_handler(pathconf, sizeof(h2o_handler_t))->on_req = on_req;
+
+ h2o_context_init(&ctx, loop, &config);
+
+ /* disabled by default: uncomment the block below to use HTTPS instead of HTTP */
+ /*
+ if (setup_ssl("server.crt", "server.key") != 0)
+ goto Error;
+ */
+
+ accept_ctx.ctx = &ctx;
+ accept_ctx.hosts = config.hosts;
+
+ return uv_run(loop, UV_RUN_DEFAULT);
+
+Error:
+ return 1;
+}