diff options
Diffstat (limited to 'web/server/h2o/libh2o/include')
33 files changed, 5989 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/include/h2o.h b/web/server/h2o/libh2o/include/h2o.h new file mode 100644 index 000000000..57877bd12 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o.h @@ -0,0 +1,2116 @@ +/* + * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc. + * + * 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. + */ +#ifndef h2o_h +#define h2o_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <time.h> +#include <unistd.h> +#include <openssl/ssl.h> +#include "h2o/filecache.h" +#include "h2o/hostinfo.h" +#include "h2o/memcached.h" +#include "h2o/linklist.h" +#include "h2o/http1client.h" +#include "h2o/memory.h" +#include "h2o/multithread.h" +#include "h2o/rand.h" +#include "h2o/socket.h" +#include "h2o/string_.h" +#include "h2o/time_.h" +#include "h2o/timeout.h" +#include "h2o/url.h" +#include "h2o/version.h" + +#ifndef H2O_USE_BROTLI +/* disabled for all but the standalone server, since the encoder is written in C++ */ +#define H2O_USE_BROTLI 0 +#endif + +#ifndef H2O_MAX_HEADERS +#define H2O_MAX_HEADERS 100 +#endif +#ifndef H2O_MAX_REQLEN +#define H2O_MAX_REQLEN (8192 + 4096 * (H2O_MAX_HEADERS)) +#endif + +#ifndef H2O_MAX_TOKENS +#define H2O_MAX_TOKENS 100 +#endif + +#ifndef H2O_SOMAXCONN +/* simply use a large value, and let the kernel clip it to the internal max */ +#define H2O_SOMAXCONN 65535 +#endif + +#define H2O_DEFAULT_MAX_REQUEST_ENTITY_SIZE (1024 * 1024 * 1024) +#define H2O_DEFAULT_MAX_DELEGATIONS 5 +#define H2O_DEFAULT_HANDSHAKE_TIMEOUT_IN_SECS 10 +#define H2O_DEFAULT_HANDSHAKE_TIMEOUT (H2O_DEFAULT_HANDSHAKE_TIMEOUT_IN_SECS * 1000) +#define H2O_DEFAULT_HTTP1_REQ_TIMEOUT_IN_SECS 10 +#define H2O_DEFAULT_HTTP1_REQ_TIMEOUT (H2O_DEFAULT_HTTP1_REQ_TIMEOUT_IN_SECS * 1000) +#define H2O_DEFAULT_HTTP1_UPGRADE_TO_HTTP2 1 +#define H2O_DEFAULT_HTTP2_IDLE_TIMEOUT_IN_SECS 10 +#define H2O_DEFAULT_HTTP2_IDLE_TIMEOUT (H2O_DEFAULT_HTTP2_IDLE_TIMEOUT_IN_SECS * 1000) +#define H2O_DEFAULT_HTTP2_GRACEFUL_SHUTDOWN_TIMEOUT_IN_SECS 0 /* no timeout */ +#define H2O_DEFAULT_HTTP2_GRACEFUL_SHUTDOWN_TIMEOUT (H2O_DEFAULT_HTTP2_GRACEFUL_SHUTDOWN_TIMEOUT_IN_SECS * 1000) +#define H2O_DEFAULT_PROXY_IO_TIMEOUT_IN_SECS 30 +#define H2O_DEFAULT_PROXY_IO_TIMEOUT (H2O_DEFAULT_PROXY_IO_TIMEOUT_IN_SECS * 1000) +#define H2O_DEFAULT_PROXY_WEBSOCKET_TIMEOUT_IN_SECS 300 +#define H2O_DEFAULT_PROXY_WEBSOCKET_TIMEOUT (H2O_DEFAULT_PROXY_WEBSOCKET_TIMEOUT_IN_SECS * 1000) +#define H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_CAPACITY 4096 +#define H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_DURATION 86400000 /* 24 hours */ + +typedef struct st_h2o_conn_t h2o_conn_t; +typedef struct st_h2o_context_t h2o_context_t; +typedef struct st_h2o_req_t h2o_req_t; +typedef struct st_h2o_ostream_t h2o_ostream_t; +typedef struct st_h2o_configurator_command_t h2o_configurator_command_t; +typedef struct st_h2o_configurator_t h2o_configurator_t; +typedef struct st_h2o_hostconf_t h2o_hostconf_t; +typedef struct st_h2o_globalconf_t h2o_globalconf_t; +typedef struct st_h2o_mimemap_t h2o_mimemap_t; +typedef struct st_h2o_logconf_t h2o_logconf_t; +typedef struct st_h2o_headers_command_t h2o_headers_command_t; + +/** + * a predefined, read-only, fast variant of h2o_iovec_t, defined in h2o/token.h + */ +typedef struct st_h2o_token_t { + h2o_iovec_t buf; + char http2_static_table_name_index; /* non-zero if any */ + unsigned char proxy_should_drop_for_req : 1; + unsigned char proxy_should_drop_for_res : 1; + unsigned char is_init_header_special : 1; + unsigned char http2_should_reject : 1; + unsigned char copy_for_push_request : 1; + unsigned char dont_compress : 1; +} h2o_token_t; + +#include "h2o/token.h" + +/** + * basic structure of a handler (an object that MAY generate a response) + * The handlers should register themselves to h2o_context_t::handlers. + */ +typedef struct st_h2o_handler_t { + size_t _config_slot; + void (*on_context_init)(struct st_h2o_handler_t *self, h2o_context_t *ctx); + void (*on_context_dispose)(struct st_h2o_handler_t *self, h2o_context_t *ctx); + void (*dispose)(struct st_h2o_handler_t *self); + int (*on_req)(struct st_h2o_handler_t *self, h2o_req_t *req); +} h2o_handler_t; + +/** + * basic structure of a filter (an object that MAY modify a response) + * The filters should register themselves to h2o_context_t::filters. + */ +typedef struct st_h2o_filter_t { + size_t _config_slot; + void (*on_context_init)(struct st_h2o_filter_t *self, h2o_context_t *ctx); + void (*on_context_dispose)(struct st_h2o_filter_t *self, h2o_context_t *ctx); + void (*dispose)(struct st_h2o_filter_t *self); + void (*on_setup_ostream)(struct st_h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t **slot); +} h2o_filter_t; + +/** + * basic structure of a logger (an object that MAY log a request) + * The loggers should register themselves to h2o_context_t::loggers. + */ +typedef struct st_h2o_logger_t { + size_t _config_slot; + void (*on_context_init)(struct st_h2o_logger_t *self, h2o_context_t *ctx); + void (*on_context_dispose)(struct st_h2o_logger_t *self, h2o_context_t *ctx); + void (*dispose)(struct st_h2o_logger_t *self); + void (*log_access)(struct st_h2o_logger_t *self, h2o_req_t *req); +} h2o_logger_t; + +/** + * contains stringified representations of a timestamp + */ +typedef struct st_h2o_timestamp_string_t { + char rfc1123[H2O_TIMESTR_RFC1123_LEN + 1]; + char log[H2O_TIMESTR_LOG_LEN + 1]; +} h2o_timestamp_string_t; + +/** + * a timestamp. + * Applications should call h2o_get_timestamp to obtain a timestamp. + */ +typedef struct st_h2o_timestamp_t { + struct timeval at; + h2o_timestamp_string_t *str; +} h2o_timestamp_t; + +typedef struct st_h2o_casper_conf_t { + /** + * capacity bits (0 to disable casper) + */ + unsigned capacity_bits; + /** + * whether if all type of files should be tracked (or only the blocking assets) + */ + int track_all_types; +} h2o_casper_conf_t; + +typedef struct st_h2o_envconf_t { + /** + * parent + */ + struct st_h2o_envconf_t *parent; + /** + * list of names to be unset + */ + h2o_iovec_vector_t unsets; + /** + * list of name-value pairs to be set + */ + h2o_iovec_vector_t sets; +} h2o_envconf_t; + +typedef struct st_h2o_pathconf_t { + /** + * globalconf to which the pathconf belongs + */ + h2o_globalconf_t *global; + /** + * pathname in lower case, may or may not have "/" at last, NULL terminated, or is {NULL,0} if is fallback or extension-level + */ + h2o_iovec_t path; + /** + * list of handlers + */ + H2O_VECTOR(h2o_handler_t *) handlers; + /** + * list of filters + */ + H2O_VECTOR(h2o_filter_t *) filters; + /** + * list of loggers (h2o_logger_t) + */ + H2O_VECTOR(h2o_logger_t *) loggers; + /** + * mimemap + */ + h2o_mimemap_t *mimemap; + /** + * env + */ + h2o_envconf_t *env; + /** + * error-log + */ + struct { + /** + * if request-level errors should be emitted to stderr + */ + unsigned emit_request_errors : 1; + } error_log; +} h2o_pathconf_t; + +struct st_h2o_hostconf_t { + /** + * reverse reference to the global configuration + */ + h2o_globalconf_t *global; + /** + * host and port + */ + struct { + /** + * host and port (in lower-case; base is NULL-terminated) + */ + h2o_iovec_t hostport; + /** + * in lower-case; base is NULL-terminated + */ + h2o_iovec_t host; + /** + * port number (or 65535 if default) + */ + uint16_t port; + } authority; + /** + * list of path configurations + */ + H2O_VECTOR(h2o_pathconf_t) paths; + /** + * catch-all path configuration + */ + h2o_pathconf_t fallback_path; + /** + * mimemap + */ + h2o_mimemap_t *mimemap; + /** + * http2 + */ + struct { + /** + * whether if blocking assets being pulled should be given highest priority in case of clients that do not implement + * dependency-based prioritization + */ + unsigned reprioritize_blocking_assets : 1; + /** + * if server push should be used + */ + unsigned push_preload : 1; + /** + * casper settings + */ + h2o_casper_conf_t casper; + } http2; +}; + +typedef struct st_h2o_protocol_callbacks_t { + void (*request_shutdown)(h2o_context_t *ctx); + int (*foreach_request)(h2o_context_t *ctx, int (*cb)(h2o_req_t *req, void *cbdata), void *cbdata); +} h2o_protocol_callbacks_t; + +typedef h2o_iovec_t (*final_status_handler_cb)(void *ctx, h2o_globalconf_t *gconf, h2o_req_t *req); +typedef struct st_h2o_status_handler_t { + h2o_iovec_t name; + void *(*init)(void); /* optional callback, allocates a context that will be passed to per_thread() */ + void (*per_thread)(void *priv, h2o_context_t *ctx); /* optional callback, will be called for each thread */ + h2o_iovec_t (* final)(void *ctx, h2o_globalconf_t *gconf, h2o_req_t *req); /* mandatory, will be passed the optional context */ +} h2o_status_handler_t; + +typedef H2O_VECTOR(h2o_status_handler_t) h2o_status_callbacks_t; +struct st_h2o_globalconf_t { + /** + * a NULL-terminated list of host contexts (h2o_hostconf_t) + */ + h2o_hostconf_t **hosts; + /** + * list of configurators + */ + h2o_linklist_t configurators; + /** + * name of the server (not the hostname) + */ + h2o_iovec_t server_name; + /** + * maximum size of the accepted request entity (e.g. POST data) + */ + size_t max_request_entity_size; + /** + * maximum count for delegations + */ + unsigned max_delegations; + /** + * setuid user (or NULL) + */ + char *user; + + /** + * SSL handshake timeout + */ + uint64_t handshake_timeout; + + struct { + /** + * request timeout (in milliseconds) + */ + uint64_t req_timeout; + /** + * a boolean value indicating whether or not to upgrade to HTTP/2 + */ + int upgrade_to_http2; + /** + * list of callbacks + */ + h2o_protocol_callbacks_t callbacks; + } http1; + + struct { + /** + * idle timeout (in milliseconds) + */ + uint64_t idle_timeout; + /** + * graceful shutdown timeout (in milliseconds) + */ + uint64_t graceful_shutdown_timeout; + /** + * maximum number of HTTP2 requests (per connection) to be handled simultaneously internally. + * H2O accepts at most 256 requests over HTTP/2, but internally limits the number of in-flight requests to the value + * specified by this property in order to limit the resources allocated to a single connection. + */ + size_t max_concurrent_requests_per_connection; + /** + * maximum nuber of streams (per connection) to be allowed in IDLE / CLOSED state (used for tracking dependencies). + */ + size_t max_streams_for_priority; + /** + * conditions for latency optimization + */ + h2o_socket_latency_optimization_conditions_t latency_optimization; + /** + * list of callbacks + */ + h2o_protocol_callbacks_t callbacks; + } http2; + + struct { + /** + * io timeout (in milliseconds) + */ + uint64_t io_timeout; + /** + * SSL context for connections initiated by the proxy (optional, governed by the application) + */ + SSL_CTX *ssl_ctx; + /** + * a boolean flag if set to true, instructs the proxy to preserve the x-forwarded-proto header passed by the client + */ + unsigned preserve_x_forwarded_proto : 1; + /** + * a boolean flag if set to true, instructs the proxy to preserve the server header passed by the origin + */ + unsigned preserve_server_header : 1; + /** + * a boolean flag if set to true, instructs the proxy to emit x-forwarded-proto and x-forwarded-for headers + */ + unsigned emit_x_forwarded_headers : 1; + /** + * a boolean flag if set to true, instructs the proxy to emit a via header + */ + unsigned emit_via_header : 1; + } proxy; + + /** + * mimemap + */ + h2o_mimemap_t *mimemap; + + /** + * filecache + */ + struct { + /* capacity of the filecache */ + size_t capacity; + } filecache; + + /* status */ + h2o_status_callbacks_t statuses; + + size_t _num_config_slots; +}; + +enum { + H2O_COMPRESS_HINT_AUTO = 0, /* default: let h2o negociate compression based on the configuration */ + H2O_COMPRESS_HINT_DISABLE, /* compression was explicitely disabled for this request */ + H2O_COMPRESS_HINT_ENABLE, /* compression was explicitely enabled for this request */ +}; + +/** + * holds various attributes related to the mime-type + */ +typedef struct st_h2o_mime_attributes_t { + /** + * whether if the content can be compressed by using gzip + */ + char is_compressible; + /** + * how the resource should be prioritized + */ + enum { H2O_MIME_ATTRIBUTE_PRIORITY_NORMAL = 0, H2O_MIME_ATTRIBUTE_PRIORITY_HIGHEST } priority; +} h2o_mime_attributes_t; + +extern h2o_mime_attributes_t h2o_mime_attributes_as_is; + +/** + * represents either a mime-type (and associated info), or contains pathinfo in case of a dynamic type (e.g. .php files) + */ +typedef struct st_h2o_mimemap_type_t { + enum { H2O_MIMEMAP_TYPE_MIMETYPE = 0, H2O_MIMEMAP_TYPE_DYNAMIC = 1 } type; + union { + struct { + h2o_iovec_t mimetype; + h2o_mime_attributes_t attr; + }; + struct { + h2o_pathconf_t pathconf; + } dynamic; + } data; +} h2o_mimemap_type_t; + +/* defined as negated form of the error codes defined in HTTP2-spec section 7 */ +#define H2O_HTTP2_ERROR_NONE 0 +#define H2O_HTTP2_ERROR_PROTOCOL -1 +#define H2O_HTTP2_ERROR_INTERNAL -2 +#define H2O_HTTP2_ERROR_FLOW_CONTROL -3 +#define H2O_HTTP2_ERROR_SETTINGS_TIMEOUT -4 +#define H2O_HTTP2_ERROR_STREAM_CLOSED -5 +#define H2O_HTTP2_ERROR_FRAME_SIZE -6 +#define H2O_HTTP2_ERROR_REFUSED_STREAM -7 +#define H2O_HTTP2_ERROR_CANCEL -8 +#define H2O_HTTP2_ERROR_COMPRESSION -9 +#define H2O_HTTP2_ERROR_CONNECT -10 +#define H2O_HTTP2_ERROR_ENHANCE_YOUR_CALM -11 +#define H2O_HTTP2_ERROR_INADEQUATE_SECURITY -12 +#define H2O_HTTP2_ERROR_MAX 13 +/* end of the HTT2-spec defined errors */ +#define H2O_HTTP2_ERROR_INVALID_HEADER_CHAR \ + -254 /* an internal value indicating that invalid characters were found in the header name or value */ +#define H2O_HTTP2_ERROR_INCOMPLETE -255 /* an internal value indicating that all data is not ready */ +#define H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY -256 + +enum { + /* http1 protocol errors */ + H2O_STATUS_ERROR_400 = 0, + H2O_STATUS_ERROR_403, + H2O_STATUS_ERROR_404, + H2O_STATUS_ERROR_405, + H2O_STATUS_ERROR_413, + H2O_STATUS_ERROR_416, + H2O_STATUS_ERROR_417, + H2O_STATUS_ERROR_500, + H2O_STATUS_ERROR_502, + H2O_STATUS_ERROR_503, + H2O_STATUS_ERROR_MAX, +}; + +/** + * holds various data related to the context + */ +typedef struct st_h2o_context_storage_item_t { + void (*dispose)(void *data); + void *data; +} h2o_context_storage_item_t; + +typedef H2O_VECTOR(h2o_context_storage_item_t) h2o_context_storage_t; + +/** + * context of the http server. + */ +struct st_h2o_context_t { + /** + * points to the loop (either uv_loop_t or h2o_evloop_t, depending on the value of H2O_USE_LIBUV) + */ + h2o_loop_t *loop; + /** + * timeout structure to be used for registering deferred callbacks + */ + h2o_timeout_t zero_timeout; + /** + * timeout structure to be used for registering 1-second timeout callbacks + */ + h2o_timeout_t one_sec_timeout; + /** + * timeout structrue to be used for registering 100-milisecond timeout callbacks + */ + h2o_timeout_t hundred_ms_timeout; + /** + * pointer to the global configuration + */ + h2o_globalconf_t *globalconf; + /** + * queue for receiving messages from other contexts + */ + h2o_multithread_queue_t *queue; + /** + * receivers + */ + struct { + h2o_multithread_receiver_t hostinfo_getaddr; + } receivers; + /** + * open file cache + */ + h2o_filecache_t *filecache; + /** + * context scope storage for general use + */ + h2o_context_storage_t storage; + /** + * flag indicating if shutdown has been requested + */ + int shutdown_requested; + + /** + * SSL handshake timeout + */ + h2o_timeout_t handshake_timeout; + + struct { + /** + * request timeout + */ + h2o_timeout_t req_timeout; + /** + * link-list of h2o_http1_conn_t + */ + h2o_linklist_t _conns; + } http1; + + struct { + /** + * idle timeout + */ + h2o_timeout_t idle_timeout; + /** + * link-list of h2o_http2_conn_t + */ + h2o_linklist_t _conns; + /** + * graceful shutdown timeout + */ + h2o_timeout_t graceful_shutdown_timeout; + /** + * timeout entry used for graceful shutdown + */ + h2o_timeout_entry_t _graceful_shutdown_timeout; + struct { + /** + * counter for http2 errors internally emitted by h2o + */ + uint64_t protocol_level_errors[H2O_HTTP2_ERROR_MAX]; + /** + * premature close on read + */ + uint64_t read_closed; + /** + * premature close on write + */ + uint64_t write_closed; + } events; + } http2; + + struct { + /** + * the default client context for proxy + */ + h2o_http1client_ctx_t client_ctx; + /** + * timeout handler used by the default client context + */ + h2o_timeout_t io_timeout; + } proxy; + + /** + * pointer to per-module configs + */ + void **_module_configs; + + struct { + uint64_t uv_now_at; + struct timeval tv_at; + h2o_timestamp_string_t *value; + } _timestamp_cache; + + /** + * counter for http1 error status internally emitted by h2o + */ + uint64_t emitted_error_status[H2O_STATUS_ERROR_MAX]; + + H2O_VECTOR(h2o_pathconf_t *) _pathconfs_inited; +}; + +/** + * represents a HTTP header + */ +typedef struct st_h2o_header_t { + /** + * name of the header (may point to h2o_token_t which is an optimized subclass of h2o_iovec_t) + */ + h2o_iovec_t *name; + /** + * The name of the header as originally received from the client, same length as `name` + */ + const char *orig_name; + /** + * value of the header + */ + h2o_iovec_t value; +} h2o_header_t; + +/** + * list of headers + */ +typedef H2O_VECTOR(h2o_header_t) h2o_headers_t; + +/** + * an object that generates a response. + * The object is typically constructed by handlers calling the h2o_start_response function. + */ +typedef struct st_h2o_generator_t { + /** + * called by the core to request new data to be pushed via the h2o_send function. + */ + void (*proceed)(struct st_h2o_generator_t *self, h2o_req_t *req); + /** + * called by the core when there is a need to terminate the response abruptly + */ + void (*stop)(struct st_h2o_generator_t *self, h2o_req_t *req); +} h2o_generator_t; + +typedef enum h2o_send_state { + H2O_SEND_STATE_IN_PROGRESS, + H2O_SEND_STATE_FINAL, + H2O_SEND_STATE_ERROR, +} h2o_send_state_t; + +typedef h2o_send_state_t (*h2o_ostream_pull_cb)(h2o_generator_t *generator, h2o_req_t *req, h2o_iovec_t *buf); + +static inline int h2o_send_state_is_in_progress(h2o_send_state_t s) +{ + return s == H2O_SEND_STATE_IN_PROGRESS; +} +/** + * an output stream that may alter the output. + * The object is typically constructed by filters calling the h2o_prepend_ostream function. + */ +struct st_h2o_ostream_t { + /** + * points to the next output stream + */ + struct st_h2o_ostream_t *next; + /** + * called by the core to send output. + * Intermediary output streams should process the given output and call the h2o_ostream_send_next function if any data can be + * sent. + */ + void (*do_send)(struct st_h2o_ostream_t *self, h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state); + /** + * called by the core when there is a need to terminate the response abruptly + */ + void (*stop)(struct st_h2o_ostream_t *self, h2o_req_t *req); + /** + * whether if the ostream supports "pull" interface + */ + void (*start_pull)(struct st_h2o_ostream_t *self, h2o_ostream_pull_cb cb); +}; + +/** + * a HTTP response + */ +typedef struct st_h2o_res_t { + /** + * status code + */ + int status; + /** + * reason phrase + */ + const char *reason; + /** + * length of the content (that is sent as the Content-Length header). + * The default value is SIZE_MAX, which means that the length is indeterminate. + * Generators should set this value whenever possible. + */ + size_t content_length; + /** + * list of response headers + */ + h2o_headers_t headers; + /** + * mime-related attributes (may be NULL) + */ + h2o_mime_attributes_t *mime_attr; + /** + * retains the original response header before rewritten by ostream filters + */ + struct { + int status; + h2o_headers_t headers; + } original; +} h2o_res_t; + +/** + * debug state (currently only for HTTP/2) + */ +typedef struct st_h2o_http2_debug_state_t { + h2o_iovec_vector_t json; + ssize_t conn_flow_in; + ssize_t conn_flow_out; +} h2o_http2_debug_state_t; + +typedef struct st_h2o_conn_callbacks_t { + /** + * getsockname (return size of the obtained address, or 0 if failed) + */ + socklen_t (*get_sockname)(h2o_conn_t *conn, struct sockaddr *sa); + /** + * getpeername (return size of the obtained address, or 0 if failed) + */ + socklen_t (*get_peername)(h2o_conn_t *conn, struct sockaddr *sa); + /** + * callback for server push (may be NULL) + */ + void (*push_path)(h2o_req_t *req, const char *abspath, size_t abspath_len); + /** + * Return the underlying socket struct + */ + h2o_socket_t *(*get_socket)(h2o_conn_t *_conn); + /** + * debug state callback (may be NULL) + */ + h2o_http2_debug_state_t *(*get_debug_state)(h2o_req_t *req, int hpack_enabled); + /** + * logging callbacks (may be NULL) + */ + union { + struct { + struct { + h2o_iovec_t (*protocol_version)(h2o_req_t *req); + h2o_iovec_t (*session_reused)(h2o_req_t *req); + h2o_iovec_t (*cipher)(h2o_req_t *req); + h2o_iovec_t (*cipher_bits)(h2o_req_t *req); + h2o_iovec_t (*session_id)(h2o_req_t *req); + } ssl; + struct { + h2o_iovec_t (*request_index)(h2o_req_t *req); + } http1; + struct { + h2o_iovec_t (*stream_id)(h2o_req_t *req); + h2o_iovec_t (*priority_received)(h2o_req_t *req); + h2o_iovec_t (*priority_received_exclusive)(h2o_req_t *req); + h2o_iovec_t (*priority_received_parent)(h2o_req_t *req); + h2o_iovec_t (*priority_received_weight)(h2o_req_t *req); + h2o_iovec_t (*priority_actual)(h2o_req_t *req); + h2o_iovec_t (*priority_actual_parent)(h2o_req_t *req); + h2o_iovec_t (*priority_actual_weight)(h2o_req_t *req); + } http2; + }; + h2o_iovec_t (*callbacks[1])(h2o_req_t *req); + } log_; +} h2o_conn_callbacks_t; + +/** + * basic structure of an HTTP connection (HTTP/1, HTTP/2, etc.) + */ +struct st_h2o_conn_t { + /** + * the context of the server + */ + h2o_context_t *ctx; + /** + * NULL-terminated list of hostconfs bound to the connection + */ + h2o_hostconf_t **hosts; + /** + * time when the connection was established + */ + struct timeval connected_at; + /** + * connection id + */ + uint64_t id; + /** + * callbacks + */ + const h2o_conn_callbacks_t *callbacks; +}; + +/** + * filter used for capturing a response (can be used to implement subreq) + */ +typedef struct st_h2o_req_prefilter_t { + struct st_h2o_req_prefilter_t *next; + void (*on_setup_ostream)(struct st_h2o_req_prefilter_t *self, h2o_req_t *req, h2o_ostream_t **slot); +} h2o_req_prefilter_t; + +typedef struct st_h2o_req_overrides_t { + /** + * specific client context (or NULL) + */ + h2o_http1client_ctx_t *client_ctx; + /** + * socketpool to be used when connecting to upstream (or NULL) + */ + h2o_socketpool_t *socketpool; + /** + * upstream host:port to connect to (or host.base == NULL) + */ + struct { + h2o_iovec_t host; + uint16_t port; + } hostport; + /** + * parameters for rewriting the `Location` header (only used if match.len != 0) + */ + struct { + /** + * if the prefix of the location header matches the url, then the header will be rewritten + */ + h2o_url_t *match; + /** + * path prefix to be inserted upon rewrite + */ + h2o_iovec_t path_prefix; + } location_rewrite; + /** + * whether if the PROXY header should be sent + */ + unsigned use_proxy_protocol : 1; + /** + * headers rewrite commands to be used when sending requests to upstream (or NULL) + */ + h2o_headers_command_t *headers_cmds; +} h2o_req_overrides_t; + +/** + * additional information for extension-based dynamic content + */ +typedef struct st_h2o_filereq_t { + h2o_iovec_t script_name; + h2o_iovec_t path_info; + h2o_iovec_t local_path; +} h2o_filereq_t; + +/** + * error message associated to a request + */ +typedef struct st_h2o_req_error_log_t { + const char *module; + h2o_iovec_t msg; +} h2o_req_error_log_t; + +/** + * a HTTP request + */ +struct st_h2o_req_t { + /** + * the underlying connection + */ + h2o_conn_t *conn; + /** + * the request sent by the client (as is) + */ + struct { + /** + * scheme (http, https, etc.) + */ + const h2o_url_scheme_t *scheme; + /** + * authority (a.k.a. the Host header; the value is supplemented if missing before the handlers are being called) + */ + h2o_iovec_t authority; + /** + * method + */ + h2o_iovec_t method; + /** + * abs-path of the request (unmodified) + */ + h2o_iovec_t path; + /** + * offset of '?' within path, or SIZE_MAX if not found + */ + size_t query_at; + } input; + /** + * the host context + */ + h2o_hostconf_t *hostconf; + /** + * the path context + */ + h2o_pathconf_t *pathconf; + /** + * scheme (http, https, etc.) + */ + const h2o_url_scheme_t *scheme; + /** + * authority (of the processing request) + */ + h2o_iovec_t authority; + /** + * method (of the processing request) + */ + h2o_iovec_t method; + /** + * abs-path of the processing request + */ + h2o_iovec_t path; + /** + * offset of '?' within path, or SIZE_MAX if not found + */ + size_t query_at; + /** + * normalized path of the processing request (i.e. no "." or "..", no query) + */ + h2o_iovec_t path_normalized; + /** + * Map of indexes of `path_normalized` into the next character in `path`; built only if `path` required normalization + */ + size_t *norm_indexes; + /** + * filters assigned per request + */ + h2o_req_prefilter_t *prefilters; + /** + * additional information (becomes available for extension-based dynamic content) + */ + h2o_filereq_t *filereq; + /** + * overrides (maybe NULL) + */ + h2o_req_overrides_t *overrides; + /** + * the HTTP version (represented as 0xMMmm (M=major, m=minor)) + */ + int version; + /** + * list of request headers + */ + h2o_headers_t headers; + /** + * the request entity (base == NULL if none) + */ + h2o_iovec_t entity; + /** + * timestamp when the request was processed + */ + h2o_timestamp_t processed_at; + /** + * additional timestamps + */ + struct { + struct timeval request_begin_at; + struct timeval request_body_begin_at; + struct timeval response_start_at; + struct timeval response_end_at; + } timestamps; + /** + * the response + */ + h2o_res_t res; + /** + * number of bytes sent by the generator (excluding headers) + */ + size_t bytes_sent; + /** + * counts the number of times the request has been reprocessed (excluding delegation) + */ + unsigned num_reprocessed; + /** + * counts the number of times the request has been delegated + */ + unsigned num_delegated; + + /** + * environment variables + */ + h2o_iovec_vector_t env; + + /** + * error logs + */ + H2O_VECTOR(h2o_req_error_log_t) error_logs; + + /* flags */ + + /** + * whether or not the connection is persistent. + * Applications should set this flag to zero in case the connection cannot be kept keep-alive (due to an error etc.) + */ + unsigned char http1_is_persistent : 1; + /** + * whether if the response has been delegated (i.e. reproxied). + * For delegated responses, redirect responses would be handled internally. + */ + unsigned char res_is_delegated : 1; + /** + * whether if the bytes sent is counted by ostreams other than final ostream + */ + unsigned char bytes_counted_by_ostream : 1; + + /** + * Whether the producer of the response has explicitely disabled or + * enabled compression. One of H2O_COMPRESS_HINT_* + */ + char compress_hint; + + /** + * the Upgrade request header (or { NULL, 0 } if not available) + */ + h2o_iovec_t upgrade; + + /** + * preferred chunk size by the ostream + */ + size_t preferred_chunk_size; + + /* internal structure */ + h2o_generator_t *_generator; + h2o_ostream_t *_ostr_top; + size_t _next_filter_index; + h2o_timeout_entry_t _timeout_entry; + /* per-request memory pool (placed at the last since the structure is large) */ + h2o_mem_pool_t pool; +}; + +typedef struct st_h2o_accept_ctx_t { + h2o_context_t *ctx; + h2o_hostconf_t **hosts; + SSL_CTX *ssl_ctx; + int expect_proxy_line; + h2o_multithread_receiver_t *libmemcached_receiver; +} h2o_accept_ctx_t; + +typedef struct st_h2o_doublebuffer_t { + h2o_buffer_t *buf; + size_t bytes_inflight; +} h2o_doublebuffer_t; + +static void h2o_doublebuffer_init(h2o_doublebuffer_t *db, h2o_buffer_prototype_t *prototype); +static void h2o_doublebuffer_dispose(h2o_doublebuffer_t *db); +static h2o_iovec_t h2o_doublebuffer_prepare(h2o_doublebuffer_t *db, h2o_buffer_t **receiving, size_t max_bytes); +static void h2o_doublebuffer_consume(h2o_doublebuffer_t *db); + +/* token */ + +extern h2o_token_t h2o__tokens[H2O_MAX_TOKENS]; +extern size_t h2o__num_tokens; + +/** + * returns a token (an optimized subclass of h2o_iovec_t) containing given string, or NULL if no such thing is available + */ +const h2o_token_t *h2o_lookup_token(const char *name, size_t len); +/** + * returns an boolean value if given buffer is a h2o_token_t. + */ +int h2o_iovec_is_token(const h2o_iovec_t *buf); + +/* headers */ + +/** + * searches for a header of given name (fast, by comparing tokens) + * @param headers header list + * @param token name of the header to search for + * @param cursor index of the last match (or set SIZE_MAX to start a new search) + * @return index of the found header (or SIZE_MAX if not found) + */ +ssize_t h2o_find_header(const h2o_headers_t *headers, const h2o_token_t *token, ssize_t cursor); +/** + * searches for a header of given name (slow, by comparing strings) + * @param headers header list + * @param name name of the header to search for + * @param name_len length of the name + * @param cursor index of the last match (or set SIZE_MAX to start a new search) + * @return index of the found header (or SIZE_MAX if not found) + */ +ssize_t h2o_find_header_by_str(const h2o_headers_t *headers, const char *name, size_t name_len, ssize_t cursor); +/** + * adds a header to list + */ +void h2o_add_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *orig_name, + const char *value, size_t value_len); +/** + * adds a header to list + */ +void h2o_add_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, + const char *orig_name, const char *value, size_t value_len); +/** + * adds or replaces a header into the list + */ +void h2o_set_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *value, size_t value_len, + int overwrite_if_exists); +/** + * adds or replaces a header into the list + */ +void h2o_set_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, + const char *value, size_t value_len, int overwrite_if_exists); +/** + * sets a header token + */ +void h2o_set_header_token(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *value, + size_t value_len); +/** + * deletes a header from list + */ +ssize_t h2o_delete_header(h2o_headers_t *headers, ssize_t cursor); + +/* util */ + +extern const char *h2o_http2_npn_protocols; +extern const char *h2o_npn_protocols; +extern const h2o_iovec_t *h2o_http2_alpn_protocols; +extern const h2o_iovec_t *h2o_alpn_protocols; + +/** + * accepts a connection + */ +void h2o_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock); +/** + * creates a new connection + */ +static h2o_conn_t *h2o_create_connection(size_t sz, h2o_context_t *ctx, h2o_hostconf_t **hosts, struct timeval connected_at, + const h2o_conn_callbacks_t *callbacks); +/** + * setups accept context for async SSL resumption + */ +void h2o_accept_setup_async_ssl_resumption(h2o_memcached_context_t *ctx, unsigned expiration); +/** + * returns the protocol version (e.g. "HTTP/1.1", "HTTP/2") + */ +size_t h2o_stringify_protocol_version(char *dst, int version); +/** + * builds the proxy header defined by the PROXY PROTOCOL + */ +size_t h2o_stringify_proxy_header(h2o_conn_t *conn, char *buf); +#define H2O_PROXY_HEADER_MAX_LENGTH \ + (sizeof("PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n") - 1) +/** + * extracts path to be pushed from `Link: rel=preload` header, duplicating the chunk (or returns {NULL,0} if none) + */ +h2o_iovec_vector_t h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, + h2o_iovec_t base_path, const h2o_url_scheme_t *input_scheme, + h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, + h2o_iovec_t *base_authority, h2o_iovec_t *filtered_value); +/** + * return a bitmap of compressible types, by parsing the `accept-encoding` header + */ +int h2o_get_compressible_types(const h2o_headers_t *headers); +#define H2O_COMPRESSIBLE_GZIP 1 +#define H2O_COMPRESSIBLE_BROTLI 2 +/** + * builds destination URL or path, by contatenating the prefix and path_info of the request + */ +h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t prefix_len, int use_path_normalized); + +extern uint64_t h2o_connection_id; + +/* request */ + +/** + * initializes the request structure + * @param req the request structure + * @param conn the underlying connection + * @param src if not NULL, the request structure would be a shallow copy of src + */ +void h2o_init_request(h2o_req_t *req, h2o_conn_t *conn, h2o_req_t *src); +/** + * releases resources allocated for handling a request + */ +void h2o_dispose_request(h2o_req_t *req); +/** + * called by the connection layer to start processing a request that is ready + */ +void h2o_process_request(h2o_req_t *req); +/** + * delegates the request to the next handler; called asynchronously by handlers that returned zero from `on_req` + */ +void h2o_delegate_request(h2o_req_t *req, h2o_handler_t *current_handler); +/** + * calls h2o_delegate_request using zero_timeout callback + */ +void h2o_delegate_request_deferred(h2o_req_t *req, h2o_handler_t *current_handler); +/** + * reprocesses a request once more (used for internal redirection) + */ +void h2o_reprocess_request(h2o_req_t *req, h2o_iovec_t method, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, + h2o_iovec_t path, h2o_req_overrides_t *overrides, int is_delegated); +/** + * calls h2o_reprocess_request using zero_timeout callback + */ +void h2o_reprocess_request_deferred(h2o_req_t *req, h2o_iovec_t method, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, + h2o_iovec_t path, h2o_req_overrides_t *overrides, int is_delegated); +/** + * called by handlers to set the generator + * @param req the request + * @param generator the generator + */ +void h2o_start_response(h2o_req_t *req, h2o_generator_t *generator); +/** + * called by filters to insert output-stream filters for modifying the response + * @param req the request + * @param size of the memory to be allocated for the ostream filter + * @param slot where the stream should be inserted + * @return pointer to the ostream filter + */ +h2o_ostream_t *h2o_add_ostream(h2o_req_t *req, size_t sz, h2o_ostream_t **slot); +/** + * binds configurations to the request + */ +void h2o_req_bind_conf(h2o_req_t *req, h2o_hostconf_t *hostconf, h2o_pathconf_t *pathconf); + +/** + * called by the generators to send output + * note: generators should free itself after sending the final chunk (i.e. calling the function with is_final set to true) + * @param req the request + * @param bufs an array of buffers + * @param bufcnt length of the buffers array + * @param state describes if the output is final, has an error, or is in progress + */ +void h2o_send(h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state); +/** + * called by the connection layer to pull the content from generator (if pull mode is being used) + */ +static h2o_send_state_t h2o_pull(h2o_req_t *req, h2o_ostream_pull_cb cb, h2o_iovec_t *buf); +/** + * creates an uninitialized prefilter and returns pointer to it + */ +h2o_req_prefilter_t *h2o_add_prefilter(h2o_req_t *req, size_t sz); +/** + * requests the next prefilter or filter (if any) to setup the ostream if necessary + */ +static void h2o_setup_next_prefilter(h2o_req_prefilter_t *self, h2o_req_t *req, h2o_ostream_t **slot); +/** + * requests the next filter (if any) to setup the ostream if necessary + */ +static void h2o_setup_next_ostream(h2o_req_t *req, h2o_ostream_t **slot); +/** + * called by the ostream filters to send output to the next ostream filter + * note: ostream filters should free itself after sending the final chunk (i.e. calling the function with is_final set to true) + * note: ostream filters must not set is_final flag to TRUE unless is_final flag of the do_send callback was set as such + * @param ostr current ostream filter + * @param req the request + * @param bufs an array of buffers + * @param bufcnt length of the buffers array + * @param state whether the output is in progress, final, or in error + */ +void h2o_ostream_send_next(h2o_ostream_t *ostream, h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state); +/** + * called by the connection layer to request additional data to the generator + */ +static void h2o_proceed_response(h2o_req_t *req); +/** + * if NULL, supplements h2o_req_t::mime_attr + */ +void h2o_req_fill_mime_attributes(h2o_req_t *req); +/** + * returns an environment variable + */ +static h2o_iovec_t *h2o_req_getenv(h2o_req_t *req, const char *name, size_t name_len, int allocate_if_not_found); +/** + * unsets an environment variable + */ +static void h2o_req_unsetenv(h2o_req_t *req, const char *name, size_t name_len); + +/* config */ + +h2o_envconf_t *h2o_config_create_envconf(h2o_envconf_t *src); +void h2o_config_setenv(h2o_envconf_t *envconf, const char *name, const char *value); +void h2o_config_unsetenv(h2o_envconf_t *envconf, const char *name); + +/** + * initializes pathconf + * @param path path to serve, or NULL if fallback or extension-level + * @param mimemap mimemap to use, or NULL if fallback or extension-level + */ +void h2o_config_init_pathconf(h2o_pathconf_t *pathconf, h2o_globalconf_t *globalconf, const char *path, h2o_mimemap_t *mimemap); +/** + * + */ +void h2o_config_dispose_pathconf(h2o_pathconf_t *pathconf); +/** + * initializes the global configuration + */ +void h2o_config_init(h2o_globalconf_t *config); +/** + * registers a host context + */ +h2o_hostconf_t *h2o_config_register_host(h2o_globalconf_t *config, h2o_iovec_t host, uint16_t port); +/** + * registers a path context + * @param hostconf host-level configuration that the path-level configuration belongs to + * @param path path + * @param flags unused and must be set to zero + * + * Handling of the path argument has changed in version 2.0 (of the standard server). + * + * Before 2.0, the function implicitely added a trailing `/` to the supplied path (if it did not end with a `/`), and when receiving + * a HTTP request for a matching path without the trailing `/`, libh2o sent a 301 response redirecting the client to a URI with a + * trailing `/`. + * + * Since 2.0, the function retains the exact path given as the argument, and the handlers of the pathconf is invoked if one of the + * following conditions are met: + * + * * request path is an exact match to the configuration path + * * configuration path does not end with a `/`, and the request path begins with the configuration path followed by a `/` + */ +h2o_pathconf_t *h2o_config_register_path(h2o_hostconf_t *hostconf, const char *path, int flags); +/** + * registers an extra status handler + */ +void h2o_config_register_status_handler(h2o_globalconf_t *config, h2o_status_handler_t); +void h2o_config_register_simple_status_handler(h2o_globalconf_t *config, h2o_iovec_t name, final_status_handler_cb status_handler); +/** + * disposes of the resources allocated for the global configuration + */ +void h2o_config_dispose(h2o_globalconf_t *config); +/** + * creates a handler associated to a given pathconf + */ +h2o_handler_t *h2o_create_handler(h2o_pathconf_t *conf, size_t sz); +/** + * creates a filter associated to a given pathconf + */ +h2o_filter_t *h2o_create_filter(h2o_pathconf_t *conf, size_t sz); +/** + * creates a logger associated to a given pathconf + */ +h2o_logger_t *h2o_create_logger(h2o_pathconf_t *conf, size_t sz); + +/* context */ + +/** + * initializes the context + */ +void h2o_context_init(h2o_context_t *context, h2o_loop_t *loop, h2o_globalconf_t *config); +/** + * disposes of the resources allocated for the context + */ +void h2o_context_dispose(h2o_context_t *context); +/** + * requests shutdown to the connections governed by the context + */ +void h2o_context_request_shutdown(h2o_context_t *context); +/** + * + */ +void h2o_context_init_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf); +/** + * + */ +void h2o_context_dispose_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf); +/** + * returns current timestamp + * @param ctx the context + * @param pool memory pool (used when ts != NULL) + * @param ts buffer to store the timestamp (optional) + * @return current time in UTC + */ +static struct timeval *h2o_get_timestamp(h2o_context_t *ctx, h2o_mem_pool_t *pool, h2o_timestamp_t *ts); +void h2o_context_update_timestamp_cache(h2o_context_t *ctx); +/** + * returns per-module context set + */ +static void *h2o_context_get_handler_context(h2o_context_t *ctx, h2o_handler_t *handler); +/** + * sets per-module context + */ +static void h2o_context_set_handler_context(h2o_context_t *ctx, h2o_handler_t *handler, void *handler_ctx); +/** + * returns per-module context set by the on_context_init callback + */ +static void *h2o_context_get_filter_context(h2o_context_t *ctx, h2o_filter_t *filter); +/** + * sets per-module filter context + */ +static void h2o_context_set_filter_context(h2o_context_t *ctx, h2o_filter_t *filter, void *filter_ctx); +/** + * returns per-module context set by the on_context_init callback + */ +static void *h2o_context_get_logger_context(h2o_context_t *ctx, h2o_logger_t *logger); +/* + * return the address associated with the key in the context storage + */ +static void **h2o_context_get_storage(h2o_context_t *ctx, size_t *key, void (*dispose_cb)(void *)); + +/* built-in generators */ + +enum { + /** + * enforces the http1 protocol handler to close the connection after sending the response + */ + H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION = 0x1, + /** + * if set, does not flush the registered response headers + */ + H2O_SEND_ERROR_KEEP_HEADERS = 0x2 +}; + +/** + * sends the given string as the response + */ +void h2o_send_inline(h2o_req_t *req, const char *body, size_t len); +/** + * sends the given information as an error response to the client + */ +void h2o_send_error_generic(h2o_req_t *req, int status, const char *reason, const char *body, int flags); +#define H2O_SEND_ERROR_XXX(status) \ + static inline void h2o_send_error_##status(h2o_req_t *req, const char *reason, const char *body, int flags) \ + { \ + req->conn->ctx->emitted_error_status[H2O_STATUS_ERROR_##status]++; \ + h2o_send_error_generic(req, status, reason, body, flags); \ + } + +H2O_SEND_ERROR_XXX(400) +H2O_SEND_ERROR_XXX(403) +H2O_SEND_ERROR_XXX(404) +H2O_SEND_ERROR_XXX(405) +H2O_SEND_ERROR_XXX(416) +H2O_SEND_ERROR_XXX(417) +H2O_SEND_ERROR_XXX(500) +H2O_SEND_ERROR_XXX(502) +H2O_SEND_ERROR_XXX(503) + +/** + * sends error response using zero timeout; can be called by output filters while processing the headers + */ +void h2o_send_error_deferred(h2o_req_t *req, int status, const char *reason, const char *body, int flags); +/** + * sends a redirect response + */ +void h2o_send_redirect(h2o_req_t *req, int status, const char *reason, const char *url, size_t url_len); +/** + * handles redirect internally + */ +void h2o_send_redirect_internal(h2o_req_t *req, h2o_iovec_t method, const char *url_str, size_t url_len, int preserve_overrides); +/** + * returns method to be used after redirection + */ +h2o_iovec_t h2o_get_redirect_method(h2o_iovec_t method, int status); +/** + * registers push path (if necessary) by parsing a Link header + * this returns a version of `value` that removes the links that had the `x-http2-push-only` attribute + */ +h2o_iovec_t h2o_push_path_in_link_header(h2o_req_t *req, const char *value, size_t value_len); +/** + * logs an error + */ +void h2o_req_log_error(h2o_req_t *req, const char *module, const char *fmt, ...) __attribute__((format(printf, 3, 4))); + +/* log */ + +enum { H2O_LOGCONF_ESCAPE_APACHE, H2O_LOGCONF_ESCAPE_JSON }; + +/** + * compiles a log configuration + */ +h2o_logconf_t *h2o_logconf_compile(const char *fmt, int escape, char *errbuf); +/** + * disposes of a log configuration + */ +void h2o_logconf_dispose(h2o_logconf_t *logconf); +/** + * logs a request + */ +char *h2o_log_request(h2o_logconf_t *logconf, h2o_req_t *req, size_t *len, char *buf); + +/* proxy */ + +/** + * processes a request (by sending the request upstream) + */ +void h2o__proxy_process_request(h2o_req_t *req); + +/* mime mapper */ + +/** + * initializes the mimemap (the returned chunk is refcounted) + */ +h2o_mimemap_t *h2o_mimemap_create(void); +/** + * clones a mimemap + */ +h2o_mimemap_t *h2o_mimemap_clone(h2o_mimemap_t *src); +/** + * + */ +void h2o_mimemap_on_context_init(h2o_mimemap_t *mimemap, h2o_context_t *ctx); +/** + * + */ +void h2o_mimemap_on_context_dispose(h2o_mimemap_t *mimemap, h2o_context_t *ctx); +/** + * returns if the map contains a dynamic type + */ +int h2o_mimemap_has_dynamic_type(h2o_mimemap_t *mimemap); +/** + * sets the default mime-type + */ +void h2o_mimemap_set_default_type(h2o_mimemap_t *mimemap, const char *mime, h2o_mime_attributes_t *attr); +/** + * adds a mime-type mapping + */ +void h2o_mimemap_define_mimetype(h2o_mimemap_t *mimemap, const char *ext, const char *mime, h2o_mime_attributes_t *attr); +/** + * adds a mime-type mapping + */ +h2o_mimemap_type_t *h2o_mimemap_define_dynamic(h2o_mimemap_t *mimemap, const char **exts, h2o_globalconf_t *globalconf); +/** + * removes a mime-type mapping + */ +void h2o_mimemap_remove_type(h2o_mimemap_t *mimemap, const char *ext); +/** + * clears all mime-type mapping + */ +void h2o_mimemap_clear_types(h2o_mimemap_t *mimemap); +/** + * sets the default mime-type + */ +h2o_mimemap_type_t *h2o_mimemap_get_default_type(h2o_mimemap_t *mimemap); +/** + * returns the mime-type corresponding to given extension + */ +h2o_mimemap_type_t *h2o_mimemap_get_type_by_extension(h2o_mimemap_t *mimemap, h2o_iovec_t ext); +/** + * returns the mime-type corresponding to given mimetype + */ +h2o_mimemap_type_t *h2o_mimemap_get_type_by_mimetype(h2o_mimemap_t *mimemap, h2o_iovec_t mime, int exact_match_only); +/** + * returns the default mime attributes given a mime type + */ +void h2o_mimemap_get_default_attributes(const char *mime, h2o_mime_attributes_t *attr); + +/* various handlers */ + +/* lib/access_log.c */ + +typedef struct st_h2o_access_log_filehandle_t h2o_access_log_filehandle_t; + +int h2o_access_log_open_log(const char *path); +h2o_access_log_filehandle_t *h2o_access_log_open_handle(const char *path, const char *fmt, int escape); +h2o_logger_t *h2o_access_log_register(h2o_pathconf_t *pathconf, h2o_access_log_filehandle_t *handle); +void h2o_access_log_register_configurator(h2o_globalconf_t *conf); + +/* lib/chunked.c */ + +/** + * registers the chunked encoding output filter (added by default) + */ +void h2o_chunked_register(h2o_pathconf_t *pathconf); + +/* lib/compress.c */ + +enum { H2O_COMPRESS_FLAG_PARTIAL, H2O_COMPRESS_FLAG_FLUSH, H2O_COMPRESS_FLAG_EOS }; + +/** + * compressor context + */ +typedef struct st_h2o_compress_context_t { + /** + * name used in content-encoding header + */ + h2o_iovec_t name; + /** + * compress or decompress callback + */ + void (*transform)(struct st_h2o_compress_context_t *self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, + h2o_iovec_t **outbufs, size_t *outbufcnt); +} h2o_compress_context_t; + +typedef struct st_h2o_compress_args_t { + size_t min_size; + struct { + int quality; /* -1 if disabled */ + } gzip; + struct { + int quality; /* -1 if disabled */ + } brotli; +} h2o_compress_args_t; + +/** + * registers the gzip/brotli encoding output filter (added by default, for now) + */ +void h2o_compress_register(h2o_pathconf_t *pathconf, h2o_compress_args_t *args); +/** + * instantiates the gzip compressor + */ +h2o_compress_context_t *h2o_compress_gzip_open(h2o_mem_pool_t *pool, int quality); +/** + * instantiates the gzip decompressor + */ +h2o_compress_context_t *h2o_compress_gunzip_open(h2o_mem_pool_t *pool); +/** + * instantiates the brotli compressor (only available if H2O_USE_BROTLI is set) + */ +h2o_compress_context_t *h2o_compress_brotli_open(h2o_mem_pool_t *pool, int quality, size_t estimated_cotent_length); +/** + * registers the configurator for the gzip/brotli output filter + */ +void h2o_compress_register_configurator(h2o_globalconf_t *conf); + +/* lib/handler/throttle_resp.c */ +/** + * registers the throttle response filter + */ +void h2o_throttle_resp_register(h2o_pathconf_t *pathconf); +/** + * configurator + */ +void h2o_throttle_resp_register_configurator(h2o_globalconf_t *conf); + +/* lib/errordoc.c */ + +typedef struct st_h2o_errordoc_t { + int status; + h2o_iovec_t url; /* can be relative */ +} h2o_errordoc_t; + +/** + * registers the errordocument output filter + */ +void h2o_errordoc_register(h2o_pathconf_t *pathconf, h2o_errordoc_t *errdocs, size_t cnt); +/** + * + */ +void h2o_errordoc_register_configurator(h2o_globalconf_t *conf); + +/* lib/expires.c */ + +enum { H2O_EXPIRES_MODE_ABSOLUTE, H2O_EXPIRES_MODE_MAX_AGE }; + +typedef struct st_h2o_expires_args_t { + int mode; + union { + const char *absolute; + uint64_t max_age; + } data; +} h2o_expires_args_t; + +/** + * registers a filter that adds an Expires (or Cache-Control) header + */ +void h2o_expires_register(h2o_pathconf_t *pathconf, h2o_expires_args_t *args); +/** + * + */ +void h2o_expires_register_configurator(h2o_globalconf_t *conf); + +/* lib/fastcgi.c */ + +typedef struct st_h2o_fastcgi_handler_t h2o_fastcgi_handler_t; + +#define H2O_DEFAULT_FASTCGI_IO_TIMEOUT 30000 + +typedef struct st_h2o_fastcgi_config_vars_t { + uint64_t io_timeout; + uint64_t keepalive_timeout; /* 0 to disable */ + h2o_iovec_t document_root; /* .base=NULL if not set */ + int send_delegated_uri; /* whether to send the rewritten HTTP_HOST & REQUEST_URI by delegation, or the original */ + struct { + void (*dispose)(h2o_fastcgi_handler_t *handler, void *data); + void *data; + } callbacks; +} h2o_fastcgi_config_vars_t; + +/** + * registers the fastcgi handler to the context + */ +h2o_fastcgi_handler_t *h2o_fastcgi_register_by_hostport(h2o_pathconf_t *pathconf, const char *host, uint16_t port, + h2o_fastcgi_config_vars_t *vars); +/** + * registers the fastcgi handler to the context + */ +h2o_fastcgi_handler_t *h2o_fastcgi_register_by_address(h2o_pathconf_t *pathconf, struct sockaddr *sa, socklen_t salen, + h2o_fastcgi_config_vars_t *vars); +/** + * registers the fastcgi handler to the context + */ +h2o_fastcgi_handler_t *h2o_fastcgi_register_by_spawnproc(h2o_pathconf_t *pathconf, char **argv, h2o_fastcgi_config_vars_t *vars); +/** + * registers the configurator + */ +void h2o_fastcgi_register_configurator(h2o_globalconf_t *conf); + +/* lib/file.c */ + +enum { + H2O_FILE_FLAG_NO_ETAG = 0x1, + H2O_FILE_FLAG_DIR_LISTING = 0x2, + H2O_FILE_FLAG_SEND_COMPRESSED = 0x4, + H2O_FILE_FLAG_GUNZIP = 0x8 +}; + +typedef struct st_h2o_file_handler_t h2o_file_handler_t; + +extern const char **h2o_file_default_index_files; + +/** + * sends given file as the response to the client + */ +int h2o_file_send(h2o_req_t *req, int status, const char *reason, const char *path, h2o_iovec_t mime_type, int flags); +/** + * registers a handler that serves a directory of statically-served files + * @param pathconf + * @param virtual_path + * @param real_path + * @param index_files optional NULL-terminated list of of filenames to be considered as the "directory-index" + * @param mimemap the mimemap (h2o_mimemap_create is called internally if the argument is NULL) + */ +h2o_file_handler_t *h2o_file_register(h2o_pathconf_t *pathconf, const char *real_path, const char **index_files, + h2o_mimemap_t *mimemap, int flags); +/** + * registers a handler that serves a specific file + * @param pathconf + * @param virtual_path + * @param real_path + * @param index_files optional NULL-terminated list of of filenames to be considered as the "directory-index" + * @param mimemap the mimemap (h2o_mimemap_create is called internally if the argument is NULL) + */ +h2o_handler_t *h2o_file_register_file(h2o_pathconf_t *pathconf, const char *real_path, h2o_mimemap_type_t *mime_type, int flags); +/** + * returns the associated mimemap + */ +h2o_mimemap_t *h2o_file_get_mimemap(h2o_file_handler_t *handler); +/** + * registers the configurator + */ +void h2o_file_register_configurator(h2o_globalconf_t *conf); + +/* lib/headers.c */ + +enum { + H2O_HEADERS_CMD_NULL, + H2O_HEADERS_CMD_ADD, /* adds a new header line */ + H2O_HEADERS_CMD_APPEND, /* adds a new header line or contenates to the existing header */ + H2O_HEADERS_CMD_MERGE, /* merges the value into a comma-listed values of the named header */ + H2O_HEADERS_CMD_SET, /* sets a header line, overwriting the existing one (if any) */ + H2O_HEADERS_CMD_SETIFEMPTY, /* sets a header line if empty */ + H2O_HEADERS_CMD_UNSET /* removes the named header(s) */ +}; + +struct st_h2o_headers_command_t { + int cmd; + h2o_iovec_t *name; /* maybe a token */ + h2o_iovec_t value; +}; + +/** + * registers a list of commands terminated by cmd==H2O_HEADERS_CMD_NULL + */ +void h2o_headers_register(h2o_pathconf_t *pathconf, h2o_headers_command_t *cmds); +/** + * returns whether if the given name can be registered to the filter + */ +int h2o_headers_is_prohibited_name(const h2o_token_t *token); +/** + * registers the configurator + */ +void h2o_headers_register_configurator(h2o_globalconf_t *conf); + +/* lib/proxy.c */ + +typedef struct st_h2o_proxy_config_vars_t { + uint64_t io_timeout; + unsigned preserve_host : 1; + unsigned use_proxy_protocol : 1; + uint64_t keepalive_timeout; /* in milliseconds; set to zero to disable keepalive */ + struct { + int enabled; + uint64_t timeout; + } websocket; + h2o_headers_command_t *headers_cmds; + SSL_CTX *ssl_ctx; /* optional */ +} h2o_proxy_config_vars_t; + +/** + * registers the reverse proxy handler to the context + */ +void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_url_t *upstream, h2o_proxy_config_vars_t *config); +/** + * registers the configurator + */ +void h2o_proxy_register_configurator(h2o_globalconf_t *conf); + +/* lib/redirect.c */ + +typedef struct st_h2o_redirect_handler_t h2o_redirect_handler_t; + +/** + * registers the redirect handler to the context + * @param pathconf + * @param internal whether if the redirect is internal or external + * @param status status code to be sent (e.g. 301, 303, 308, ...) + * @param prefix prefix of the destitation URL + */ +h2o_redirect_handler_t *h2o_redirect_register(h2o_pathconf_t *pathconf, int internal, int status, const char *prefix); +/** + * registers the configurator + */ +void h2o_redirect_register_configurator(h2o_globalconf_t *conf); + +/* lib/handler/reproxy.c */ + +typedef struct st_h2o_reproxy_handler_t h2o_reproxy_handler_t; + +/** + * registers the reproxy filter + */ +void h2o_reproxy_register(h2o_pathconf_t *pathconf); +/** + * registers the configurator + */ +void h2o_reproxy_register_configurator(h2o_globalconf_t *conf); + +/* lib/handler/status.c */ + +/** + * registers the status handler + */ +void h2o_status_register(h2o_pathconf_t *pathconf); +/** + * registers the duration handler + */ +void h2o_duration_stats_register(h2o_globalconf_t *conf); +/** + * registers the configurator + */ +void h2o_status_register_configurator(h2o_globalconf_t *conf); + +/* lib/handler/headers_util.c */ + +/** + * appends a headers command to the list + */ +void h2o_headers_append_command(h2o_headers_command_t **cmds, int cmd, h2o_iovec_t *name, h2o_iovec_t value); +/** + * rewrite headers by the command provided + */ +void h2o_rewrite_headers(h2o_mem_pool_t *pool, h2o_headers_t *headers, h2o_headers_command_t *cmd); + +/* lib/handler/http2_debug_state.c */ + +/** + * registers the http2 debug state handler + */ +void h2o_http2_debug_state_register(h2o_hostconf_t *hostconf, int hpack_enabled); +/** + * registers the configurator + */ +void h2o_http2_debug_state_register_configurator(h2o_globalconf_t *conf); + +/* inline defs */ + +#ifdef H2O_NO_64BIT_ATOMICS +extern pthread_mutex_t h2o_conn_id_mutex; +#endif + +inline h2o_conn_t *h2o_create_connection(size_t sz, h2o_context_t *ctx, h2o_hostconf_t **hosts, struct timeval connected_at, + const h2o_conn_callbacks_t *callbacks) +{ + h2o_conn_t *conn = (h2o_conn_t *)h2o_mem_alloc(sz); + + conn->ctx = ctx; + conn->hosts = hosts; + conn->connected_at = connected_at; +#ifdef H2O_NO_64BIT_ATOMICS + pthread_mutex_lock(&h2o_conn_id_mutex); + conn->id = ++h2o_connection_id; + pthread_mutex_unlock(&h2o_conn_id_mutex); +#else + conn->id = __sync_add_and_fetch(&h2o_connection_id, 1); +#endif + conn->callbacks = callbacks; + + return conn; +} + +inline void h2o_proceed_response(h2o_req_t *req) +{ + if (req->_generator != NULL) { + req->_generator->proceed(req->_generator, req); + } else { + req->_ostr_top->do_send(req->_ostr_top, req, NULL, 0, H2O_SEND_STATE_FINAL); + } +} + +inline h2o_iovec_t *h2o_req_getenv(h2o_req_t *req, const char *name, size_t name_len, int allocate_if_not_found) +{ + size_t i; + for (i = 0; i != req->env.size; i += 2) + if (h2o_memis(req->env.entries[i].base, req->env.entries[i].len, name, name_len)) + return req->env.entries + i + 1; + if (!allocate_if_not_found) + return NULL; + h2o_vector_reserve(&req->pool, &req->env, req->env.size + 2); + req->env.entries[req->env.size++] = h2o_iovec_init(name, name_len); + req->env.entries[req->env.size++] = h2o_iovec_init(NULL, 0); + return req->env.entries + req->env.size - 1; +} + +inline void h2o_req_unsetenv(h2o_req_t *req, const char *name, size_t name_len) +{ + size_t i; + for (i = 0; i != req->env.size; i += 2) + if (h2o_memis(req->env.entries[i].base, req->env.entries[i].len, name, name_len)) + goto Found; + /* not found */ + return; +Found: + memmove(req->env.entries + i, req->env.entries + i + 2, req->env.size - i - 2); + req->env.size -= 2; +} + +inline h2o_send_state_t h2o_pull(h2o_req_t *req, h2o_ostream_pull_cb cb, h2o_iovec_t *buf) +{ + h2o_send_state_t send_state; + assert(req->_generator != NULL); + send_state = cb(req->_generator, req, buf); + if (!h2o_send_state_is_in_progress(send_state)) + req->_generator = NULL; + return send_state; +} + +inline void h2o_setup_next_ostream(h2o_req_t *req, h2o_ostream_t **slot) +{ + h2o_filter_t *next; + + if (req->_next_filter_index < req->pathconf->filters.size) { + next = req->pathconf->filters.entries[req->_next_filter_index++]; + next->on_setup_ostream(next, req, slot); + } +} + +inline void h2o_setup_next_prefilter(h2o_req_prefilter_t *self, h2o_req_t *req, h2o_ostream_t **slot) +{ + h2o_req_prefilter_t *next = self->next; + + if (next != NULL) + next->on_setup_ostream(next, req, slot); + else + h2o_setup_next_ostream(req, slot); +} + +inline struct timeval *h2o_get_timestamp(h2o_context_t *ctx, h2o_mem_pool_t *pool, h2o_timestamp_t *ts) +{ + uint64_t now = h2o_now(ctx->loop); + + if (ctx->_timestamp_cache.uv_now_at != now) { + h2o_context_update_timestamp_cache(ctx); + } + + if (ts != NULL) { + ts->at = ctx->_timestamp_cache.tv_at; + h2o_mem_link_shared(pool, ctx->_timestamp_cache.value); + ts->str = ctx->_timestamp_cache.value; + } + + return &ctx->_timestamp_cache.tv_at; +} + +inline void *h2o_context_get_handler_context(h2o_context_t *ctx, h2o_handler_t *handler) +{ + return ctx->_module_configs[handler->_config_slot]; +} + +inline void h2o_context_set_handler_context(h2o_context_t *ctx, h2o_handler_t *handler, void *handler_ctx) +{ + ctx->_module_configs[handler->_config_slot] = handler_ctx; +} + +inline void *h2o_context_get_filter_context(h2o_context_t *ctx, h2o_filter_t *filter) +{ + return ctx->_module_configs[filter->_config_slot]; +} + +inline void h2o_context_set_filter_context(h2o_context_t *ctx, h2o_filter_t *filter, void *filter_ctx) +{ + ctx->_module_configs[filter->_config_slot] = filter_ctx; +} + +inline void *h2o_context_get_logger_context(h2o_context_t *ctx, h2o_logger_t *logger) +{ + return ctx->_module_configs[logger->_config_slot]; +} + +inline void **h2o_context_get_storage(h2o_context_t *ctx, size_t *key, void (*dispose_cb)(void *)) +{ + /* SIZE_MAX might not be available in case the file is included from a C++ source file */ + size_t size_max = (size_t)-1; + if (*key == size_max) + *key = ctx->storage.size; + if (ctx->storage.size <= *key) { + h2o_vector_reserve(NULL, &ctx->storage, *key + 1); + memset(ctx->storage.entries + ctx->storage.size, 0, (*key + 1 - ctx->storage.size) * sizeof(ctx->storage.entries[0])); + ctx->storage.size = *key + 1; + } + + ctx->storage.entries[*key].dispose = dispose_cb; + return &ctx->storage.entries[*key].data; +} + +static inline void h2o_context_set_logger_context(h2o_context_t *ctx, h2o_logger_t *logger, void *logger_ctx) +{ + ctx->_module_configs[logger->_config_slot] = logger_ctx; +} + +static inline void h2o_doublebuffer_init(h2o_doublebuffer_t *db, h2o_buffer_prototype_t *prototype) +{ + h2o_buffer_init(&db->buf, prototype); + db->bytes_inflight = 0; +} + +static inline void h2o_doublebuffer_dispose(h2o_doublebuffer_t *db) +{ + h2o_buffer_dispose(&db->buf); +} + +static inline h2o_iovec_t h2o_doublebuffer_prepare(h2o_doublebuffer_t *db, h2o_buffer_t **receiving, size_t max_bytes) +{ + assert(db->bytes_inflight == 0); + + if (db->buf->size == 0) { + if ((*receiving)->size == 0) + return h2o_iovec_init(NULL, 0); + /* swap buffers */ + h2o_buffer_t *t = db->buf; + db->buf = *receiving; + *receiving = t; + } + if ((db->bytes_inflight = db->buf->size) > max_bytes) + db->bytes_inflight = max_bytes; + return h2o_iovec_init(db->buf->bytes, db->bytes_inflight); +} + +static inline void h2o_doublebuffer_consume(h2o_doublebuffer_t *db) +{ + assert(db->bytes_inflight != 0); + h2o_buffer_consume(&db->buf, db->bytes_inflight); + db->bytes_inflight = 0; +} + +#define COMPUTE_DURATION(name, from, until) \ + static inline int h2o_time_compute_##name(struct st_h2o_req_t *req, int64_t *delta_usec) \ + { \ + if (h2o_timeval_is_null((from)) || h2o_timeval_is_null((until))) { \ + return 0; \ + } \ + *delta_usec = h2o_timeval_subtract((from), (until)); \ + return 1; \ + } + +COMPUTE_DURATION(connect_time, &req->conn->connected_at, &req->timestamps.request_begin_at); +COMPUTE_DURATION(header_time, &req->timestamps.request_begin_at, h2o_timeval_is_null(&req->timestamps.request_body_begin_at) + ? &req->processed_at.at + : &req->timestamps.request_body_begin_at); +COMPUTE_DURATION(body_time, h2o_timeval_is_null(&req->timestamps.request_body_begin_at) ? &req->processed_at.at + : &req->timestamps.request_body_begin_at, + &req->processed_at.at); +COMPUTE_DURATION(request_total_time, &req->timestamps.request_begin_at, &req->processed_at.at); +COMPUTE_DURATION(process_time, &req->processed_at.at, &req->timestamps.response_start_at); +COMPUTE_DURATION(response_time, &req->timestamps.response_start_at, &req->timestamps.response_end_at); +COMPUTE_DURATION(duration, &req->timestamps.request_begin_at, &req->timestamps.response_end_at); + +#undef COMPUTE_DURATION + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/cache.h b/web/server/h2o/libh2o/include/h2o/cache.h new file mode 100644 index 000000000..4eae70c92 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/cache.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__cache_h +#define h2o__cache_h + +#include <stdint.h> +#include "h2o/linklist.h" +#include "h2o/memory.h" + +typedef struct st_h2o_cache_t h2o_cache_t; + +typedef uint32_t /* eq. khint_t */ h2o_cache_hashcode_t; + +typedef struct st_h2o_cache_key_t { + h2o_iovec_t vec; + h2o_cache_hashcode_t hash; +} h2o_cache_key_t; + +typedef struct st_h2o_cache_ref_t { + h2o_iovec_t key; + h2o_cache_hashcode_t keyhash; + uint64_t at; + h2o_iovec_t value; + int _requested_early_update; + h2o_linklist_t _lru_link; + h2o_linklist_t _age_link; + size_t _refcnt; +} h2o_cache_ref_t; + +/** + * calculates the hash code of a key + */ +h2o_cache_hashcode_t h2o_cache_calchash(const char *s, size_t len); + +enum { + /** + * if set, the internals of the cache is protected by a mutex so that it can be accessed concurrently + */ + H2O_CACHE_FLAG_MULTITHREADED = 0x1, + /** + * if set, the cache triggers an early update + */ + H2O_CACHE_FLAG_EARLY_UPDATE = 0x2 +}; + +/** + * creates a new cache + */ +h2o_cache_t *h2o_cache_create(int flags, size_t capacity, uint64_t duration, void (*destroy_cb)(h2o_iovec_t value)); +/** + * destroys a cache + */ +void h2o_cache_destroy(h2o_cache_t *cache); +/** + * clears a cache + */ +void h2o_cache_clear(h2o_cache_t *cache); +/** + * returns a value named by key from the cache if found, or else returns NULL + * @param cache + * @param now + * @param key + * @param keyhash callers may optionally pass in the precalculated hash value (or should be set to 0) + */ +h2o_cache_ref_t *h2o_cache_fetch(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash); +/** + * releases the reference returned by h2o_cache_fetch + */ +void h2o_cache_release(h2o_cache_t *cache, h2o_cache_ref_t *ref); +/** + * sets the value of the cache + * @param cache + * @param now + * @param key + * @param keyhash callers may optionally pass in the precalculated hash value (or should be set to 0) + * @param value (when no longer needed, destroy_cb will be called) + * @return if the specified value already existed + */ +int h2o_cache_set(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash, h2o_iovec_t value); +/** + * deletes a named value from the cache + * @param cache + * @param now + * @param key + * @param keyhash callers may optionally pass in the precalculated hash value (or should be set to 0) + */ +void h2o_cache_delete(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash); + +/** + * getter functions + */ +size_t h2o_cache_get_capacity(h2o_cache_t *cache); +uint64_t h2o_cache_get_duration(h2o_cache_t *cache); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/cache_digests.h b/web/server/h2o/libh2o/include/h2o/cache_digests.h new file mode 100644 index 000000000..8680b38b3 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/cache_digests.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__cache_digests_h +#define h2o__cache_digests_h + +#include <stddef.h> +#include <stdlib.h> +#include "h2o/memory.h" + +typedef enum en_h2o_cache_digests_state_t { + H2O_CACHE_DIGESTS_STATE_UNKNOWN, + H2O_CACHE_DIGESTS_STATE_NOT_CACHED, + H2O_CACHE_DIGESTS_STATE_FRESH, + H2O_CACHE_DIGESTS_STATE_STALE +} h2o_cache_digests_state_t; + +typedef struct st_h2o_cache_digests_frame_t h2o_cache_digests_frame_t; + +typedef H2O_VECTOR(h2o_cache_digests_frame_t) h2o_cache_digests_frame_vector_t; + +typedef struct st_h2o_cache_digests_t { + struct { + h2o_cache_digests_frame_vector_t url_only; + h2o_cache_digests_frame_vector_t url_and_etag; + int complete; + } fresh; +} h2o_cache_digests_t; + +/** + * destroys the object + */ +void h2o_cache_digests_destroy(h2o_cache_digests_t *digests); +/** + * loads a header (*digests may be NULL) + */ +void h2o_cache_digests_load_header(h2o_cache_digests_t **digests, const char *value, size_t len); +/** + * lookup for a match with URL only + */ +h2o_cache_digests_state_t h2o_cache_digests_lookup_by_url(h2o_cache_digests_t *digests, const char *url, size_t url_len); +/** + * lookup for a match with URL and etag + */ +h2o_cache_digests_state_t h2o_cache_digests_lookup_by_url_and_etag(h2o_cache_digests_t *digests, const char *url, size_t url_len, + const char *etag, size_t etag_len); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/configurator.h b/web/server/h2o/libh2o/include/h2o/configurator.h new file mode 100644 index 000000000..d1a2e2515 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/configurator.h @@ -0,0 +1,181 @@ +/* + * 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. + */ +#ifndef h2o__configurator_h +#define h2o__configurator_h + +#include "yoml.h" + +enum { + H2O_CONFIGURATOR_FLAG_GLOBAL = 0x1, + H2O_CONFIGURATOR_FLAG_HOST = 0x2, + H2O_CONFIGURATOR_FLAG_PATH = 0x4, + H2O_CONFIGURATOR_FLAG_EXTENSION = 0x8, + H2O_CONFIGURATOR_FLAG_ALL_LEVELS = + H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXTENSION, + H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR = 0x100, + H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE = 0x200, + H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING = 0x400, + H2O_CONFIGURATOR_FLAG_DEFERRED = 0x1000, + H2O_CONFIGURATOR_FLAG_SEMI_DEFERRED = 0x2000 /* used by file.custom-handler (invoked before hosts,paths,file-dir, etc.) */ +}; + +#define H2O_CONFIGURATOR_NUM_LEVELS 4 + +typedef struct st_h2o_configurator_context_t { + /** + * pointer to globalconf + */ + h2o_globalconf_t *globalconf; + /** + * pointer to hostconf, or NULL if the context is above host level + */ + h2o_hostconf_t *hostconf; + /** + * pointer to pathconf (either at path level or custom handler level), or NULL + */ + h2o_pathconf_t *pathconf; + /** + * pointer to mimemap + */ + h2o_mimemap_t **mimemap; + /** + * pointer to env + */ + h2o_envconf_t *env; + /** + * if is a dry run + */ + int dry_run; + /** + * parent context (or NULL if the context is at global level) + */ + struct st_h2o_configurator_context_t *parent; +} h2o_configurator_context_t; + +typedef int (*h2o_configurator_dispose_cb)(h2o_configurator_t *configurator); +typedef int (*h2o_configurator_enter_cb)(h2o_configurator_t *configurator, h2o_configurator_context_t *ctx, yoml_t *node); +typedef int (*h2o_configurator_exit_cb)(h2o_configurator_t *configurator, h2o_configurator_context_t *ctx, yoml_t *node); +typedef int (*h2o_configurator_command_cb)(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node); +typedef h2o_headers_command_t **(*h2o_configurator_get_headers_commands_cb)(h2o_configurator_t *conf); + +struct st_h2o_configurator_command_t { + /** + * configurator to which the command belongs + */ + h2o_configurator_t *configurator; + /** + * name of the command handled by the configurator + */ + const char *name; + /** + * flags + */ + int flags; + /** + * mandatory callback called to handle the command + */ + h2o_configurator_command_cb cb; +}; + +/** + * basic structure of a configurator (handles a configuration command) + */ +struct st_h2o_configurator_t { + h2o_linklist_t _link; + /** + * optional callback called when the global config is being disposed + */ + h2o_configurator_dispose_cb dispose; + /** + * optional callback called before the configuration commands are handled + */ + h2o_configurator_enter_cb enter; + /** + * optional callback called after all the configuration commands are handled + */ + h2o_configurator_exit_cb exit; + /** + * list of commands + */ + H2O_VECTOR(h2o_configurator_command_t) commands; +}; + +/** + * registers a configurator + */ +h2o_configurator_t *h2o_configurator_create(h2o_globalconf_t *conf, size_t sz); +/** + * + */ +void h2o_configurator_define_command(h2o_configurator_t *configurator, const char *name, int flags, h2o_configurator_command_cb cb); +/** + * returns a configurator of given command name + * @return configurator for given name or NULL if not found + */ +h2o_configurator_command_t *h2o_configurator_get_command(h2o_globalconf_t *conf, const char *name); +/** + * applies the configuration to the context + * @return 0 if successful, -1 if not + */ +int h2o_configurator_apply(h2o_globalconf_t *config, yoml_t *node, int dry_run); +/** + * + */ +int h2o_configurator_apply_commands(h2o_configurator_context_t *ctx, yoml_t *node, int flags_mask, const char **ignore_commands); +/** + * emits configuration error + */ +void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, const char *reason, ...) + __attribute__((format(printf, 3, 4))); +/** + * interprets the configuration value using sscanf, or prints an error upon failure + * @param configurator configurator + * @param node configuration value + * @param fmt scanf-style format string + * @return 0 if successful, -1 if not + */ +int h2o_configurator_scanf(h2o_configurator_command_t *cmd, yoml_t *node, const char *fmt, ...) + __attribute__((format(scanf, 3, 4))); +/** + * interprets the configuration value and returns the index of the matched string within the candidate strings, or prints an error + * upon failure + * @param configurator configurator + * @param node configuration value + * @param candidates a comma-separated list of strings (should not contain whitespaces) + * @return index of the matched string within the given list, or -1 if none of them matched + */ +ssize_t h2o_configurator_get_one_of(h2o_configurator_command_t *cmd, yoml_t *node, const char *candidates); +/** + * returns the absolute paths of supplementary commands + */ +char *h2o_configurator_get_cmd_path(const char *cmd); + +/** + * lib/handler/configurator/headers_util.c + */ +void h2o_configurator_define_headers_commands(h2o_globalconf_t *global_conf, h2o_configurator_t *conf, const char *prefix, + h2o_configurator_get_headers_commands_cb get_commands); + +void h2o_configurator__init_core(h2o_globalconf_t *conf); +void h2o_configurator__dispose_configurators(h2o_globalconf_t *conf); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/file.h b/web/server/h2o/libh2o/include/h2o/file.h new file mode 100644 index 000000000..76c5ed657 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/file.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__file_h +#define h2o__file_h + +#include "h2o/memory.h" + +h2o_iovec_t h2o_file_read(const char *fn); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/filecache.h b/web/server/h2o/libh2o/include/h2o/filecache.h new file mode 100644 index 000000000..a000c4c6d --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/filecache.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__filecache_h +#define h2o__filecache_h + +#include <stddef.h> +#include <sys/stat.h> +#include <time.h> +#include "h2o/linklist.h" +#include "h2o/memory.h" +#include "h2o/time_.h" + +#define H2O_FILECACHE_ETAG_MAXLEN (sizeof("\"deadbeef-deadbeefdeadbeef\"") - 1) + +typedef struct st_h2o_filecache_ref_t { + int fd; + size_t _refcnt; + h2o_linklist_t _lru; + union { + struct { + /* used if fd != -1 */ + struct stat st; + struct { + struct tm gm; + char str[H2O_TIMESTR_RFC1123_LEN + 1]; + } _last_modified; + struct { + char buf[H2O_FILECACHE_ETAG_MAXLEN + 1]; + size_t len; + } _etag; + }; + /* used if fd != -1 */ + int open_err; + }; + char _path[1]; +} h2o_filecache_ref_t; + +typedef struct st_h2o_filecache_t h2o_filecache_t; + +h2o_filecache_t *h2o_filecache_create(size_t capacity); +void h2o_filecache_destroy(h2o_filecache_t *cache); +void h2o_filecache_clear(h2o_filecache_t *cache); + +h2o_filecache_ref_t *h2o_filecache_open_file(h2o_filecache_t *cache, const char *path, int oflag); +void h2o_filecache_close_file(h2o_filecache_ref_t *ref); +struct tm *h2o_filecache_get_last_modified(h2o_filecache_ref_t *ref, char *outbuf); +size_t h2o_filecache_get_etag(h2o_filecache_ref_t *ref, char *outbuf); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/hostinfo.h b/web/server/h2o/libh2o/include/h2o/hostinfo.h new file mode 100644 index 000000000..14ac30c6c --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/hostinfo.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__hostinfo_h +#define h2o__hostinfo_h + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include "h2o/multithread.h" + +typedef struct st_h2o_hostinfo_getaddr_req_t h2o_hostinfo_getaddr_req_t; + +typedef void (*h2o_hostinfo_getaddr_cb)(h2o_hostinfo_getaddr_req_t *req, const char *errstr, struct addrinfo *res, void *cbdata); + +extern size_t h2o_hostinfo_max_threads; + +/** + * dispatches a (possibly) asynchronous hostname lookup + */ +h2o_hostinfo_getaddr_req_t *h2o_hostinfo_getaddr(h2o_multithread_receiver_t *receiver, h2o_iovec_t name, h2o_iovec_t serv, + int family, int socktype, int protocol, int flags, h2o_hostinfo_getaddr_cb cb, + void *cbdata); +/** + * + */ +void h2o__hostinfo_getaddr_dispatch(h2o_hostinfo_getaddr_req_t *req); +/** + * cancels the request + */ +void h2o_hostinfo_getaddr_cancel(h2o_hostinfo_getaddr_req_t *req); + +/** + * function that receives and dispatches the responses + */ +void h2o_hostinfo_getaddr_receiver(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages); + +/** + * select one entry at random from the response + */ +static struct addrinfo *h2o_hostinfo_select_one(struct addrinfo *res); + +/** + * equiv. to inet_pton(AF_INET4) + */ +int h2o_hostinfo_aton(h2o_iovec_t host, struct in_addr *addr); + +/* inline defs */ + +inline struct addrinfo *h2o_hostinfo_select_one(struct addrinfo *res) +{ + if (res->ai_next == NULL) + return res; + + /* count the number of candidates */ + size_t i = 0; + struct addrinfo *ai = res; + do { + ++i; + } while ((ai = ai->ai_next) != NULL); + + /* choose one, distributed by rand() :-p */ + i = rand() % i; + for (ai = res; i != 0; ai = ai->ai_next, --i) + ; + return ai; +} + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/http1.h b/web/server/h2o/libh2o/include/h2o/http1.h new file mode 100644 index 000000000..cb9e9395d --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/http1.h @@ -0,0 +1,40 @@ +/* + * 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. + */ +#ifndef h2o__http1_h +#define h2o__http1_h + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*h2o_http1_upgrade_cb)(void *user_data, h2o_socket_t *sock, size_t reqsize); + +extern const h2o_protocol_callbacks_t H2O_HTTP1_CALLBACKS; + +void h2o_http1_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at); +void h2o_http1_upgrade(h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_http1_upgrade_cb on_complete, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/http1client.h b/web/server/h2o/libh2o/include/h2o/http1client.h new file mode 100644 index 000000000..243994074 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/http1client.h @@ -0,0 +1,82 @@ +/* + * 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. + */ +#ifndef h2o__http1client_h +#define h2o__http1client_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "h2o/memory.h" +#include "h2o/socket.h" +#include "h2o/socketpool.h" +#include "h2o/timeout.h" +#include "h2o/cache.h" + +typedef struct st_h2o_http1client_t h2o_http1client_t; + +struct st_h2o_header_t; +typedef int (*h2o_http1client_body_cb)(h2o_http1client_t *client, const char *errstr); +typedef h2o_http1client_body_cb (*h2o_http1client_head_cb)(h2o_http1client_t *client, const char *errstr, int minor_version, + int status, h2o_iovec_t msg, struct st_h2o_header_t *headers, + size_t num_headers, int rlen); +typedef h2o_http1client_head_cb (*h2o_http1client_connect_cb)(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, + size_t *reqbufcnt, int *method_is_head); +typedef int (*h2o_http1client_informational_cb)(h2o_http1client_t *client, int minor_version, int status, h2o_iovec_t msg, + struct st_h2o_header_t *headers, size_t num_headers); + +typedef struct st_h2o_http1client_ctx_t { + h2o_loop_t *loop; + h2o_multithread_receiver_t *getaddr_receiver; + h2o_timeout_t *io_timeout; + h2o_timeout_t *websocket_timeout; /* NULL if upgrade to websocket is not allowed */ + SSL_CTX *ssl_ctx; +} h2o_http1client_ctx_t; + +struct st_h2o_http1client_t { + h2o_http1client_ctx_t *ctx; + struct { + h2o_socketpool_t *pool; + h2o_socketpool_connect_request_t *connect_req; + } sockpool; + struct { + char *server_name; /* non-null if ssl is to be used */ + } ssl; + h2o_socket_t *sock; + void *data; + h2o_http1client_informational_cb informational_cb; +}; + +extern const char *const h2o_http1client_error_is_eos; + +void h2o_http1client_connect(h2o_http1client_t **client, void *data, h2o_http1client_ctx_t *ctx, h2o_iovec_t host, uint16_t port, + int is_ssl, h2o_http1client_connect_cb cb); +void h2o_http1client_connect_with_pool(h2o_http1client_t **client, void *data, h2o_http1client_ctx_t *ctx, + h2o_socketpool_t *sockpool, h2o_http1client_connect_cb cb); +void h2o_http1client_cancel(h2o_http1client_t *client); +h2o_socket_t *h2o_http1client_steal_socket(h2o_http1client_t *client); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/http2.h b/web/server/h2o/libh2o/include/h2o/http2.h new file mode 100644 index 000000000..567e77de2 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/http2.h @@ -0,0 +1,67 @@ +/* + * 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. + */ +#ifndef h2o__http2_h +#define h2o__http2_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *h2o_http2_npn_protocols; +extern const h2o_iovec_t *h2o_http2_alpn_protocols; + +extern const h2o_protocol_callbacks_t H2O_HTTP2_CALLBACKS; + +#define H2O_HTTP2_SETTINGS_HEADER_TABLE_SIZE 1 +#define H2O_HTTP2_SETTINGS_ENABLE_PUSH 2 +#define H2O_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS 3 +#define H2O_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE 4 +#define H2O_HTTP2_SETTINGS_MAX_FRAME_SIZE 5 +#define H2O_HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE 6 + +typedef struct st_h2o_http2_settings_t { + uint32_t header_table_size; + uint32_t enable_push; + uint32_t max_concurrent_streams; + uint32_t initial_window_size; + uint32_t max_frame_size; +} h2o_http2_settings_t; + +extern const h2o_http2_settings_t H2O_HTTP2_SETTINGS_DEFAULT; +extern const h2o_http2_settings_t H2O_HTTP2_SETTINGS_HOST; + +typedef struct st_h2o_http2_priority_t { + int exclusive; + uint32_t dependency; + uint16_t weight; +} h2o_http2_priority_t; + +extern const h2o_http2_priority_t h2o_http2_default_priority; + +void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at); +int h2o_http2_handle_upgrade(h2o_req_t *req, struct timeval connected_at); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/http2_casper.h b/web/server/h2o/libh2o/include/h2o/http2_casper.h new file mode 100644 index 000000000..dd6ea2436 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/http2_casper.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__http2__casper_h +#define h2o__http2__casper_h + +#include <stddef.h> +#include <stdlib.h> +#include "h2o/memory.h" + +typedef struct st_h2o_http2_casper_t h2o_http2_casper_t; + +/** + * creates an object with provided parameters + */ +h2o_http2_casper_t *h2o_http2_casper_create(unsigned capacity_bits, unsigned remainder_bits); +/** + * destroys the object and resources associated to it + */ +void h2o_http2_casper_destroy(h2o_http2_casper_t *casper); +/** + * returns the number of keys stored + */ +size_t h2o_http2_casper_num_entries(h2o_http2_casper_t *casper); +/** + * checks if a key is (was) marked as cached at the moment the fuction is invoked + */ +int h2o_http2_casper_lookup(h2o_http2_casper_t *casper, const char *path, size_t path_len, int set); +/** + * consumes the `Cookie` headers in requests and updates the structure + */ +void h2o_http2_casper_consume_cookie(h2o_http2_casper_t *casper, const char *cookie, size_t cookie_len); +/** + * returns the value of the `Set-Cookie` header that should be sent to the client + */ +h2o_iovec_t h2o_http2_casper_get_cookie(h2o_http2_casper_t *casper); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/http2_internal.h b/web/server/h2o/libh2o/include/h2o/http2_internal.h new file mode 100644 index 000000000..5cfc4d820 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/http2_internal.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2014,2015 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. + */ +#ifndef h2o__http2__internal_h +#define h2o__http2__internal_h + +#include <assert.h> +#include <stdint.h> +#include "khash.h" +#include "h2o/cache.h" +#include "h2o/http2_casper.h" +#include "h2o/cache_digests.h" +#include "h2o/http2_scheduler.h" + +typedef struct st_h2o_http2_conn_t h2o_http2_conn_t; +typedef struct st_h2o_http2_stream_t h2o_http2_stream_t; + +#define H2O_HTTP2_DEFAULT_OUTBUF_SIZE 81920 /* the target size of each write call; connection flow control window + alpha */ +#define H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE 524288 /* 512KB; stops reading if size exceeds this value */ + +/* hpack */ + +#define H2O_HTTP2_ENCODE_INT_MAX_LENGTH 5 + +typedef struct st_h2o_hpack_header_table_t { + /* ring buffer */ + struct st_h2o_hpack_header_table_entry_t *entries; + size_t num_entries, entry_capacity, entry_start_index; + /* size and capacities are 32+name_len+value_len (as defined by hpack spec.) */ + size_t hpack_size; + size_t hpack_capacity; /* the value set by SETTINGS_HEADER_TABLE_SIZE _and_ dynamic table size update */ + size_t hpack_max_capacity; /* the value set by SETTINGS_HEADER_TABLE_SIZE */ +} h2o_hpack_header_table_t; + +typedef struct st_h2o_hpack_header_table_entry_t { + h2o_iovec_t *name; + h2o_iovec_t *value; + const char *err_desc; /* the recorded soft error description */ +} h2o_hpack_header_table_entry_t; + +#define H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS 1 +#define H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS 2 +#define H2O_HPACK_PARSE_HEADERS_PATH_EXISTS 4 +#define H2O_HPACK_PARSE_HEADERS_AUTHORITY_EXISTS 8 + +void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table); +int h2o_hpack_parse_headers(h2o_req_t *req, h2o_hpack_header_table_t *header_table, const uint8_t *src, size_t len, + int *pseudo_header_exists_map, size_t *content_length, h2o_cache_digests_t **digests, + const char **err_desc); +size_t h2o_hpack_encode_string(uint8_t *dst, const char *s, size_t len); +void h2o_hpack_flatten_request(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t stream_id, + size_t max_frame_size, h2o_req_t *req, uint32_t parent_stream_id); +void h2o_hpack_flatten_response(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t stream_id, + size_t max_frame_size, h2o_res_t *res, h2o_timestamp_t *ts, const h2o_iovec_t *server_name, + size_t content_length); +static h2o_hpack_header_table_entry_t *h2o_hpack_header_table_get(h2o_hpack_header_table_t *table, size_t index); + +/* frames */ + +#define H2O_HTTP2_FRAME_HEADER_SIZE 9 + +#define H2O_HTTP2_FRAME_TYPE_DATA 0 +#define H2O_HTTP2_FRAME_TYPE_HEADERS 1 +#define H2O_HTTP2_FRAME_TYPE_PRIORITY 2 +#define H2O_HTTP2_FRAME_TYPE_RST_STREAM 3 +#define H2O_HTTP2_FRAME_TYPE_SETTINGS 4 +#define H2O_HTTP2_FRAME_TYPE_PUSH_PROMISE 5 +#define H2O_HTTP2_FRAME_TYPE_PING 6 +#define H2O_HTTP2_FRAME_TYPE_GOAWAY 7 +#define H2O_HTTP2_FRAME_TYPE_WINDOW_UPDATE 8 +#define H2O_HTTP2_FRAME_TYPE_CONTINUATION 9 + +#define H2O_HTTP2_FRAME_FLAG_END_STREAM 0x1 +#define H2O_HTTP2_FRAME_FLAG_ACK 0x1 +#define H2O_HTTP2_FRAME_FLAG_END_HEADERS 0x4 +#define H2O_HTTP2_FRAME_FLAG_PADDED 0x8 +#define H2O_HTTP2_FRAME_FLAG_PRIORITY 0x20 + +typedef struct st_h2o_http2_frame_t { + uint32_t length; + uint8_t type; + uint8_t flags; + uint32_t stream_id; + const uint8_t *payload; +} h2o_http2_frame_t; + +typedef struct st_h2o_http2_data_payload_t { + const uint8_t *data; + size_t length; +} h2o_http2_data_payload_t; + +typedef struct st_h2o_http2_headers_payload_t { + h2o_http2_priority_t priority; + const uint8_t *headers; + size_t headers_len; +} h2o_http2_headers_payload_t; + +typedef struct st_h2o_http2_rst_stream_payload_t { + uint32_t error_code; +} h2o_http2_rst_stream_payload_t; + +typedef struct st_h2o_http2_ping_payload_t { + uint8_t data[8]; +} h2o_http2_ping_payload_t; + +typedef struct st_h2o_http2_goaway_payload_t { + uint32_t last_stream_id; + uint32_t error_code; + h2o_iovec_t debug_data; +} h2o_http2_goaway_payload_t; + +typedef struct st_h2o_http2_window_update_payload_t { + uint32_t window_size_increment; +} h2o_http2_window_update_payload_t; + +typedef struct st_h2o_http2_window_t { + ssize_t _avail; +} h2o_http2_window_t; + +typedef enum enum_h2o_http2_stream_state_t { + H2O_HTTP2_STREAM_STATE_IDLE, + H2O_HTTP2_STREAM_STATE_RECV_HEADERS, + H2O_HTTP2_STREAM_STATE_RECV_BODY, + H2O_HTTP2_STREAM_STATE_REQ_PENDING, + H2O_HTTP2_STREAM_STATE_SEND_HEADERS, + H2O_HTTP2_STREAM_STATE_SEND_BODY, + H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL, + H2O_HTTP2_STREAM_STATE_END_STREAM +} h2o_http2_stream_state_t; + +typedef struct st_h2o_http2_conn_num_streams_t { + uint32_t open; + uint32_t half_closed; + uint32_t send_body; +} h2o_http2_conn_num_streams_t; + +struct st_h2o_http2_stream_t { + uint32_t stream_id; + h2o_ostream_t _ostr_final; + h2o_http2_stream_state_t state; + h2o_http2_window_t output_window; + h2o_http2_window_t input_window; + h2o_http2_priority_t received_priority; + h2o_buffer_t *_req_body; /* NULL unless request body IS expected */ + size_t _expected_content_length; /* SIZE_MAX if unknown */ + H2O_VECTOR(h2o_iovec_t) _data; + h2o_ostream_pull_cb _pull_cb; + h2o_http2_conn_num_streams_t *_num_streams_slot; /* points http2_conn_t::num_streams::* in which the stream is counted */ + h2o_cache_digests_t *cache_digests; + union { + struct { + uint32_t parent_stream_id; + unsigned promise_sent : 1; + } push; + struct { + unsigned casper_is_ready : 1; + } pull; + }; + /* references governed by connection.c for handling various things */ + struct { + h2o_linklist_t link; + h2o_http2_scheduler_openref_t scheduler; + } _refs; + h2o_send_state_t send_state; /* state of the ostream, only used in push mode */ + /* placed at last since it is large and has it's own ctor */ + h2o_req_t req; +}; + +KHASH_MAP_INIT_INT64(h2o_http2_stream_t, h2o_http2_stream_t *) + +typedef enum enum_h2o_http2_conn_state_t { + H2O_HTTP2_CONN_STATE_OPEN, /* accepting new connections */ + H2O_HTTP2_CONN_STATE_HALF_CLOSED, /* no more accepting new streams */ + H2O_HTTP2_CONN_STATE_IS_CLOSING /* nothing should be sent */ +} h2o_http2_conn_state_t; + +struct st_h2o_http2_conn_t { + h2o_conn_t super; + h2o_socket_t *sock; + /* settings */ + h2o_http2_settings_t peer_settings; + /* streams */ + khash_t(h2o_http2_stream_t) * streams; + struct { + uint32_t max_open; + uint32_t max_processed; + } pull_stream_ids; + struct { + uint32_t max_open; + } push_stream_ids; + struct { + h2o_http2_conn_num_streams_t priority; + h2o_http2_conn_num_streams_t pull; + h2o_http2_conn_num_streams_t push; + } num_streams; + /* internal */ + h2o_http2_scheduler_node_t scheduler; + h2o_http2_conn_state_t state; + h2o_linklist_t _conns; /* linklist to h2o_context_t::http2._conns */ + ssize_t (*_read_expect)(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc); + h2o_buffer_t *_http1_req_input; /* contains data referred to by original request via HTTP/1.1 */ + h2o_hpack_header_table_t _input_header_table; + h2o_http2_window_t _input_window; + h2o_hpack_header_table_t _output_header_table; + h2o_linklist_t _pending_reqs; /* list of h2o_http2_stream_t that contain pending requests */ + h2o_timeout_entry_t _timeout_entry; + h2o_buffer_t *_headers_unparsed; /* for temporary storing HEADERS|CONTINUATION frames without END_HEADERS flag set */ + struct { + h2o_buffer_t *buf; + h2o_buffer_t *buf_in_flight; + h2o_linklist_t streams_to_proceed; + h2o_timeout_entry_t timeout_entry; + h2o_http2_window_t window; + } _write; + h2o_cache_t *push_memo; + h2o_http2_casper_t *casper; +}; + +int h2o_http2_update_peer_settings(h2o_http2_settings_t *settings, const uint8_t *src, size_t len, const char **err_desc); + +/* frames */ +uint8_t *h2o_http2_encode_frame_header(uint8_t *dst, size_t length, uint8_t type, uint8_t flags, int32_t stream_id); + +#define h2o_http2_encode_rst_stream_frame(buf, stream_id, errnum) \ + h2o_http2__encode_rst_stream_frame(buf, stream_id, (H2O_BUILD_ASSERT((errnum) > 0), errnum)) + +void h2o_http2__encode_rst_stream_frame(h2o_buffer_t **buf, uint32_t stream_id, int errnum); +void h2o_http2_encode_ping_frame(h2o_buffer_t **buf, int is_ack, const uint8_t *data); +void h2o_http2_encode_goaway_frame(h2o_buffer_t **buf, uint32_t last_stream_id, int errnum, h2o_iovec_t additional_data); +void h2o_http2_encode_window_update_frame(h2o_buffer_t **buf, uint32_t stream_id, int32_t window_size_increment); +ssize_t h2o_http2_decode_frame(h2o_http2_frame_t *frame, const uint8_t *src, size_t len, const h2o_http2_settings_t *host_settings, + const char **err_desc); +int h2o_http2_decode_data_payload(h2o_http2_data_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc); +int h2o_http2_decode_headers_payload(h2o_http2_headers_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc); +int h2o_http2_decode_priority_payload(h2o_http2_priority_t *payload, const h2o_http2_frame_t *frame, const char **err_desc); +int h2o_http2_decode_rst_stream_payload(h2o_http2_rst_stream_payload_t *payload, const h2o_http2_frame_t *frame, + const char **err_desc); +int h2o_http2_decode_ping_payload(h2o_http2_ping_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc); +int h2o_http2_decode_goaway_payload(h2o_http2_goaway_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc); +int h2o_http2_decode_window_update_payload(h2o_http2_window_update_payload_t *paylaod, const h2o_http2_frame_t *frame, + const char **err_desc, int *err_is_stream_level); + +/* connection */ +void h2o_http2_conn_register_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +void h2o_http2_conn_unregister_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +static h2o_http2_stream_t *h2o_http2_conn_get_stream(h2o_http2_conn_t *conn, uint32_t stream_id); +void h2o_http2_conn_push_path(h2o_http2_conn_t *conn, h2o_iovec_t path, h2o_http2_stream_t *src_stream); +void h2o_http2_conn_request_write(h2o_http2_conn_t *conn); +void h2o_http2_conn_register_for_proceed_callback(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +static ssize_t h2o_http2_conn_get_buffer_window(h2o_http2_conn_t *conn); +static void h2o_http2_conn_init_casper(h2o_http2_conn_t *conn, unsigned capacity_bits); + +/* stream */ +static int h2o_http2_stream_is_push(uint32_t stream_id); +h2o_http2_stream_t *h2o_http2_stream_open(h2o_http2_conn_t *conn, uint32_t stream_id, h2o_req_t *src_req, + const h2o_http2_priority_t *received_priority); +static void h2o_http2_stream_update_open_slot(h2o_http2_stream_t *stream, h2o_http2_conn_num_streams_t *slot); +static void h2o_http2_stream_set_state(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_http2_stream_state_t new_state); +static void h2o_http2_stream_prepare_for_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +void h2o_http2_stream_close(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +void h2o_http2_stream_reset(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +void h2o_http2_stream_send_pending_data(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +static int h2o_http2_stream_has_pending_data(h2o_http2_stream_t *stream); +void h2o_http2_stream_proceed(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); +static void h2o_http2_stream_send_push_promise(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream); + +/* misc */ +static void h2o_http2_window_init(h2o_http2_window_t *window, const h2o_http2_settings_t *peer_settings); +static int h2o_http2_window_update(h2o_http2_window_t *window, ssize_t delta); +static ssize_t h2o_http2_window_get_window(h2o_http2_window_t *window); +static void h2o_http2_window_consume_window(h2o_http2_window_t *window, size_t bytes); + +static uint16_t h2o_http2_decode16u(const uint8_t *src); +static uint32_t h2o_http2_decode24u(const uint8_t *src); +static uint32_t h2o_http2_decode32u(const uint8_t *src); +static uint8_t *h2o_http2_encode24u(uint8_t *dst, uint32_t value); +static uint8_t *h2o_http2_encode32u(uint8_t *dst, uint32_t value); + +h2o_http2_debug_state_t *h2o_http2_get_debug_state(h2o_req_t *req, int hpack_enabled); + +/* inline definitions */ + +inline void h2o_http2_window_init(h2o_http2_window_t *window, const h2o_http2_settings_t *peer_settings) +{ + window->_avail = peer_settings->initial_window_size; +} + +inline int h2o_http2_window_update(h2o_http2_window_t *window, ssize_t delta) +{ + ssize_t v = window->_avail + delta; + if (v > INT32_MAX) + return -1; + window->_avail = v; + return 0; +} + +inline ssize_t h2o_http2_window_get_window(h2o_http2_window_t *window) +{ + return window->_avail; +} + +inline void h2o_http2_window_consume_window(h2o_http2_window_t *window, size_t bytes) +{ + window->_avail -= bytes; +} + +inline h2o_http2_stream_t *h2o_http2_conn_get_stream(h2o_http2_conn_t *conn, uint32_t stream_id) +{ + khiter_t iter = kh_get(h2o_http2_stream_t, conn->streams, stream_id); + if (iter != kh_end(conn->streams)) + return kh_val(conn->streams, iter); + return NULL; +} + +inline int h2o_http2_stream_is_push(uint32_t stream_id) +{ + return stream_id % 2 == 0; +} + +inline ssize_t h2o_http2_conn_get_buffer_window(h2o_http2_conn_t *conn) +{ + ssize_t ret, winsz; + size_t capacity, cwnd_left; + + capacity = conn->_write.buf->capacity; + if ((cwnd_left = h2o_socket_prepare_for_latency_optimized_write( + conn->sock, &conn->super.ctx->globalconf->http2.latency_optimization)) < capacity) { + capacity = cwnd_left; + if (capacity < conn->_write.buf->size) + return 0; + } + + ret = capacity - conn->_write.buf->size; + if (ret < H2O_HTTP2_FRAME_HEADER_SIZE) + return 0; + ret -= H2O_HTTP2_FRAME_HEADER_SIZE; + winsz = h2o_http2_window_get_window(&conn->_write.window); + if (winsz < ret) + ret = winsz; + return ret; +} + +inline void h2o_http2_conn_init_casper(h2o_http2_conn_t *conn, unsigned capacity_bits) +{ + assert(conn->casper == NULL); + conn->casper = h2o_http2_casper_create(capacity_bits, 6); +} + +inline void h2o_http2_stream_update_open_slot(h2o_http2_stream_t *stream, h2o_http2_conn_num_streams_t *slot) +{ + --stream->_num_streams_slot->open; + ++slot->open; + stream->_num_streams_slot = slot; +} + +inline void h2o_http2_stream_set_state(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_http2_stream_state_t new_state) +{ + switch (new_state) { + case H2O_HTTP2_STREAM_STATE_IDLE: + assert(!"FIXME"); + break; + case H2O_HTTP2_STREAM_STATE_RECV_HEADERS: + assert(stream->state == H2O_HTTP2_STREAM_STATE_IDLE); + if (h2o_http2_stream_is_push(stream->stream_id)) + h2o_http2_stream_update_open_slot(stream, &conn->num_streams.push); + else + h2o_http2_stream_update_open_slot(stream, &conn->num_streams.pull); + stream->state = new_state; + stream->req.timestamps.request_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); + break; + case H2O_HTTP2_STREAM_STATE_RECV_BODY: + stream->state = new_state; + stream->req.timestamps.request_body_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); + break; + case H2O_HTTP2_STREAM_STATE_REQ_PENDING: + stream->state = new_state; + break; + case H2O_HTTP2_STREAM_STATE_SEND_HEADERS: + assert(stream->state == H2O_HTTP2_STREAM_STATE_REQ_PENDING); + ++stream->_num_streams_slot->half_closed; + stream->state = new_state; + break; + case H2O_HTTP2_STREAM_STATE_SEND_BODY: + stream->state = new_state; + ++stream->_num_streams_slot->send_body; + stream->req.timestamps.response_start_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); + break; + case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL: + assert(stream->state == H2O_HTTP2_STREAM_STATE_SEND_BODY); + stream->state = new_state; + break; + case H2O_HTTP2_STREAM_STATE_END_STREAM: + switch (stream->state) { + case H2O_HTTP2_STREAM_STATE_IDLE: + case H2O_HTTP2_STREAM_STATE_RECV_BODY: + case H2O_HTTP2_STREAM_STATE_RECV_HEADERS: + break; + case H2O_HTTP2_STREAM_STATE_REQ_PENDING: + break; + case H2O_HTTP2_STREAM_STATE_SEND_HEADERS: + --stream->_num_streams_slot->half_closed; + break; + case H2O_HTTP2_STREAM_STATE_SEND_BODY: + case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL: + --stream->_num_streams_slot->half_closed; + --stream->_num_streams_slot->send_body; + break; + case H2O_HTTP2_STREAM_STATE_END_STREAM: + assert(!"FIXME"); + break; + } + stream->state = new_state; + stream->req.timestamps.response_end_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); + --stream->_num_streams_slot->open; + stream->_num_streams_slot = NULL; + break; + } +} + +inline void h2o_http2_stream_prepare_for_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) +{ + assert(h2o_http2_scheduler_is_open(&stream->_refs.scheduler)); + + /* adjust max-open */ + uint32_t *max_open = + h2o_http2_stream_is_push(stream->stream_id) ? &conn->push_stream_ids.max_open : &conn->pull_stream_ids.max_open; + if (*max_open < stream->stream_id) + *max_open = stream->stream_id; + h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_RECV_HEADERS); + h2o_http2_window_init(&stream->output_window, &conn->peer_settings); +} + +inline int h2o_http2_stream_has_pending_data(h2o_http2_stream_t *stream) +{ + return stream->_data.size != 0; +} + +inline void h2o_http2_stream_send_push_promise(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) +{ + assert(!stream->push.promise_sent); + h2o_hpack_flatten_request(&conn->_write.buf, &conn->_output_header_table, stream->stream_id, conn->peer_settings.max_frame_size, + &stream->req, stream->push.parent_stream_id); + stream->push.promise_sent = 1; +} + +inline uint16_t h2o_http2_decode16u(const uint8_t *src) +{ + return (uint16_t)src[0] << 8 | src[1]; +} + +inline uint32_t h2o_http2_decode24u(const uint8_t *src) +{ + return (uint32_t)src[0] << 16 | (uint32_t)src[1] << 8 | src[2]; +} + +inline uint32_t h2o_http2_decode32u(const uint8_t *src) +{ + return (uint32_t)src[0] << 24 | (uint32_t)src[1] << 16 | (uint32_t)src[2] << 8 | src[3]; +} + +inline uint8_t *h2o_http2_encode24u(uint8_t *dst, uint32_t value) +{ + *dst++ = value >> 16; + *dst++ = value >> 8; + *dst++ = value; + return dst; +} + +inline uint8_t *h2o_http2_encode32u(uint8_t *dst, uint32_t value) +{ + *dst++ = value >> 24; + *dst++ = value >> 16; + *dst++ = value >> 8; + *dst++ = value; + return dst; +} + +inline h2o_hpack_header_table_entry_t *h2o_hpack_header_table_get(h2o_hpack_header_table_t *table, size_t index) +{ + size_t entry_index = (index + table->entry_start_index) % table->entry_capacity; + struct st_h2o_hpack_header_table_entry_t *entry = table->entries + entry_index; + assert(entry->name != NULL); + return entry; +} + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/http2_scheduler.h b/web/server/h2o/libh2o/include/h2o/http2_scheduler.h new file mode 100644 index 000000000..f0a7d6e87 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/http2_scheduler.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015 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. + */ +#ifndef h2o__http2__scheduler_h +#define h2o__http2__scheduler_h + +#include <assert.h> +#include "h2o/linklist.h" +#include "h2o/memory.h" + +typedef struct st_h2o_http2_scheduler_queue_node_t { + h2o_linklist_t _link; + size_t _deficit; +} h2o_http2_scheduler_queue_node_t; + +typedef struct st_h2o_http2_scheduler_queue_t h2o_http2_scheduler_queue_t; + +/** + * resembles a node in the dependency tree; i.e. assigned for each HTTP/2 stream (as a member of openref), or the root of the tree + * associated to the connection + */ +typedef struct st_h2o_http2_scheduler_node_t { + struct st_h2o_http2_scheduler_node_t *_parent; /* NULL if root */ + h2o_linklist_t _all_refs; /* list of nodes */ + h2o_http2_scheduler_queue_t *_queue; /* priority list (NULL if _all_refs is empty) */ +} h2o_http2_scheduler_node_t; + +/** + * the entry to be scheduled; is assigned for every HTTP/2 stream. + */ +typedef struct st_h2o_http2_scheduler_openref_t { + h2o_http2_scheduler_node_t node; + uint16_t weight; + h2o_linklist_t _all_link; /* linked to _all_refs */ + size_t _active_cnt; /* COUNT(active_streams_in_dependents) + _self_is_active */ + int _self_is_active; + h2o_http2_scheduler_queue_node_t _queue_node; +} h2o_http2_scheduler_openref_t; + +/** + * callback called by h2o_http2_scheduler_run. + * @param ref reference to an active stream that should consume resource + * @param still_is_active [out] flag to indicate whether the ref should still be marked as active after returning from the function + * @param cb_arg value of cb_arg passed to h2o_http2_scheduler_run + * @return non-zero value to stop traversing through the tree, or 0 to continue + */ +typedef int (*h2o_http2_scheduler_run_cb)(h2o_http2_scheduler_openref_t *ref, int *still_is_active, void *cb_arg); + +/** + * + */ +void h2o_http2_scheduler_init(h2o_http2_scheduler_node_t *root); + +/** + * disposes of the scheduler. All open references belonging to the node must be closed before calling this functions. + */ +void h2o_http2_scheduler_dispose(h2o_http2_scheduler_node_t *root); +/** + * opens a reference with given parent as its dependency + */ +void h2o_http2_scheduler_open(h2o_http2_scheduler_openref_t *ref, h2o_http2_scheduler_node_t *parent, uint16_t weight, + int exclusive); +/** + * closes a reference. All the dependents are raised to become the dependents of the parent of the reference being closed. + */ +void h2o_http2_scheduler_close(h2o_http2_scheduler_openref_t *ref); +/** + * reprioritizes the reference. + */ +void h2o_http2_scheduler_rebind(h2o_http2_scheduler_openref_t *ref, h2o_http2_scheduler_node_t *new_parent, uint16_t weight, + int exclusive); +/** + * tests if the ref is open + */ +static int h2o_http2_scheduler_is_open(h2o_http2_scheduler_openref_t *ref); +/** + * returns weight associated to the reference + */ +static uint16_t h2o_http2_scheduler_get_weight(h2o_http2_scheduler_openref_t *ref); +/** + * returns the parent + */ +static h2o_http2_scheduler_node_t *h2o_http2_scheduler_get_parent(h2o_http2_scheduler_openref_t *ref); +/** + * activates a reference so that it would be passed back as the argument to the callback of the h2o_http2_scheduler_run function + * if any resource should be allocated + */ +void h2o_http2_scheduler_activate(h2o_http2_scheduler_openref_t *ref); +/** + * calls the callback of the references linked to the dependency tree one by one, in the order defined by the dependency and the + * weight. + */ +int h2o_http2_scheduler_run(h2o_http2_scheduler_node_t *root, h2o_http2_scheduler_run_cb cb, void *cb_arg); +/** + * returns if there are any active entries nodes in the scheduler (may have false positives, but no false negatives) + */ +int h2o_http2_scheduler_is_active(h2o_http2_scheduler_node_t *root); + +/* inline definitions */ + +inline int h2o_http2_scheduler_is_open(h2o_http2_scheduler_openref_t *ref) +{ + return h2o_linklist_is_linked(&ref->_all_link); +} + +inline uint16_t h2o_http2_scheduler_get_weight(h2o_http2_scheduler_openref_t *ref) +{ + return ref->weight; +} + +inline h2o_http2_scheduler_node_t *h2o_http2_scheduler_get_parent(h2o_http2_scheduler_openref_t *ref) +{ + return ref->node._parent; +} + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/linklist.h b/web/server/h2o/libh2o/include/h2o/linklist.h new file mode 100644 index 000000000..eb7fd10cb --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/linklist.h @@ -0,0 +1,119 @@ +/* + * 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. + */ +#ifndef h2o__linklist_h +#define h2o__linklist_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <stddef.h> + +/** + * linklist + * The structure is used to represent both nodes and the head of the list. + * Nodes should be zero-filled upon initialization. + * Heads should be initialized by calling h2o_linklist_init_anchor. + */ +typedef struct st_h2o_linklist_t { + struct st_h2o_linklist_t *next; + struct st_h2o_linklist_t *prev; +} h2o_linklist_t; + +/** + * initializes the anchor (i.e. head) of a linked list + */ +static void h2o_linklist_init_anchor(h2o_linklist_t *anchor); +/** + * tests if the list is empty + */ +static int h2o_linklist_is_empty(h2o_linklist_t *anchor); +/** + * tests if the node is linked to a list + */ +static int h2o_linklist_is_linked(h2o_linklist_t *node); +/** + * inserts a node to the linked list + * @param pos insert position; the node will be inserted before pos + * @param node the node to be inserted + */ +static void h2o_linklist_insert(h2o_linklist_t *pos, h2o_linklist_t *node); +/** + * inserts all the elements of list before pos (list becomes empty) + */ +static void h2o_linklist_insert_list(h2o_linklist_t *pos, h2o_linklist_t *list); +/** + * unlinks a node from the linked list + */ +static void h2o_linklist_unlink(h2o_linklist_t *node); + +/* inline defs */ + +inline void h2o_linklist_init_anchor(h2o_linklist_t *anchor) +{ + anchor->next = anchor->prev = anchor; +} + +inline int h2o_linklist_is_linked(h2o_linklist_t *node) +{ + return node->next != NULL; +} + +inline int h2o_linklist_is_empty(h2o_linklist_t *anchor) +{ + return anchor->next == anchor; +} + +inline void h2o_linklist_insert(h2o_linklist_t *pos, h2o_linklist_t *node) +{ + assert(!h2o_linklist_is_linked(node)); + + node->prev = pos->prev; + node->next = pos; + node->prev->next = node; + node->next->prev = node; +} + +inline void h2o_linklist_insert_list(h2o_linklist_t *pos, h2o_linklist_t *list) +{ + if (h2o_linklist_is_empty(list)) + return; + list->next->prev = pos->prev; + list->prev->next = pos; + pos->prev->next = list->next; + pos->prev = list->prev; + h2o_linklist_init_anchor(list); +} + +inline void h2o_linklist_unlink(h2o_linklist_t *node) +{ + node->next->prev = node->prev; + node->prev->next = node->next; + node->next = node->prev = NULL; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/memcached.h b/web/server/h2o/libh2o/include/h2o/memcached.h new file mode 100644 index 000000000..2bd7da891 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/memcached.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__memcached_h +#define h2o__memcached_h + +#include <pthread.h> +#include "h2o/memory.h" +#include "h2o/multithread.h" + +#define H2O_MEMCACHED_ENCODE_KEY 0x1 +#define H2O_MEMCACHED_ENCODE_VALUE 0x2 + +typedef struct st_h2o_memcached_context_t h2o_memcached_context_t; +typedef struct st_h2o_memcached_req_t h2o_memcached_req_t; +typedef void (*h2o_memcached_get_cb)(h2o_iovec_t value, void *cb_data); + +h2o_memcached_context_t *h2o_memcached_create_context(const char *host, uint16_t port, int text_protocol, size_t num_threads, + const char *prefix); + +void h2o_memcached_receiver(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages); + +h2o_memcached_req_t *h2o_memcached_get(h2o_memcached_context_t *ctx, h2o_multithread_receiver_t *receiver, h2o_iovec_t key, + h2o_memcached_get_cb cb, void *cb_data, int flags); + +void h2o_memcached_cancel_get(h2o_memcached_context_t *ctx, h2o_memcached_req_t *req); + +void h2o_memcached_set(h2o_memcached_context_t *ctx, h2o_iovec_t key, h2o_iovec_t value, uint32_t expiration, int flags); + +void h2o_memcached_delete(h2o_memcached_context_t *ctx, h2o_iovec_t key, int flags); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/memory.h b/web/server/h2o/libh2o/include/h2o/memory.h new file mode 100644 index 000000000..10c137c88 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/memory.h @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu + * + * 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. + */ +#ifndef h2o__memory_h +#define h2o__memory_h + +#ifdef __sun__ +#include <alloca.h> +#endif +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define H2O_STRUCT_FROM_MEMBER(s, m, p) ((s *)((char *)(p)-offsetof(s, m))) + +#if __GNUC__ >= 3 +#define H2O_LIKELY(x) __builtin_expect(!!(x), 1) +#define H2O_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define H2O_LIKELY(x) (x) +#define H2O_UNLIKELY(x) (x) +#endif + +#ifdef __GNUC__ +#define H2O_GNUC_VERSION ((__GNUC__ << 16) | (__GNUC_MINOR__ << 8) | __GNUC_PATCHLEVEL__) +#else +#define H2O_GNUC_VERSION 0 +#endif + +#if __STDC_VERSION__ >= 201112L +#define H2O_NORETURN _Noreturn +#elif defined(__clang__) || defined(__GNUC__) && H2O_GNUC_VERSION >= 0x20500 +// noreturn was not defined before gcc 2.5 +#define H2O_NORETURN __attribute__((noreturn)) +#else +#define H2O_NORETURN +#endif + +#if !defined(__clang__) && defined(__GNUC__) && H2O_GNUC_VERSION >= 0x40900 +// returns_nonnull was seemingly not defined before gcc 4.9 (exists in 4.9.1 but not in 4.8.2) +#define H2O_RETURNS_NONNULL __attribute__((returns_nonnull)) +#else +#define H2O_RETURNS_NONNULL +#endif + +#define H2O_TO__STR(n) #n +#define H2O_TO_STR(n) H2O_TO__STR(n) + +#define H2O_BUILD_ASSERT(condition) ((void)sizeof(char[2 * !!(!__builtin_constant_p(condition) || (condition)) - 1])) + +typedef struct st_h2o_buffer_prototype_t h2o_buffer_prototype_t; + +/** + * buffer structure compatible with iovec + */ +typedef struct st_h2o_iovec_t { + char *base; + size_t len; +} h2o_iovec_t; + +typedef struct st_h2o_mem_recycle_t { + size_t max; + size_t cnt; + struct st_h2o_mem_recycle_chunk_t *_link; +} h2o_mem_recycle_t; + +struct st_h2o_mem_pool_shared_entry_t { + size_t refcnt; + void (*dispose)(void *); + char bytes[1]; +}; + +/** + * the memory pool + */ +typedef struct st_h2o_mem_pool_t { + struct st_h2o_mem_pool_chunk_t *chunks; + size_t chunk_offset; + struct st_h2o_mem_pool_shared_ref_t *shared_refs; + struct st_h2o_mem_pool_direct_t *directs; +} h2o_mem_pool_t; + +/** + * buffer used to store incoming / outgoing octets + */ +typedef struct st_h2o_buffer_t { + /** + * capacity of the buffer (or minimum initial capacity in case of a prototype (i.e. bytes == NULL)) + */ + size_t capacity; + /** + * amount of the data available + */ + size_t size; + /** + * pointer to the start of the data (or NULL if is pointing to a prototype) + */ + char *bytes; + /** + * prototype (or NULL if the instance is part of the prototype (i.e. bytes == NULL)) + */ + h2o_buffer_prototype_t *_prototype; + /** + * file descriptor (if not -1, used to store the buffer) + */ + int _fd; + char _buf[1]; +} h2o_buffer_t; + +typedef struct st_h2o_buffer_mmap_settings_t { + size_t threshold; + char fn_template[FILENAME_MAX]; +} h2o_buffer_mmap_settings_t; + +struct st_h2o_buffer_prototype_t { + h2o_mem_recycle_t allocator; + h2o_buffer_t _initial_buf; + h2o_buffer_mmap_settings_t *mmap_settings; +}; + +#define H2O_VECTOR(type) \ + struct { \ + type *entries; \ + size_t size; \ + size_t capacity; \ + } + +typedef H2O_VECTOR(void) h2o_vector_t; +typedef H2O_VECTOR(h2o_iovec_t) h2o_iovec_vector_t; + +extern void *(*h2o_mem__set_secure)(void *, int, size_t); + +/** + * prints an error message and aborts + */ +#define h2o_fatal(msg) h2o__fatal(__FILE__ ":" H2O_TO_STR(__LINE__) ":" msg) +H2O_NORETURN void h2o__fatal(const char *msg); + +/** + * A version of memcpy that can take a NULL @src to avoid UB + */ +static void *h2o_memcpy(void *dst, const void *src, size_t n); +/** + * constructor for h2o_iovec_t + */ +static h2o_iovec_t h2o_iovec_init(const void *base, size_t len); +/** + * wrapper of malloc; allocates given size of memory or dies if impossible + */ +H2O_RETURNS_NONNULL static void *h2o_mem_alloc(size_t sz); +/** + * warpper of realloc; reallocs the given chunk or dies if impossible + */ +static void *h2o_mem_realloc(void *oldp, size_t sz); + +/** + * allocates memory using the reusing allocator + */ +void *h2o_mem_alloc_recycle(h2o_mem_recycle_t *allocator, size_t sz); +/** + * returns the memory to the reusing allocator + */ +void h2o_mem_free_recycle(h2o_mem_recycle_t *allocator, void *p); + +/** + * initializes the memory pool. + */ +void h2o_mem_init_pool(h2o_mem_pool_t *pool); +/** + * clears the memory pool. + * Applications may dispose the pool after calling the function or reuse it without calling h2o_mem_init_pool. + */ +void h2o_mem_clear_pool(h2o_mem_pool_t *pool); +/** + * allocates given size of memory from the memory pool, or dies if impossible + */ +void *h2o_mem_alloc_pool(h2o_mem_pool_t *pool, size_t sz); +/** + * allocates a ref-counted chunk of given size from the memory pool, or dies if impossible. + * The ref-count of the returned chunk is 1 regardless of whether or not the chunk is linked to a pool. + * @param pool pool to which the allocated chunk should be linked (or NULL to allocate an orphan chunk) + */ +void *h2o_mem_alloc_shared(h2o_mem_pool_t *pool, size_t sz, void (*dispose)(void *)); +/** + * links a ref-counted chunk to a memory pool. + * The ref-count of the chunk will be decremented when the pool is cleared. + * It is permitted to link a chunk more than once to a single pool. + */ +void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p); +/** + * increments the reference count of a ref-counted chunk. + */ +static void h2o_mem_addref_shared(void *p); +/** + * decrements the reference count of a ref-counted chunk. + * The chunk gets freed when the ref-count reaches zero. + */ +static int h2o_mem_release_shared(void *p); +/** + * initialize the buffer using given prototype. + */ +static void h2o_buffer_init(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype); +/** + * + */ +void h2o_buffer__do_free(h2o_buffer_t *buffer); +/** + * disposes of the buffer + */ +static void h2o_buffer_dispose(h2o_buffer_t **buffer); +/** + * allocates a buffer. + * @param inbuf - pointer to a pointer pointing to the structure (set *inbuf to NULL to allocate a new buffer) + * @param min_guarantee minimum number of bytes to reserve + * @return buffer to which the next data should be stored + * @note When called against a new buffer, the function returns a buffer twice the size of requested guarantee. The function uses + * exponential backoff for already-allocated buffers. + */ +h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **inbuf, size_t min_guarantee); +/** + * throws away given size of the data from the buffer. + * @param delta number of octets to be drained from the buffer + */ +void h2o_buffer_consume(h2o_buffer_t **inbuf, size_t delta); +/** + * resets the buffer prototype + */ +static void h2o_buffer_set_prototype(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype); +/** + * registers a buffer to memory pool, so that it would be freed when the pool is flushed. Note that the buffer cannot be resized + * after it is linked. + */ +static void h2o_buffer_link_to_pool(h2o_buffer_t *buffer, h2o_mem_pool_t *pool); +void h2o_buffer__dispose_linked(void *p); +/** + * grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible). + * @param pool memory pool that the vector is using + * @param vector the vector + * @param element_size size of the elements stored in the vector + * @param new_capacity the capacity of the buffer after the function returns + */ +#define h2o_vector_reserve(pool, vector, new_capacity) \ + h2o_vector__reserve((pool), (h2o_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (new_capacity)) +static void h2o_vector__reserve(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t element_size, size_t new_capacity); +void h2o_vector__expand(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t element_size, size_t new_capacity); +/** + * erase the entry at given index from the vector + */ +#define h2o_vector_erase(vector, index) h2o_vector__erase((h2o_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (index)) +static void h2o_vector__erase(h2o_vector_t *vector, size_t element_size, size_t index); + +/** + * tests if target chunk (target_len bytes long) is equal to test chunk (test_len bytes long) + */ +static int h2o_memis(const void *target, size_t target_len, const void *test, size_t test_len); + +/** + * variant of memchr that searches the string from tail + */ +static void *h2o_memrchr(const void *s, int c, size_t n); + +/** + * secure memset + */ +static void *h2o_mem_set_secure(void *b, int c, size_t len); + +/** + * swaps contents of memory + */ +void h2o_mem_swap(void *x, void *y, size_t len); + +/** + * emits hexdump of given buffer to fp + */ +void h2o_dump_memory(FILE *fp, const char *buf, size_t len); + +/** + * appends an element to a NULL-terminated list allocated using malloc + */ +void h2o_append_to_null_terminated_list(void ***list, void *element); + +/* inline defs */ + +inline void *h2o_memcpy(void *dst, const void *src, size_t n) +{ + if (src != NULL) + return memcpy(dst, src, n); + else if (n != 0) + h2o_fatal("null pointer passed to memcpy"); + return dst; +} + +inline h2o_iovec_t h2o_iovec_init(const void *base, size_t len) +{ + /* intentionally declared to take a "const void*" since it may contain any type of data and since _some_ buffers are constant */ + h2o_iovec_t buf; + buf.base = (char *)base; + buf.len = len; + return buf; +} + +inline void *h2o_mem_alloc(size_t sz) +{ + void *p = malloc(sz); + if (p == NULL) + h2o_fatal("no memory"); + return p; +} + +inline void *h2o_mem_realloc(void *oldp, size_t sz) +{ + void *newp = realloc(oldp, sz); + if (newp == NULL) { + h2o_fatal("no memory"); + return oldp; + } + return newp; +} + +inline void h2o_mem_addref_shared(void *p) +{ + struct st_h2o_mem_pool_shared_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p); + assert(entry->refcnt != 0); + ++entry->refcnt; +} + +inline int h2o_mem_release_shared(void *p) +{ + struct st_h2o_mem_pool_shared_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p); + if (--entry->refcnt == 0) { + if (entry->dispose != NULL) + entry->dispose(entry->bytes); + free(entry); + return 1; + } + return 0; +} + +inline void h2o_buffer_init(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype) +{ + *buffer = &prototype->_initial_buf; +} + +inline void h2o_buffer_dispose(h2o_buffer_t **_buffer) +{ + h2o_buffer_t *buffer = *_buffer; + *_buffer = NULL; + if (buffer->bytes != NULL) + h2o_buffer__do_free(buffer); +} + +inline void h2o_buffer_set_prototype(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype) +{ + if ((*buffer)->_prototype != NULL) + (*buffer)->_prototype = prototype; + else + *buffer = &prototype->_initial_buf; +} + +inline void h2o_buffer_link_to_pool(h2o_buffer_t *buffer, h2o_mem_pool_t *pool) +{ + h2o_buffer_t **slot = (h2o_buffer_t **)h2o_mem_alloc_shared(pool, sizeof(*slot), h2o_buffer__dispose_linked); + *slot = buffer; +} + +inline void h2o_vector__reserve(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t element_size, size_t new_capacity) +{ + if (vector->capacity < new_capacity) { + h2o_vector__expand(pool, vector, element_size, new_capacity); + } +} + +inline void h2o_vector__erase(h2o_vector_t *vector, size_t element_size, size_t index) +{ + char *entries = (char *)vector->entries; + memmove(entries + element_size * index, entries + element_size * (index + 1), vector->size - index - 1); + --vector->size; +} + +inline int h2o_memis(const void *_target, size_t target_len, const void *_test, size_t test_len) +{ + const char *target = (const char *)_target, *test = (const char *)_test; + if (target_len != test_len) + return 0; + if (target_len == 0) + return 1; + if (target[0] != test[0]) + return 0; + return memcmp(target + 1, test + 1, test_len - 1) == 0; +} + +inline void *h2o_memrchr(const void *s, int c, size_t n) +{ + if (n != 0) { + const char *p = (const char *)s + n; + do { + if (*--p == c) + return (void *)p; + } while (p != s); + } + return NULL; +} + +inline void *h2o_mem_set_secure(void *b, int c, size_t len) +{ + return h2o_mem__set_secure(b, c, len); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/mruby_.h b/web/server/h2o/libh2o/include/h2o/mruby_.h new file mode 100644 index 000000000..908d34f4f --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/mruby_.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Ryosuke Matsumoto + * + * 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. + */ +#ifndef H20_MRUBY_H +#define H20_MRUBY_H + +#include "h2o.h" +#include <mruby.h> +#include <mruby/data.h> +#include <mruby/proc.h> +#include <mruby/compile.h> + +#define H2O_MRUBY_MODULE_NAME "h2o_mruby" + +enum { + H2O_MRUBY_LIT_REQUEST_METHOD = H2O_MAX_TOKENS, + H2O_MRUBY_LIT_SCRIPT_NAME, + H2O_MRUBY_LIT_PATH_INFO, + H2O_MRUBY_LIT_QUERY_STRING, + H2O_MRUBY_LIT_SERVER_NAME, + H2O_MRUBY_LIT_SERVER_ADDR, + H2O_MRUBY_LIT_SERVER_PORT, + H2O_MRUBY_LIT_SERVER_PROTOCOL, + H2O_MRUBY_LIT_CONTENT_LENGTH, + H2O_MRUBY_LIT_REMOTE_ADDR, + H2O_MRUBY_LIT_REMOTE_PORT, + H2O_MRUBY_LIT_REMOTE_USER, + H2O_MRUBY_LIT_RACK_URL_SCHEME, + H2O_MRUBY_LIT_RACK_MULTITHREAD, + H2O_MRUBY_LIT_RACK_MULTIPROCESS, + H2O_MRUBY_LIT_RACK_RUN_ONCE, + H2O_MRUBY_LIT_RACK_HIJACK_, + H2O_MRUBY_LIT_RACK_INPUT, + H2O_MRUBY_LIT_RACK_ERRORS, + H2O_MRUBY_LIT_SERVER_SOFTWARE, + H2O_MRUBY_LIT_SERVER_SOFTWARE_VALUE, + H2O_MRUBY_LIT_SEPARATOR_COMMA, + H2O_MRUBY_LIT_SEPARATOR_SEMICOLON, + H2O_MRUBY_PROC_EACH_TO_ARRAY, + H2O_MRUBY_PROC_APP_TO_FIBER, + + /* used by chunked.c */ + H2O_MRUBY_CHUNKED_PROC_EACH_TO_FIBER, + + /* used by http_request.c */ + H2O_MRUBY_HTTP_REQUEST_CLASS, + H2O_MRUBY_HTTP_INPUT_STREAM_CLASS, + H2O_MRUBY_HTTP_EMPTY_INPUT_STREAM_CLASS, + + H2O_MRUBY_NUM_CONSTANTS +}; + +typedef struct st_h2o_mruby_config_vars_t { + h2o_iovec_t source; + char *path; + int lineno; +} h2o_mruby_config_vars_t; + +typedef struct st_h2o_mruby_handler_t { + h2o_handler_t super; + h2o_mruby_config_vars_t config; +} h2o_mruby_handler_t; + +typedef struct st_h2o_mruby_shared_context_t { + mrb_state *mrb; + mrb_value constants; + struct { + mrb_sym sym_call; + mrb_sym sym_close; + mrb_sym sym_method; + mrb_sym sym_headers; + mrb_sym sym_body; + mrb_sym sym_async; + } symbols; +} h2o_mruby_shared_context_t; + +typedef struct st_h2o_mruby_context_t { + h2o_mruby_handler_t *handler; + mrb_value proc; + h2o_mruby_shared_context_t *shared; +} h2o_mruby_context_t; + +typedef struct st_h2o_mruby_chunked_t h2o_mruby_chunked_t; +typedef struct st_h2o_mruby_http_request_context_t h2o_mruby_http_request_context_t; + +typedef struct st_h2o_mruby_generator_t { + h2o_generator_t super; + h2o_req_t *req; /* becomes NULL once the underlying connection gets terminated */ + h2o_mruby_context_t *ctx; + mrb_value rack_input; + h2o_mruby_chunked_t *chunked; +} h2o_mruby_generator_t; + +#define H2O_MRUBY_CALLBACK_ID_EXCEPTION_RAISED -1 /* used to notify exception, does not execution to mruby code */ +#define H2O_MRUBY_CALLBACK_ID_SEND_CHUNKED_EOS -2 +#define H2O_MRUBY_CALLBACK_ID_HTTP_JOIN_RESPONSE -3 +#define H2O_MRUBY_CALLBACK_ID_HTTP_FETCH_CHUNK -4 + +enum { H2O_MRUBY_CALLBACK_NEXT_ACTION_STOP, H2O_MRUBY_CALLBACK_NEXT_ACTION_IMMEDIATE, H2O_MRUBY_CALLBACK_NEXT_ACTION_ASYNC }; + +#define h2o_mruby_assert(mrb) \ + if (mrb->exc != NULL) \ + h2o_mruby__assert_failed(mrb, __FILE__, __LINE__) + +/* source files using this macro should include mruby/throw.h */ +#define H2O_MRUBY_EXEC_GUARD(block) \ + do { \ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; \ + struct mrb_jmpbuf c_jmp; \ + MRB_TRY(&c_jmp) \ + { \ + mrb->jmp = &c_jmp; \ + do { \ + block \ + } while (0); \ + mrb->jmp = prev_jmp; \ + } \ + MRB_CATCH(&c_jmp) \ + { \ + mrb->jmp = prev_jmp; \ + } \ + MRB_END_EXC(&c_jmp); \ + } while (0) + +/* handler/mruby.c */ +extern __thread h2o_mruby_generator_t *h2o_mruby_current_generator; +void h2o_mruby__assert_failed(mrb_state *mrb, const char *file, int line); +mrb_value h2o_mruby_to_str(mrb_state *mrb, mrb_value v); +mrb_value h2o_mruby_eval_expr(mrb_state *mrb, const char *expr); +void h2o_mruby_define_callback(mrb_state *mrb, const char *name, int id); +mrb_value h2o_mruby_create_data_instance(mrb_state *mrb, mrb_value class_obj, void *ptr, const mrb_data_type *type); +void h2o_mruby_setup_globals(mrb_state *mrb); +mrb_value h2o_mruby_compile_code(mrb_state *mrb, h2o_mruby_config_vars_t *config, char *errbuf); +h2o_mruby_handler_t *h2o_mruby_register(h2o_pathconf_t *pathconf, h2o_mruby_config_vars_t *config); +void h2o_mruby_run_fiber(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value input, int *is_delegate); +mrb_value h2o_mruby_each_to_array(h2o_mruby_context_t *handler_ctx, mrb_value src); +int h2o_mruby_iterate_headers(h2o_mruby_context_t *handler_ctx, mrb_value headers, + int (*cb)(h2o_mruby_context_t *, h2o_iovec_t, h2o_iovec_t, void *), void *cb_data); + +/* handler/mruby/chunked.c */ +void h2o_mruby_send_chunked_init_context(h2o_mruby_shared_context_t *ctx); +void h2o_mruby_send_chunked_close(h2o_mruby_generator_t *generator); +mrb_value h2o_mruby_send_chunked_init(h2o_mruby_generator_t *generator, mrb_value body); +void h2o_mruby_send_chunked_dispose(h2o_mruby_generator_t *generator); +mrb_value h2o_mruby_send_chunked_eos_callback(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value input, + int *next_action); + +/* handler/mruby/http_request.c */ +void h2o_mruby_http_request_init_context(h2o_mruby_shared_context_t *ctx); +mrb_value h2o_mruby_http_join_response_callback(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value args, + int *next_action); +mrb_value h2o_mruby_http_fetch_chunk_callback(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value input, + int *next_action); +h2o_mruby_http_request_context_t *h2o_mruby_http_set_shortcut(mrb_state *mrb, mrb_value obj, void (*cb)(h2o_mruby_generator_t *)); +h2o_buffer_t **h2o_mruby_http_peek_content(h2o_mruby_http_request_context_t *ctx, int *is_final); + +/* handler/configurator/mruby.c */ +void h2o_mruby_register_configurator(h2o_globalconf_t *conf); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/multithread.h b/web/server/h2o/libh2o/include/h2o/multithread.h new file mode 100644 index 000000000..d089379e5 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/multithread.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku, Tatsuhiko Kubo + * + * 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. + */ +#ifndef h2o__multithread_h +#define h2o__multithread_h + +#include <pthread.h> +#include "h2o/linklist.h" +#include "h2o/socket.h" + +typedef struct st_h2o_multithread_receiver_t h2o_multithread_receiver_t; +typedef struct st_h2o_multithread_queue_t h2o_multithread_queue_t; +typedef struct st_h2o_multithread_request_t h2o_multithread_request_t; + +typedef void (*h2o_multithread_receiver_cb)(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages); +typedef void (*h2o_multithread_response_cb)(h2o_multithread_request_t *req); + +struct st_h2o_multithread_receiver_t { + h2o_multithread_queue_t *queue; + h2o_linklist_t _link; + h2o_linklist_t _messages; + h2o_multithread_receiver_cb cb; +}; + +typedef struct st_h2o_multithread_message_t { + h2o_linklist_t link; +} h2o_multithread_message_t; + +struct st_h2o_multithread_request_t { + h2o_multithread_message_t super; + h2o_multithread_receiver_t *source; + h2o_multithread_response_cb cb; +}; + +typedef struct st_h2o_sem_t { + pthread_mutex_t _mutex; + pthread_cond_t _cond; + ssize_t _cur; + ssize_t _capacity; +} h2o_sem_t; + +typedef struct st_h2o_barrier_t { + pthread_mutex_t _mutex; + pthread_cond_t _cond; + size_t _count; +} h2o_barrier_t; + +/** + * creates a queue that is used for inter-thread communication + */ +h2o_multithread_queue_t *h2o_multithread_create_queue(h2o_loop_t *loop); +/** + * destroys the queue + */ +void h2o_multithread_destroy_queue(h2o_multithread_queue_t *queue); +/** + * registers a receiver for specific type of message + */ +void h2o_multithread_register_receiver(h2o_multithread_queue_t *queue, h2o_multithread_receiver_t *receiver, + h2o_multithread_receiver_cb cb); +/** + * unregisters a receiver + */ +void h2o_multithread_unregister_receiver(h2o_multithread_queue_t *queue, h2o_multithread_receiver_t *receiver); +/** + * sends a message (or set message to NULL to just wake up the receiving thread) + */ +void h2o_multithread_send_message(h2o_multithread_receiver_t *receiver, h2o_multithread_message_t *message); +/** + * sends a request + */ +void h2o_multithread_send_request(h2o_multithread_receiver_t *receiver, h2o_multithread_request_t *req); +/** + * create a thread + */ +void h2o_multithread_create_thread(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg); + +void h2o_sem_init(h2o_sem_t *sem, ssize_t capacity); +void h2o_sem_destroy(h2o_sem_t *sem); +void h2o_sem_wait(h2o_sem_t *sem); +void h2o_sem_post(h2o_sem_t *sem); +void h2o_sem_set_capacity(h2o_sem_t *sem, ssize_t new_capacity); + +#define H2O_BARRIER_INITIALIZER(count_) {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, count_} +void h2o_barrier_init(h2o_barrier_t *barrier, size_t count); +int h2o_barrier_wait(h2o_barrier_t *barrier); +int h2o_barrier_done(h2o_barrier_t *barrier); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/openssl_backport.h b/web/server/h2o/libh2o/include/h2o/openssl_backport.h new file mode 100644 index 000000000..72cc43c45 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/openssl_backport.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__openssl_backport_h +#define h2o__openssl_backport_h + +#include <stdlib.h> + +/* backports for OpenSSL 1.0.2 */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) + +#define BIO_get_data(bio) ((bio)->ptr) +#define BIO_set_data(bio, p) ((bio)->ptr = (p)) +#define BIO_get_init(bio) ((bio)->init) +#define BIO_set_init(bio, i) ((bio)->init = (i)) +#define BIO_get_shutdown(bio) ((bio)->shutdown) +#define BIO_set_shutdown(bio, shut) ((bio)->shutdown = (shut)) + +static inline BIO_METHOD *BIO_meth_new(int type, const char *name) +{ + BIO_METHOD *bm = (BIO_METHOD *)malloc(sizeof(*bm)); + if (bm != NULL) { + memset(bm, 0, sizeof(*bm)); + bm->type = type; + bm->name = name; + } + return bm; +} + +#define BIO_meth_set_write(bm, cb) ((bm)->bwrite = cb) +#define BIO_meth_set_read(bm, cb) ((bm)->bread = cb) +#define BIO_meth_set_puts(bm, cb) ((bm)->bputs = cb) +#define BIO_meth_set_ctrl(bm, cb) ((bm)->ctrl = cb) + +#define SSL_CTX_up_ref(ctx) CRYPTO_add(&(ctx)->references, 1, CRYPTO_LOCK_SSL_CTX) + +#define X509_STORE_up_ref(store) CRYPTO_add(&(store)->references, 1, CRYPTO_LOCK_X509_STORE) + +#endif + +/* backports for OpenSSL 1.0.1 and LibreSSL */ +#if OPENSSL_VERSION_NUMBER < 0x10002000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) + +#define SSL_is_server(ssl) ((ssl)->server) + +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/rand.h b/web/server/h2o/libh2o/include/h2o/rand.h new file mode 100644 index 000000000..76721d262 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/rand.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 David Carlier + * + * 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. + */ +#ifndef h2o__rand_h +#define h2o__rand_h + +#include <stdlib.h> +#include <unistd.h> + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#define h2o_srand() +#define h2o_rand() arc4random() +#else +#define h2o_srand() srand(time(NULL) ^ getpid()) +#define h2o_rand() rand() +#endif +#endif diff --git a/web/server/h2o/libh2o/include/h2o/serverutil.h b/web/server/h2o/libh2o/include/h2o/serverutil.h new file mode 100644 index 000000000..7698cdcb4 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/serverutil.h @@ -0,0 +1,81 @@ +/* + * 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. + */ +#ifndef h2o__server_starter_h +#define h2o__server_starter_h + +#include <stddef.h> + +/* taken from sysexits.h */ +#ifndef EX_SOFTWARE +#define EX_SOFTWARE 70 +#endif +#ifndef EX_OSERR +#define EX_OSERR 71 +#endif +#ifndef EX_TEMPFAIL +#define EX_TEMPFAIL 75 +#endif +#ifndef EX_CONFIG +#define EX_CONFIG 78 +#endif + +/** + * equivalent of signal(3) + */ +void h2o_set_signal_handler(int signo, void (*cb)(int signo)); + +/** + * equiv. to setuidgid of djb + */ +int h2o_setuidgid(const char *user); + +/** + * return a list of fds passed in from Server::Starter, or 0 if Server::Starter was not used. -1 on error + */ +size_t h2o_server_starter_get_fds(int **_fds); + +/** + * spawns a command with given arguments, while mapping the designated file descriptors. + * @param cmd file being executed + * @param argv argv passed to the executable + * @param mapped_fds if non-NULL, must point to an array contain containing a list of pair of file descriptors, terminated with -1. + * Every pair of the mapping will be duplicated by calling `dup2` before execvp is being called if the second value of the + * pair is not -1. If the second value is -1, then `close` is called with the first value as the argument. + * @return pid of the process being spawned if successful, or -1 if otherwise + */ +pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int clocexec_mutex_is_locked); + +/** + * executes a command and returns its output + * @param cmd + * @param argv + * @param resp the output, only available if the function returns zero + * @param child_status result of waitpid(child_pid), only available if the function returns zero + */ +int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status); + +/** + * Gets the number of processor cores + */ +size_t h2o_numproc(void); + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/socket.h b/web/server/h2o/libh2o/include/h2o/socket.h new file mode 100644 index 000000000..58ada8509 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/socket.h @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc. + * + * 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. + */ +#ifndef h2o__socket_h +#define h2o__socket_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <sys/socket.h> +#include <openssl/ssl.h> +#include "h2o/cache.h" +#include "h2o/memory.h" +#include "h2o/openssl_backport.h" +#include "h2o/string_.h" + +#ifndef H2O_USE_LIBUV +#if H2O_USE_SELECT || H2O_USE_EPOLL || H2O_USE_KQUEUE +#define H2O_USE_LIBUV 0 +#else +#define H2O_USE_LIBUV 1 +#endif +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#define H2O_USE_ALPN 1 +#define H2O_USE_NPN 1 +#elif OPENSSL_VERSION_NUMBER >= 0x10001000L +#define H2O_USE_ALPN 0 +#define H2O_USE_NPN 1 +#else +#define H2O_USE_ALPN 0 +#define H2O_USE_NPN 0 +#endif + +typedef struct st_h2o_sliding_counter_t { + uint64_t average; + struct { + uint64_t sum; + uint64_t slots[8]; + size_t index; + } prev; + struct { + uint64_t start_at; + } cur; +} h2o_sliding_counter_t; + +static int h2o_sliding_counter_is_running(h2o_sliding_counter_t *counter); +static void h2o_sliding_counter_start(h2o_sliding_counter_t *counter, uint64_t now); +void h2o_sliding_counter_stop(h2o_sliding_counter_t *counter, uint64_t now); + +#define H2O_SOCKET_INITIAL_INPUT_BUFFER_SIZE 4096 + +typedef struct st_h2o_socket_t h2o_socket_t; + +typedef void (*h2o_socket_cb)(h2o_socket_t *sock, const char *err); + +#if H2O_USE_LIBUV +#include "socket/uv-binding.h" +#else +#include "socket/evloop.h" +#endif + +struct st_h2o_socket_peername_t { + socklen_t len; + struct sockaddr addr; +}; + +enum { + H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_TBD = 0, + H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE, + H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED, + H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED +}; + +/** + * abstraction layer for sockets (SSL vs. TCP) + */ +struct st_h2o_socket_t { + void *data; + struct st_h2o_socket_ssl_t *ssl; + h2o_buffer_t *input; + /** + * total bytes read (above the TLS layer) + */ + size_t bytes_read; + /** + * total bytes written (above the TLS layer) + */ + size_t bytes_written; + struct { + void (*cb)(void *data); + void *data; + } on_close; + struct { + h2o_socket_cb read; + h2o_socket_cb write; + } _cb; + struct st_h2o_socket_peername_t *_peername; + struct { + uint8_t state; /* one of H2O_SOCKET_LATENCY_STATE_* */ + uint8_t notsent_is_minimized : 1; + uint16_t suggested_tls_payload_size; + size_t suggested_write_size; /* SIZE_MAX if no need to optimize for latency */ + } _latency_optimization; +}; + +typedef struct st_h2o_socket_export_t { + int fd; + struct st_h2o_socket_ssl_t *ssl; + h2o_buffer_t *input; +} h2o_socket_export_t; + +/** + * sets the conditions to enable the optimization + */ +typedef struct st_h2o_socket_latency_optimization_conditions_t { + /** + * in milliseconds + */ + unsigned min_rtt; + /** + * percent ratio + */ + unsigned max_additional_delay; + /** + * in number of octets + */ + unsigned max_cwnd; +} h2o_socket_latency_optimization_conditions_t; + +typedef void (*h2o_socket_ssl_resumption_get_async_cb)(h2o_socket_t *sock, h2o_iovec_t session_id); +typedef void (*h2o_socket_ssl_resumption_new_cb)(h2o_iovec_t session_id, h2o_iovec_t session_data); +typedef void (*h2o_socket_ssl_resumption_remove_cb)(h2o_iovec_t session_id); + +extern h2o_buffer_mmap_settings_t h2o_socket_buffer_mmap_settings; +extern __thread h2o_buffer_prototype_t h2o_socket_buffer_prototype; + +extern const char *h2o_socket_error_out_of_memory; +extern const char *h2o_socket_error_io; +extern const char *h2o_socket_error_closed; +extern const char *h2o_socket_error_conn_fail; +extern const char *h2o_socket_error_ssl_no_cert; +extern const char *h2o_socket_error_ssl_cert_invalid; +extern const char *h2o_socket_error_ssl_cert_name_mismatch; +extern const char *h2o_socket_error_ssl_decode; + +/** + * returns the loop + */ +h2o_loop_t *h2o_socket_get_loop(h2o_socket_t *sock); +/** + * detaches a socket from loop. + */ +int h2o_socket_export(h2o_socket_t *sock, h2o_socket_export_t *info); +/** + * attaches a socket onto a loop. + */ +h2o_socket_t *h2o_socket_import(h2o_loop_t *loop, h2o_socket_export_t *info); +/** + * destroys an exported socket info. + */ +void h2o_socket_dispose_export(h2o_socket_export_t *info); +/** + * closes the socket + */ +void h2o_socket_close(h2o_socket_t *sock); +/** + * Schedules a callback to be notify we the socket can be written to + */ +void h2o_socket_notify_write(h2o_socket_t *sock, h2o_socket_cb cb); +/** + * Obtain the underlying fd of a sock struct + */ +int h2o_socket_get_fd(h2o_socket_t *sock); +/** + * Set/Unset the H2O_SOCKET_FLAG_DONT_READ flag. + * Setting it allows to be simply notified rather than having the data + * automatically be read. + */ +void h2o_socket_dont_read(h2o_socket_t *sock, int dont_read); +/** + * connects to peer + */ +h2o_socket_t *h2o_socket_connect(h2o_loop_t *loop, struct sockaddr *addr, socklen_t addrlen, h2o_socket_cb cb); +/** + * prepares for latency-optimized write and returns the number of octets that should be written, or SIZE_MAX if failed to prepare + */ +static size_t h2o_socket_prepare_for_latency_optimized_write(h2o_socket_t *sock, + const h2o_socket_latency_optimization_conditions_t *conditions); +size_t h2o_socket_do_prepare_for_latency_optimized_write(h2o_socket_t *sock, + const h2o_socket_latency_optimization_conditions_t *conditions); +/** + * writes given data to socket + * @param sock the socket + * @param bufs an array of buffers + * @param bufcnt length of the buffer array + * @param cb callback to be called when write is complete + */ +void h2o_socket_write(h2o_socket_t *sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb); +/** + * starts polling on the socket (for read) and calls given callback when data arrives + * @param sock the socket + * @param cb callback to be called when data arrives + * @note callback is called when any data arrives at the TCP level so that the + * applications can update their timeout counters. In other words, there is no + * guarantee that _new_ data is available when the callback gets called (e.g. + * in cases like receiving a partial SSL record or a corrupt TCP packet). + */ +void h2o_socket_read_start(h2o_socket_t *sock, h2o_socket_cb cb); +/** + * stops polling on the socket (for read) + * @param sock the socket + */ +void h2o_socket_read_stop(h2o_socket_t *sock); +/** + * returns a boolean value indicating whether if there is a write is under operation + */ +static int h2o_socket_is_writing(h2o_socket_t *sock); +/** + * returns a boolean value indicating whether if the socket is being polled for read + */ +static int h2o_socket_is_reading(h2o_socket_t *sock); +/** + * returns the length of the local address obtained (or 0 if failed) + */ +socklen_t h2o_socket_getsockname(h2o_socket_t *sock, struct sockaddr *sa); +/** + * returns the length of the remote address obtained (or 0 if failed) + */ +socklen_t h2o_socket_getpeername(h2o_socket_t *sock, struct sockaddr *sa); +/** + * sets the remote address (used for overriding the value) + */ +void h2o_socket_setpeername(h2o_socket_t *sock, struct sockaddr *sa, socklen_t len); +/** + * + */ +const char *h2o_socket_get_ssl_protocol_version(h2o_socket_t *sock); +int h2o_socket_get_ssl_session_reused(h2o_socket_t *sock); +const char *h2o_socket_get_ssl_cipher(h2o_socket_t *sock); +int h2o_socket_get_ssl_cipher_bits(h2o_socket_t *sock); +h2o_iovec_t h2o_socket_get_ssl_session_id(h2o_socket_t *sock); +static h2o_iovec_t h2o_socket_log_ssl_protocol_version(h2o_socket_t *sock, h2o_mem_pool_t *pool); +static h2o_iovec_t h2o_socket_log_ssl_session_reused(h2o_socket_t *sock, h2o_mem_pool_t *pool); +static h2o_iovec_t h2o_socket_log_ssl_cipher(h2o_socket_t *sock, h2o_mem_pool_t *pool); +h2o_iovec_t h2o_socket_log_ssl_cipher_bits(h2o_socket_t *sock, h2o_mem_pool_t *pool); +h2o_iovec_t h2o_socket_log_ssl_session_id(h2o_socket_t *sock, h2o_mem_pool_t *pool); + +/** + * compares socket addresses + */ +int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y); +/** + * getnameinfo (buf should be NI_MAXHOST in length), returns SIZE_MAX if failed + */ +size_t h2o_socket_getnumerichost(struct sockaddr *sa, socklen_t salen, char *buf); +/** + * returns the port number, or -1 if failed + */ +int32_t h2o_socket_getport(struct sockaddr *sa); +/** + * performs SSL handshake on a socket + * @param sock the socket + * @param ssl_ctx SSL context + * @param handshake_cb callback to be called when handshake is complete + */ +void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb); +/** + * resumes SSL handshake with given session data + * @param sock the socket + * @param session_data session data (or {NULL,0} if not available) + */ +void h2o_socket_ssl_resume_server_handshake(h2o_socket_t *sock, h2o_iovec_t session_data); +/** + * registers callbacks to be called for handling session data + */ +void h2o_socket_ssl_async_resumption_init(h2o_socket_ssl_resumption_get_async_cb get_cb, h2o_socket_ssl_resumption_new_cb new_cb); +/** + * setups the SSL context to use the async resumption + */ +void h2o_socket_ssl_async_resumption_setup_ctx(SSL_CTX *ctx); +/** + * returns the name of the protocol selected using either NPN or ALPN (ALPN has the precedence). + * @param sock the socket + */ +h2o_iovec_t h2o_socket_ssl_get_selected_protocol(h2o_socket_t *sock); +/** + * + */ +struct st_ptls_context_t *h2o_socket_ssl_get_picotls_context(SSL_CTX *ossl); +/** + * associates a picotls context to SSL_CTX + */ +void h2o_socket_ssl_set_picotls_context(SSL_CTX *ossl, struct st_ptls_context_t *ptls); +/** + * + */ +h2o_cache_t *h2o_socket_ssl_get_session_cache(SSL_CTX *ctx); +/** + * + */ +void h2o_socket_ssl_set_session_cache(SSL_CTX *ctx, h2o_cache_t *cache); +/** + * + */ +void h2o_socket_ssl_destroy_session_cache_entry(h2o_iovec_t value); +/** + * registers the protocol list to be used for ALPN + */ +void h2o_ssl_register_alpn_protocols(SSL_CTX *ctx, const h2o_iovec_t *protocols); +/** + * registers the protocol list to be used for NPN + */ +void h2o_ssl_register_npn_protocols(SSL_CTX *ctx, const char *protocols); + +void h2o_socket__write_pending(h2o_socket_t *sock); +void h2o_socket__write_on_complete(h2o_socket_t *sock, int status); + +/* inline defs */ + +inline int h2o_socket_is_writing(h2o_socket_t *sock) +{ + return sock->_cb.write != NULL; +} + +inline int h2o_socket_is_reading(h2o_socket_t *sock) +{ + return sock->_cb.read != NULL; +} + +inline size_t h2o_socket_prepare_for_latency_optimized_write(h2o_socket_t *sock, + const h2o_socket_latency_optimization_conditions_t *conditions) +{ + switch (sock->_latency_optimization.state) { + case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_TBD: + case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE: + return h2o_socket_do_prepare_for_latency_optimized_write(sock, conditions); + default: + return sock->_latency_optimization.suggested_write_size; + } +} + +inline h2o_iovec_t h2o_socket_log_ssl_protocol_version(h2o_socket_t *sock, h2o_mem_pool_t *pool) +{ + const char *s = h2o_socket_get_ssl_protocol_version(sock); + return s != NULL ? h2o_iovec_init(s, strlen(s)) : h2o_iovec_init(NULL, 0); +} + +inline h2o_iovec_t h2o_socket_log_ssl_session_reused(h2o_socket_t *sock, h2o_mem_pool_t *pool) +{ + switch (h2o_socket_get_ssl_session_reused(sock)) { + case 0: + return h2o_iovec_init(H2O_STRLIT("0")); + case 1: + return h2o_iovec_init(H2O_STRLIT("1")); + default: + return h2o_iovec_init(NULL, 0); + } +} + +inline h2o_iovec_t h2o_socket_log_ssl_cipher(h2o_socket_t *sock, h2o_mem_pool_t *pool) +{ + const char *s = h2o_socket_get_ssl_cipher(sock); + return s != NULL ? h2o_iovec_init(s, strlen(s)) : h2o_iovec_init(NULL, 0); +} + +inline int h2o_sliding_counter_is_running(h2o_sliding_counter_t *counter) +{ + return counter->cur.start_at != 0; +} + +inline void h2o_sliding_counter_start(h2o_sliding_counter_t *counter, uint64_t now) +{ + counter->cur.start_at = now; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/socket/evloop.h b/web/server/h2o/libh2o/include/h2o/socket/evloop.h new file mode 100644 index 000000000..61ff29a66 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/socket/evloop.h @@ -0,0 +1,74 @@ +/* + * 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. + */ +#ifndef h2o__evloop_h +#define h2o__evloop_h + +#include "h2o/linklist.h" + +#define H2O_SOCKET_FLAG_IS_DISPOSED 0x1 +#define H2O_SOCKET_FLAG_IS_READ_READY 0x2 +#define H2O_SOCKET_FLAG_IS_WRITE_NOTIFY 0x4 +#define H2O_SOCKET_FLAG_IS_POLLED_FOR_READ 0x8 +#define H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE 0x10 +#define H2O_SOCKET_FLAG_DONT_READ 0x20 +#define H2O_SOCKET_FLAG_IS_CONNECTING 0x40 +#define H2O_SOCKET_FLAG_IS_ACCEPTED_CONNECTION 0x80 +#define H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED 0x1000 + +typedef struct st_h2o_evloop_t { + struct st_h2o_evloop_socket_t *_pending_as_client; + struct st_h2o_evloop_socket_t *_pending_as_server; + struct { + struct st_h2o_evloop_socket_t *head; + struct st_h2o_evloop_socket_t **tail_ref; + } _statechanged; + uint64_t _now; + h2o_linklist_t _timeouts; /* list of h2o_timeout_t */ + h2o_sliding_counter_t exec_time_counter; +} h2o_evloop_t; + +typedef h2o_evloop_t h2o_loop_t; + +struct st_h2o_timeout_backend_properties_t { + char _dummy; /* sizeof(empty_struct) differs bet. C (GCC extension) and C++ */ +}; + +h2o_socket_t *h2o_evloop_socket_create(h2o_evloop_t *loop, int fd, int flags); +h2o_socket_t *h2o_evloop_socket_accept(h2o_socket_t *listener); + +h2o_evloop_t *h2o_evloop_create(void); +void h2o_evloop_destroy(h2o_evloop_t *loop); +int h2o_evloop_run(h2o_evloop_t *loop, int32_t max_wait); + +/* inline definitions */ + +static inline uint64_t h2o_now(h2o_evloop_t *loop) +{ + return loop->_now; +} + +static inline uint64_t h2o_evloop_get_execution_time(h2o_evloop_t *loop) +{ + return loop->exec_time_counter.average; +} + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/socket/uv-binding.h b/web/server/h2o/libh2o/include/h2o/socket/uv-binding.h new file mode 100644 index 000000000..ad2812293 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/socket/uv-binding.h @@ -0,0 +1,44 @@ +/* + * 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. + */ +#ifndef h2o__uv_binding_h +#define h2o__uv_binding_h + +#include <uv.h> + +#if !(defined(UV_VERSION_MAJOR) && UV_VERSION_MAJOR == 1) +#error "libh2o (libuv binding) requires libuv version 1.x.y" +#endif + +typedef uv_loop_t h2o_loop_t; + +struct st_h2o_timeout_backend_properties_t { + uv_timer_t timer; +}; + +h2o_socket_t *h2o_uv_socket_create(uv_stream_t *stream, uv_close_cb close_cb); + +static inline uint64_t h2o_now(uv_loop_t *loop) +{ + return uv_now(loop); +} + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/socketpool.h b/web/server/h2o/libh2o/include/h2o/socketpool.h new file mode 100644 index 000000000..cc4161df4 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/socketpool.h @@ -0,0 +1,120 @@ +/* + * 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. + */ +#ifndef h2o__socket_pool_h +#define h2o__socket_pool_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <pthread.h> +#include "h2o/linklist.h" +#include "h2o/multithread.h" +#include "h2o/socket.h" +#include "h2o/timeout.h" + +typedef enum en_h2o_socketpool_type_t { H2O_SOCKETPOOL_TYPE_NAMED, H2O_SOCKETPOOL_TYPE_SOCKADDR } h2o_socketpool_type_t; + +typedef struct st_h2o_socketpool_t { + + /* read-only vars */ + h2o_socketpool_type_t type; + struct { + h2o_iovec_t host; + union { + /* used to specify servname passed to getaddrinfo */ + h2o_iovec_t named_serv; + /* if type is sockaddr, the `host` is not resolved but is used for TLS SNI and hostname verification */ + struct { + struct sockaddr_storage bytes; + socklen_t len; + } sockaddr; + }; + } peer; + int is_ssl; + size_t capacity; + uint64_t timeout; /* in milliseconds (UINT64_MAX if not set) */ + struct { + h2o_loop_t *loop; + h2o_timeout_t timeout; + h2o_timeout_entry_t entry; + } _interval_cb; + + /* vars that are modified by multiple threads */ + struct { + size_t count; /* synchronous operations should be used to access the variable */ + pthread_mutex_t mutex; + h2o_linklist_t sockets; /* guarded by the mutex; list of struct pool_entry_t defined in socket/pool.c */ + } _shared; +} h2o_socketpool_t; + +typedef struct st_h2o_socketpool_connect_request_t h2o_socketpool_connect_request_t; + +typedef void (*h2o_socketpool_connect_cb)(h2o_socket_t *sock, const char *errstr, void *data); +/** + * initializes a socket loop + */ +void h2o_socketpool_init_by_address(h2o_socketpool_t *pool, struct sockaddr *sa, socklen_t salen, int is_ssl, size_t capacity); +/** + * initializes a socket loop + */ +void h2o_socketpool_init_by_hostport(h2o_socketpool_t *pool, h2o_iovec_t host, uint16_t port, int is_ssl, size_t capacity); +/** + * disposes of a socket loop + */ +void h2o_socketpool_dispose(h2o_socketpool_t *pool); +/** + * sets a close timeout for the sockets being pooled + */ +void h2o_socketpool_set_timeout(h2o_socketpool_t *pool, h2o_loop_t *loop, uint64_t msec); +/** + * connects to the peer (or returns a pooled connection) + */ +void h2o_socketpool_connect(h2o_socketpool_connect_request_t **req, h2o_socketpool_t *pool, h2o_loop_t *loop, + h2o_multithread_receiver_t *getaddr_receiver, h2o_socketpool_connect_cb cb, void *data); +/** + * cancels a connect request + */ +void h2o_socketpool_cancel_connect(h2o_socketpool_connect_request_t *req); +/** + * returns an idling socket to the socket pool + */ +int h2o_socketpool_return(h2o_socketpool_t *pool, h2o_socket_t *sock); +/** + * determines if a socket belongs to the socket pool + */ +static int h2o_socketpool_is_owned_socket(h2o_socketpool_t *pool, h2o_socket_t *sock); + +/* inline defs */ + +inline int h2o_socketpool_is_owned_socket(h2o_socketpool_t *pool, h2o_socket_t *sock) +{ + return sock->on_close.data == pool; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/string_.h b/web/server/h2o/libh2o/include/h2o/string_.h new file mode 100644 index 000000000..ca319e54a --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/string_.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu + * + * 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. + */ +#ifndef h2o__string_h +#define h2o__string_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> +#include <stdint.h> +#include <time.h> +#include "h2o/memory.h" + +#define H2O_STRLIT(s) (s), sizeof(s) - 1 + +#define H2O_INT16_LONGEST_STR "-32768" +#define H2O_UINT16_LONGEST_STR "65535" +#define H2O_INT32_LONGEST_STR "-2147483648" +#define H2O_UINT32_LONGEST_STR "4294967295" +#define H2O_INT64_LONGEST_STR "-9223372036854775808" +#define H2O_UINT64_LONGEST_STR "18446744073709551615" + +/** + * duplicates given string + * @param pool memory pool (or NULL to use malloc) + * @param s source string + * @param len length of the source string (the result of strlen(s) used in case len is SIZE_MAX) + * @return buffer pointing to the duplicated string (buf is NUL-terminated but the length does not include the NUL char) + */ +h2o_iovec_t h2o_strdup(h2o_mem_pool_t *pool, const char *s, size_t len); +/** + * variant of h2o_strdup that calls h2o_mem_alloc_shared + */ +h2o_iovec_t h2o_strdup_shared(h2o_mem_pool_t *pool, const char *s, size_t len); +/** + * duplicates given string appending '/' to the tail if not found + */ +h2o_iovec_t h2o_strdup_slashed(h2o_mem_pool_t *pool, const char *s, size_t len); +/** + * tr/A-Z/a-z/ + */ +static int h2o_tolower(int ch); +/** + * tr/A-Z/a-z/ + */ +static void h2o_strtolower(char *s, size_t len); +/** + * tr/a-z/A-Z/ + */ +static int h2o_toupper(int ch); +/** + * tr/a-z/A-Z/ + */ +static void h2o_strtoupper(char *s, size_t len); +/** + * tests if target string (target_len bytes long) is equal to test string (test_len bytes long) after being converted to lower-case + */ +static int h2o_lcstris(const char *target, size_t target_len, const char *test, size_t test_len); +/** + * turns the length of a string into the length of the same string encoded in base64 + */ +static size_t h2o_base64_encode_capacity(size_t len); +/** + * parses a positive number of return SIZE_MAX if failed + */ +size_t h2o_strtosize(const char *s, size_t len); +/** + * parses first positive number contained in *s or return SIZE_MAX if failed. + * *s will set to right after the number in string or right after the end of string. + */ +size_t h2o_strtosizefwd(char **s, size_t len); +/** + * base64 url decoder + */ +h2o_iovec_t h2o_decode_base64url(h2o_mem_pool_t *pool, const char *src, size_t len); +/** + * base64 encoder (note: the function emits trailing '\0') + */ +size_t h2o_base64_encode(char *dst, const void *src, size_t len, int url_encoded); +/** + * decodes hexadecimal string + */ +int h2o_hex_decode(void *dst, const char *src, size_t src_len); +/** + * encodes binary into a hexadecimal string (with '\0' appended at last) + */ +void h2o_hex_encode(char *dst, const void *src, size_t src_len); +/** + * URI-ecsapes given string (as defined in RFC 3986) + */ +h2o_iovec_t h2o_uri_escape(h2o_mem_pool_t *pool, const char *s, size_t l, const char *preserve_chars); +/** + * returns the extension portion of path + */ +h2o_iovec_t h2o_get_filext(const char *path, size_t len); +/** + * returns a vector with surrounding WS stripped + */ +h2o_iovec_t h2o_str_stripws(const char *s, size_t len); +/** + * returns the offset of given substring or SIZE_MAX if not found + */ +size_t h2o_strstr(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len); +/** + * + */ +const char *h2o_next_token(h2o_iovec_t *iter, int separator, size_t *element_len, h2o_iovec_t *value); +/** + * tests if string needle exists within a separator-separated string (for handling "#rule" of RFC 2616) + */ +int h2o_contains_token(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len, int separator); +/** + * HTML-escapes a string + * @param pool memory pool + * @param src source string + * @param len source length + * @return the escaped string, or the source itself if escape was not necessary + */ +h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len); +/** + * concatenates a list of iovecs (with NUL termination) + */ +#define h2o_concat(pool, ...) \ + h2o_concat_list(pool, (h2o_iovec_t[]){__VA_ARGS__}, sizeof((h2o_iovec_t[]){__VA_ARGS__}) / sizeof(h2o_iovec_t)) +h2o_iovec_t h2o_concat_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count); +/** + * emits a two-line string to buf that graphically points to given location within the source string + * @return 0 if successful + */ +int h2o_str_at_position(char *buf, const char *src, size_t src_len, int lineno, int column); + +int h2o__lcstris_core(const char *target, const char *test, size_t test_len); + +/* inline defs */ + +inline int h2o_tolower(int ch) +{ + return 'A' <= ch && ch <= 'Z' ? ch + 0x20 : ch; +} + +inline void h2o_strtolower(char *s, size_t len) +{ + for (; len != 0; ++s, --len) + *s = h2o_tolower(*s); +} + +inline int h2o_toupper(int ch) +{ + return 'a' <= ch && ch <= 'z' ? ch - 0x20 : ch; +} + +inline void h2o_strtoupper(char *s, size_t len) +{ + for (; len != 0; ++s, --len) + *s = h2o_toupper(*s); +} + +inline int h2o_lcstris(const char *target, size_t target_len, const char *test, size_t test_len) +{ + if (target_len != test_len) + return 0; + return h2o__lcstris_core(target, test, test_len); +} + +inline size_t h2o_base64_encode_capacity(size_t len) +{ + return (((len) + 2) / 3 * 4 + 1); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/time_.h b/web/server/h2o/libh2o/include/h2o/time_.h new file mode 100644 index 000000000..1bab3efab --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/time_.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 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. + */ +#ifndef h2o__time_h +#define h2o__time_h + +#include <stdint.h> +#include <sys/time.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define H2O_TIMESTR_RFC1123_LEN (sizeof("Sun, 06 Nov 1994 08:49:37 GMT") - 1) +#define H2O_TIMESTR_LOG_LEN (sizeof("29/Aug/2014:15:34:38 +0900") - 1) + +/** + * builds a RFC-1123 style date string + */ +void h2o_time2str_rfc1123(char *buf, struct tm *gmt); +/** + * converts HTTP-date to packed format (or returns UINT64_MAX on failure) + */ +int h2o_time_parse_rfc1123(const char *s, size_t len, struct tm *tm); +/** + * builds an Apache log-style date string + */ +void h2o_time2str_log(char *buf, time_t time); + +static inline int64_t h2o_timeval_subtract(struct timeval *from, struct timeval *until) +{ + int32_t delta_sec = (int32_t)until->tv_sec - (int32_t)from->tv_sec; + int32_t delta_usec = (int32_t)until->tv_usec - (int32_t)from->tv_usec; + int64_t delta = (int64_t)((int64_t)delta_sec * 1000 * 1000L) + delta_usec; + + return delta; +} + +static inline int h2o_timeval_is_null(struct timeval *tv) +{ + return tv->tv_sec == 0; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/timeout.h b/web/server/h2o/libh2o/include/h2o/timeout.h new file mode 100644 index 000000000..59e65f0c2 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/timeout.h @@ -0,0 +1,99 @@ +/* + * 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. + */ +#ifndef h2o__timeout_h +#define h2o__timeout_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include "h2o/linklist.h" +#include "h2o/socket.h" + +typedef struct st_h2o_timeout_entry_t h2o_timeout_entry_t; +typedef void (*h2o_timeout_cb)(h2o_timeout_entry_t *entry); + +/** + * an entry linked to h2o_timeout_t. + * Modules willing to use timeouts should embed this object as part of itself, and link it to a specific timeout by calling + * h2o_timeout_link. + */ +struct st_h2o_timeout_entry_t { + uint64_t registered_at; + h2o_timeout_cb cb; + h2o_linklist_t _link; +}; + +/** + * represents a collection of h2o_timeout_entry_t linked to a single timeout value + */ +typedef struct st_h2o_timeout_t { + uint64_t timeout; + h2o_linklist_t _link; + h2o_linklist_t _entries; /* link list of h2o_timeout_entry_t */ + struct st_h2o_timeout_backend_properties_t _backend; +} h2o_timeout_t; + +/** + * initializes and registers a timeout + * @param loop loop to which the timeout should be registered + * @param timeout the timeout structure to be initialized + * @param millis timeout in milliseconds + */ +void h2o_timeout_init(h2o_loop_t *loop, h2o_timeout_t *timeout, uint64_t millis); +/** + * + */ +void h2o_timeout_dispose(h2o_loop_t *loop, h2o_timeout_t *timeout); +/** + * activates a timeout entry, by linking it to a timeout + */ +void h2o_timeout_link(h2o_loop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry); +/** + * deactivates a timeout entry, by unlinking it from a timeout + */ +void h2o_timeout_unlink(h2o_timeout_entry_t *entry); +/** + * returns a boolean value indicating if the timeout is linked (i.e. active) or not + */ +static int h2o_timeout_is_linked(h2o_timeout_entry_t *entry); + +void h2o_timeout_run(h2o_loop_t *loop, h2o_timeout_t *timeout, uint64_t now); +uint64_t h2o_timeout_get_wake_at(h2o_linklist_t *timeouts); +void h2o_timeout__do_init(h2o_loop_t *loop, h2o_timeout_t *timeout); +void h2o_timeout__do_dispose(h2o_loop_t *loop, h2o_timeout_t *timeout); +void h2o_timeout__do_link(h2o_loop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry); +void h2o_timeout__do_post_callback(h2o_loop_t *loop); + +/* inline defs */ + +inline int h2o_timeout_is_linked(h2o_timeout_entry_t *entry) +{ + return h2o_linklist_is_linked(&entry->_link); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/token.h b/web/server/h2o/libh2o/include/h2o/token.h new file mode 100644 index 000000000..1946b8b74 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/token.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +/* DO NOT EDIT! generated by tokens.pl */ +#ifndef h2o__token_h +#define h2o__token_h + +#define H2O_TOKEN_AUTHORITY (h2o__tokens + 0) +#define H2O_TOKEN_METHOD (h2o__tokens + 1) +#define H2O_TOKEN_PATH (h2o__tokens + 2) +#define H2O_TOKEN_SCHEME (h2o__tokens + 3) +#define H2O_TOKEN_STATUS (h2o__tokens + 4) +#define H2O_TOKEN_ACCEPT (h2o__tokens + 5) +#define H2O_TOKEN_ACCEPT_CHARSET (h2o__tokens + 6) +#define H2O_TOKEN_ACCEPT_ENCODING (h2o__tokens + 7) +#define H2O_TOKEN_ACCEPT_LANGUAGE (h2o__tokens + 8) +#define H2O_TOKEN_ACCEPT_RANGES (h2o__tokens + 9) +#define H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN (h2o__tokens + 10) +#define H2O_TOKEN_AGE (h2o__tokens + 11) +#define H2O_TOKEN_ALLOW (h2o__tokens + 12) +#define H2O_TOKEN_AUTHORIZATION (h2o__tokens + 13) +#define H2O_TOKEN_CACHE_CONTROL (h2o__tokens + 14) +#define H2O_TOKEN_CACHE_DIGEST (h2o__tokens + 15) +#define H2O_TOKEN_CONNECTION (h2o__tokens + 16) +#define H2O_TOKEN_CONTENT_DISPOSITION (h2o__tokens + 17) +#define H2O_TOKEN_CONTENT_ENCODING (h2o__tokens + 18) +#define H2O_TOKEN_CONTENT_LANGUAGE (h2o__tokens + 19) +#define H2O_TOKEN_CONTENT_LENGTH (h2o__tokens + 20) +#define H2O_TOKEN_CONTENT_LOCATION (h2o__tokens + 21) +#define H2O_TOKEN_CONTENT_RANGE (h2o__tokens + 22) +#define H2O_TOKEN_CONTENT_TYPE (h2o__tokens + 23) +#define H2O_TOKEN_COOKIE (h2o__tokens + 24) +#define H2O_TOKEN_DATE (h2o__tokens + 25) +#define H2O_TOKEN_ETAG (h2o__tokens + 26) +#define H2O_TOKEN_EXPECT (h2o__tokens + 27) +#define H2O_TOKEN_EXPIRES (h2o__tokens + 28) +#define H2O_TOKEN_FROM (h2o__tokens + 29) +#define H2O_TOKEN_HOST (h2o__tokens + 30) +#define H2O_TOKEN_HTTP2_SETTINGS (h2o__tokens + 31) +#define H2O_TOKEN_IF_MATCH (h2o__tokens + 32) +#define H2O_TOKEN_IF_MODIFIED_SINCE (h2o__tokens + 33) +#define H2O_TOKEN_IF_NONE_MATCH (h2o__tokens + 34) +#define H2O_TOKEN_IF_RANGE (h2o__tokens + 35) +#define H2O_TOKEN_IF_UNMODIFIED_SINCE (h2o__tokens + 36) +#define H2O_TOKEN_KEEP_ALIVE (h2o__tokens + 37) +#define H2O_TOKEN_LAST_MODIFIED (h2o__tokens + 38) +#define H2O_TOKEN_LINK (h2o__tokens + 39) +#define H2O_TOKEN_LOCATION (h2o__tokens + 40) +#define H2O_TOKEN_MAX_FORWARDS (h2o__tokens + 41) +#define H2O_TOKEN_PROXY_AUTHENTICATE (h2o__tokens + 42) +#define H2O_TOKEN_PROXY_AUTHORIZATION (h2o__tokens + 43) +#define H2O_TOKEN_RANGE (h2o__tokens + 44) +#define H2O_TOKEN_REFERER (h2o__tokens + 45) +#define H2O_TOKEN_REFRESH (h2o__tokens + 46) +#define H2O_TOKEN_RETRY_AFTER (h2o__tokens + 47) +#define H2O_TOKEN_SERVER (h2o__tokens + 48) +#define H2O_TOKEN_SET_COOKIE (h2o__tokens + 49) +#define H2O_TOKEN_STRICT_TRANSPORT_SECURITY (h2o__tokens + 50) +#define H2O_TOKEN_TE (h2o__tokens + 51) +#define H2O_TOKEN_TRANSFER_ENCODING (h2o__tokens + 52) +#define H2O_TOKEN_UPGRADE (h2o__tokens + 53) +#define H2O_TOKEN_USER_AGENT (h2o__tokens + 54) +#define H2O_TOKEN_VARY (h2o__tokens + 55) +#define H2O_TOKEN_VIA (h2o__tokens + 56) +#define H2O_TOKEN_WWW_AUTHENTICATE (h2o__tokens + 57) +#define H2O_TOKEN_X_COMPRESS_HINT (h2o__tokens + 58) +#define H2O_TOKEN_X_FORWARDED_FOR (h2o__tokens + 59) +#define H2O_TOKEN_X_REPROXY_URL (h2o__tokens + 60) +#define H2O_TOKEN_X_TRAFFIC (h2o__tokens + 61) + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/tunnel.h b/web/server/h2o/libh2o/include/h2o/tunnel.h new file mode 100644 index 000000000..520de91cc --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/tunnel.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 Justin Zhu, DeNA Co., Ltd., Kazuho Oku + * + * 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. + */ +#ifndef h2o__tunnel_h +#define h2o__tunnel_h + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_h2o_tunnel_t h2o_tunnel_t; + +h2o_tunnel_t *h2o_tunnel_establish(h2o_context_t *ctx, h2o_socket_t *sock1, h2o_socket_t *sock2, h2o_timeout_t *timeout); +void h2o_tunnel_break(h2o_tunnel_t *tunnel); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/url.h b/web/server/h2o/libh2o/include/h2o/url.h new file mode 100644 index 000000000..231c9a263 --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/url.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2014,2015 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. + */ +#ifndef h2o__url_h +#define h2o__url_h + +#include <sys/un.h> +#include "h2o/memory.h" + +typedef struct st_h2o_url_scheme_t { + h2o_iovec_t name; + uint16_t default_port; +} h2o_url_scheme_t; + +extern const h2o_url_scheme_t H2O_URL_SCHEME_HTTP, H2O_URL_SCHEME_HTTPS; + +typedef struct st_h2o_url_t { + const h2o_url_scheme_t *scheme; + h2o_iovec_t authority; /* i.e. host:port */ + h2o_iovec_t host; + h2o_iovec_t path; + uint16_t _port; +} h2o_url_t; + +/** + * retrieves the port number from url + */ +static uint16_t h2o_url_get_port(const h2o_url_t *url); +/** + * removes "..", ".", decodes %xx from a path representation + * @param pool memory pool to be used in case the path contained references to directories + * @param path source path + * @param len source length + * @param returns offset of '?' within `path` if found, or SIZE_MAX if not + * @param indexes mapping the normalized version to the input version + * @return buffer pointing to source, or buffer pointing to an allocated chunk with normalized representation of the given path + */ +h2o_iovec_t h2o_url_normalize_path(h2o_mem_pool_t *pool, const char *path, size_t len, size_t *query_at, size_t **norm_indexes); +/** + * initializes URL object given scheme, authority, and path + * @param the output + * @param scheme scheme + * @param authority + * @param path + * @return 0 if successful + */ +static int h2o_url_init(h2o_url_t *url, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, h2o_iovec_t path); +/** + * parses absolute URL (either http or https) + */ +int h2o_url_parse(const char *url, size_t url_len, h2o_url_t *result); +/** + * parses relative URL + */ +int h2o_url_parse_relative(const char *url, size_t url_len, h2o_url_t *result); +/** + * parses the authority and returns the next position (i.e. start of path) + * @return pointer to the end of hostport if successful, or NULL if failed. *port becomes the specified port number or 65535 if not + */ +const char *h2o_url_parse_hostport(const char *s, size_t len, h2o_iovec_t *host, uint16_t *port); +/** + * resolves the URL (stored to `dest` as well as returning the stringified representation (always allocated using pool) + */ +h2o_iovec_t h2o_url_resolve(h2o_mem_pool_t *pool, const h2o_url_t *base, const h2o_url_t *relative, h2o_url_t *dest); +/** + * resolves the path part of the URL (both the arguments are modified; the result is h2o_concat(*base, *relative)) + */ +void h2o_url_resolve_path(h2o_iovec_t *base, h2o_iovec_t *relative); +/** + * stringifies the URL + */ +static h2o_iovec_t h2o_url_stringify(h2o_mem_pool_t *pool, const h2o_url_t *url); +/** + * copies a URL object (null-terminates all the string elements) + */ +void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src); +/** + * extracts sockaddr_un from host and returns NULL (or returns an error string if failed) + */ +const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa); +extern const char *h2o_url_host_to_sun_err_is_not_unix_socket; + +/* inline definitions */ + +inline int h2o_url_init(h2o_url_t *url, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, h2o_iovec_t path) +{ + if (h2o_url_parse_hostport(authority.base, authority.len, &url->host, &url->_port) != authority.base + authority.len) + return -1; + url->scheme = scheme; + url->authority = authority; + url->path = path; + return 0; +} + +inline uint16_t h2o_url_get_port(const h2o_url_t *url) +{ + return url->_port != 65535 ? url->_port : url->scheme->default_port; +} + +inline h2o_iovec_t h2o_url_stringify(h2o_mem_pool_t *pool, const h2o_url_t *url) +{ + h2o_url_t tmp; + return h2o_url_resolve(pool, url, NULL, &tmp); +} + +static inline int h2o_url_host_is_unix_path(h2o_iovec_t host) +{ + if (host.len < 5) { + return 0; + } + return h2o_memis(host.base, 5, H2O_STRLIT("unix:")); +} + +/** + * Compares to hostnames, taking into account whether they contain a + * unix path (the comparison will be case sensitive) or not. + */ +static inline int h2o_url_hosts_are_equal(const h2o_url_t *url_a, const h2o_url_t *url_b) +{ + if (url_a->host.len != url_b->host.len) + return 0; + + if (h2o_url_host_is_unix_path(url_a->host)) + return h2o_memis(url_a->host.base, url_a->host.len, url_b->host.base, url_b->host.len); + else + return h2o_lcstris(url_a->host.base, url_a->host.len, url_b->host.base, url_b->host.len); +} + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/version.h b/web/server/h2o/libh2o/include/h2o/version.h new file mode 100644 index 000000000..0299197af --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/version.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014,2015 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. + */ +#ifndef h2o__version_h +#define h2o__version_h + +#define H2O_VERSION "2.2.6" + +#define H2O_VERSION_MAJOR 2 +#define H2O_VERSION_MINOR 2 +#define H2O_VERSION_PATCH 6 + +#define H2O_LIBRARY_VERSION_MAJOR 0 +#define H2O_LIBRARY_VERSION_MINOR 13 +#define H2O_LIBRARY_VERSION_PATCH 6 + +#endif diff --git a/web/server/h2o/libh2o/include/h2o/websocket.h b/web/server/h2o/libh2o/include/h2o/websocket.h new file mode 100644 index 000000000..96e047ada --- /dev/null +++ b/web/server/h2o/libh2o/include/h2o/websocket.h @@ -0,0 +1,58 @@ +/* + * 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. + */ +#ifndef h2o__websocket_h +#define h2o__websocket_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <wslay/wslay.h> +#include "h2o.h" +#include "h2o/http1.h" + +typedef struct st_h2o_websocket_conn_t h2o_websocket_conn_t; + +/* arg is NULL if the connection has been closed */ +typedef void (*h2o_websocket_msg_callback)(h2o_websocket_conn_t *conn, const struct wslay_event_on_msg_recv_arg *arg); + +struct st_h2o_websocket_conn_t { + h2o_socket_t *sock; + wslay_event_context_ptr ws_ctx; + struct wslay_event_callbacks ws_callbacks; + void *data; + h2o_websocket_msg_callback cb; + void *_write_buf; +}; + +int h2o_is_websocket_handshake(h2o_req_t *req, const char **client_key); +void h2o_websocket_create_accept_key(char *dst, const char *client_key); +h2o_websocket_conn_t *h2o_upgrade_to_websocket(h2o_req_t *req, const char *client_key, void *user_data, + h2o_websocket_msg_callback msg_cb); +void h2o_websocket_close(h2o_websocket_conn_t *conn); +void h2o_websocket_proceed(h2o_websocket_conn_t *conn); + +#ifdef __cplusplus +} +#endif + +#endif |