static void on_ssl_handshake_complete(h2o_socket_t *sock, int status) { h2o_accept_ctx_t *ctx = free_accept_data(sock->data); sock->data = NULL; if (status != 0) { h2o_socket_close(sock); return; } h2o_iovec_t proto = h2o_socket_ssl_get_selected_protocol(sock); const h2o_iovec_t *ident; for (ident = h2o_http2_alpn_protocols; ident->len != 0; ++ident) { if (proto.len == ident->len && memcmp(proto.base, ident->base, proto.len) == 0) { goto Is_Http2; } } /* connect as http1 */ h2o_http1_accept(ctx, sock); return; Is_Http2: /* connect as http2 */ h2o_http2_accept(ctx, sock); }
static void on_ssl_handshake_complete(h2o_socket_t *sock, int status) { struct st_h2o_accept_data_t *data = sock->data; sock->data = NULL; if (status != 0) { h2o_socket_close(sock); goto Exit; } h2o_iovec_t proto = h2o_socket_ssl_get_selected_protocol(sock); const h2o_iovec_t *ident; for (ident = h2o_http2_alpn_protocols; ident->len != 0; ++ident) { if (proto.len == ident->len && memcmp(proto.base, ident->base, proto.len) == 0) { /* connect as http2 */ h2o_http2_accept(data->ctx, sock, data->connected_at); goto Exit; } } /* connect as http1 */ h2o_http1_accept(data->ctx, sock, data->connected_at); Exit: free_accept_data(data); }
static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) { size_t inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; int reqlen, minor_version; struct phr_header headers[H2O_MAX_HEADERS]; size_t num_headers = H2O_MAX_HEADERS; ssize_t entity_body_header_index; h2o_iovec_t expect; /* need to set request_begin_at here for keep-alive connection */ if (conn->req.timestamps.request_begin_at.tv_sec == 0) conn->req.timestamps.request_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); reqlen = phr_parse_request(conn->sock->input->bytes, inreqlen, (const char **)&conn->req.input.method.base, &conn->req.input.method.len, (const char **)&conn->req.input.path.base, &conn->req.input.path.len, &minor_version, headers, &num_headers, conn->_prevreqlen); conn->_prevreqlen = inreqlen; switch (reqlen) { default: // parse complete conn->_reqsize = reqlen; if ((entity_body_header_index = fixup_request(conn, headers, num_headers, minor_version, &expect)) != -1) { conn->req.timestamps.request_body_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); if (expect.base != NULL) { if (!h2o_lcstris(expect.base, expect.len, H2O_STRLIT("100-continue"))) { set_timeout(conn, NULL, NULL); h2o_socket_read_stop(conn->sock); h2o_send_error(&conn->req, 417, "Expectation Failed", "unknown expectation", H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION); return; } static const h2o_iovec_t res = {H2O_STRLIT("HTTP/1.1 100 Continue\r\n\r\n")}; h2o_socket_write(conn->sock, (void *)&res, 1, on_continue_sent); } if (create_entity_reader(conn, headers + entity_body_header_index) != 0) { return; } if (expect.base != NULL) { /* processing of the incoming entity is postponed until the 100 response is sent */ h2o_socket_read_stop(conn->sock); return; } conn->_req_entity_reader->handle_incoming_entity(conn); } else { set_timeout(conn, NULL, NULL); h2o_socket_read_stop(conn->sock); process_request(conn); } return; case -2: // incomplete if (inreqlen == H2O_MAX_REQLEN) { // request is too long (TODO notify) close_connection(conn, 1); } return; case -1: // error /* upgrade to HTTP/2 if the request starts with: PRI * HTTP/2 */ if (conn->super.ctx->globalconf->http1.upgrade_to_http2) { /* should check up to the first octet that phr_parse_request returns an error */ static const h2o_iovec_t HTTP2_SIG = {H2O_STRLIT("PRI * HTTP/2")}; if (conn->sock->input->size >= HTTP2_SIG.len && memcmp(conn->sock->input->bytes, HTTP2_SIG.base, HTTP2_SIG.len) == 0) { h2o_accept_ctx_t accept_ctx = {conn->super.ctx, conn->super.hosts}; h2o_socket_t *sock = conn->sock; struct timeval connected_at = conn->super.connected_at; /* destruct the connection after detatching the socket */ conn->sock = NULL; close_connection(conn, 1); /* and accept as http2 connection */ h2o_http2_accept(&accept_ctx, sock, connected_at); return; } } close_connection(conn, 1); return; } }