static void on_read_proxy_line(h2o_socket_t *sock, int status) { struct st_h2o_accept_data_t *data = sock->data; if (status != 0) { free_accept_data(data); h2o_socket_close(sock); return; } struct sockaddr_storage addr; socklen_t addrlen; ssize_t r = parse_proxy_line(sock->input->bytes, sock->input->size, (void *)&addr, &addrlen); switch (r) { case -1: /* error, just pass the input to the next handler */ break; case -2: /* incomplete */ return; default: h2o_buffer_consume(&sock->input, r); if (addrlen != 0) h2o_socket_setpeername(sock, (void *)&addr, addrlen); break; } if (data->ctx->ssl_ctx != NULL) { h2o_socket_ssl_server_handshake(sock, data->ctx->ssl_ctx, on_ssl_handshake_complete); } else { h2o_accept_ctx_t *ctx = free_accept_data(data); sock->data = NULL; h2o_http1_accept(ctx, sock); } }
static void requests_status_per_thread(void *priv, h2o_context_t *ctx) { struct st_requests_status_ctx_t *rsc = priv; struct st_collect_req_status_cbdata_t cbdata = {rsc->logconf}; /* we encountered an error at init() time, return early */ if (rsc->logconf == NULL) return; h2o_buffer_init(&cbdata.buffer, &h2o_socket_buffer_prototype); ctx->globalconf->http1.callbacks.foreach_request(ctx, collect_req_status, &cbdata); ctx->globalconf->http2.callbacks.foreach_request(ctx, collect_req_status, &cbdata); /* concat JSON elements */ if (cbdata.buffer->size != 0) { #ifndef _MSC_VER pthread_mutex_lock(&rsc->mutex); #else uv_mutex_lock(&rsc->mutex); #endif if (rsc->req_data.len == 0) h2o_buffer_consume(&cbdata.buffer, 1); /* skip preceeding comma */ rsc->req_data.base = h2o_mem_realloc(rsc->req_data.base, rsc->req_data.len + cbdata.buffer->size); memcpy(rsc->req_data.base + rsc->req_data.len, cbdata.buffer->bytes, cbdata.buffer->size); rsc->req_data.len += cbdata.buffer->size; #ifndef _MSC_VER pthread_mutex_unlock(&rsc->mutex); #else uv_mutex_unlock(&rsc->mutex); #endif } h2o_buffer_dispose(&cbdata.buffer); }
static void do_proceed(h2o_generator_t *generator, h2o_req_t *req) { struct rp_generator_t *self = (void*)generator; h2o_buffer_consume(&self->buf_sending, self->buf_sending->size); do_send(self); }
static void on_read(h2o_socket_t *sock, int status) { if (status != 0) { fprintf(stderr, "pipe error\n"); abort(); } h2o_buffer_consume(&sock->input, sock->input->size); queue_cb(sock->data); }
static h2o_socket_t *do_steal_socket(h2o_httpclient_t *_client) { struct st_h2o_http1client_t *client = (void *)_client; h2o_socket_t *sock = client->sock; h2o_socket_read_stop(sock); h2o_buffer_consume(&sock->input, client->bytes_to_consume); client->bytes_to_consume = 0; client->sock = NULL; return sock; }
static void on_read(h2o_socket_t *sock, const char *err) { if (err != NULL) { fprintf(stderr, "pipe error\n"); abort(); } h2o_buffer_consume(&sock->input, sock->input->size); queue_cb(sock->data); }
static inline void on_websocket_upgrade(struct rp_generator_t *self, h2o_timeout_t *timeout, int rlen) { h2o_req_t *req = self->src_req; h2o_socket_t *sock = h2o_http1client_steal_socket(self->client); h2o_buffer_consume(&sock->input, rlen);//trash data after stealing sock. struct rp_ws_upgrade_info_t *info = h2o_mem_alloc(sizeof(*info)); info->upstream_sock = sock; info->timeout = timeout; info->ctx = req->conn->ctx; h2o_http1_upgrade(req, NULL, 0, on_websocket_upgrade_complete, info); }
static void on_websocket_upgrade_complete(void *_info, h2o_socket_t *sock, size_t reqsize) { struct rp_ws_upgrade_info_t *info = _info; if (sock != NULL) { h2o_buffer_consume(&sock->input, reqsize);//It is detached from conn. Let's trash unused data. h2o_tunnel_establish(info->ctx, sock, info->upstream_sock, info->timeout); } else { h2o_socket_close(info->upstream_sock); } free(info); }
static mrb_value build_chunk(struct st_h2o_mruby_http_request_context_t *ctx) { mrb_value chunk; assert(ctx->resp.has_content); if (ctx->client != NULL) { assert(ctx->client->sock->input->size != 0); chunk = mrb_str_new(ctx->generator->ctx->mrb, ctx->client->sock->input->bytes, ctx->client->sock->input->size); h2o_buffer_consume(&ctx->client->sock->input, ctx->client->sock->input->size); ctx->resp.has_content = 0; } else { if (ctx->resp.after_closed->size == 0) { chunk = mrb_nil_value(); } else { chunk = mrb_str_new(ctx->generator->ctx->mrb, ctx->resp.after_closed->bytes, ctx->resp.after_closed->size); h2o_buffer_consume(&ctx->resp.after_closed, ctx->resp.after_closed->size); } /* has_content is retained as true, so that repeated calls will return nil immediately */ } return chunk; }
static void on_complete(void *user_data, h2o_socket_t *sock, size_t reqsize) { h2o_websocket_conn_t *conn = user_data; /* close the connection on error */ if (sock == NULL) { (*conn->cb)(conn, NULL); return; } conn->sock = sock; sock->data = conn; h2o_buffer_consume(&sock->input, reqsize); h2o_websocket_proceed(conn); }
static ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *_conn) { h2o_websocket_conn_t *conn = _conn; /* return WOULDBLOCK if no data */ if (conn->sock->input->size == 0) { wslay_event_set_error(conn->ws_ctx, WSLAY_ERR_WOULDBLOCK); return -1; } if (conn->sock->input->size < len) len = conn->sock->input->size; memcpy(buf, conn->sock->input->bytes, len); h2o_buffer_consume(&conn->sock->input, len); return len; }
static void on_send_complete(h2o_socket_t *sock, int status) { struct st_h2o_http1_conn_t *conn = sock->data; assert(conn->req._ostr_top == &conn->_ostr_final.super); if (!conn->req.http1_is_persistent) { /* TODO use lingering close */ close_connection(conn); return; } /* handle next request */ init_request(conn, 1); h2o_buffer_consume(&conn->sock->input, conn->_reqsize); conn->_prevreqlen = 0; conn->_reqsize = 0; reqread_start(conn); }
static void on_req_body_done(h2o_socket_t *sock, const char *err) { struct st_h2o_http1client_t *client = sock->data; if (client->_body_buf_in_flight != NULL) { client->proceed_req(&client->super, client->_body_buf_in_flight->size, client->_body_buf_is_done); h2o_buffer_consume(&client->_body_buf_in_flight, client->_body_buf_in_flight->size); } if (err) { on_send_request(client->sock, err); return; } if (client->_body_buf != NULL && client->_body_buf->size != 0) do_write_req(&client->super, h2o_iovec_init(NULL, 0), client->_body_buf_is_done); else if (client->_body_buf_is_done) on_send_request(client->sock, NULL); }
static void close_client(struct st_h2o_http1client_t *client) { if (client->sock != NULL) { if (client->super.connpool != NULL && client->_do_keepalive) { /* we do not send pipelined requests, and thus can trash all the received input at the end of the request */ h2o_buffer_consume(&client->sock->input, client->sock->input->size); h2o_socketpool_return(client->super.connpool->socketpool, client->sock); } else { h2o_socket_close(client->sock); } } if (h2o_timer_is_linked(&client->super._timeout)) h2o_timer_unlink(&client->super._timeout); if (client->_body_buf != NULL) h2o_buffer_dispose(&client->_body_buf); if (client->_body_buf_in_flight != NULL) h2o_buffer_dispose(&client->_body_buf_in_flight); free(client); }
static int read_bio(BIO *b, char *out, int len) { h2o_socket_t *sock = b->ptr; if (len == 0) return 0; if (sock->ssl->input.encrypted->size == 0) { BIO_set_retry_read(b); return -1; } if (sock->ssl->input.encrypted->size < len) { len = (int)sock->ssl->input.encrypted->size; } memcpy(out, sock->ssl->input.encrypted->bytes, len); h2o_buffer_consume(&sock->ssl->input.encrypted, len); return len; }
static int on_body(h2o_http1client_t *client, const char *errstr) { if (errstr != NULL && errstr != h2o_http1client_error_is_eos) { fprintf(stderr, "%s\n", errstr); exit(1); return -1; } fwrite(client->sock->input->bytes, 1, client->sock->input->size, stdout); h2o_buffer_consume(&client->sock->input, client->sock->input->size); if (errstr == h2o_http1client_error_is_eos) { if (--cnt_left != 0) { /* next attempt */ h2o_mempool_clear(&pool); start_request(client->ctx); } } return 0; }
static void on_write_complete(h2o_socket_t *sock, const char *err) { struct st_h2o_tunnel_t *tunnel = sock->data; h2o_socket_t *peer; assert(tunnel != NULL); assert(tunnel->sock[0] == sock || tunnel->sock[1] == sock); if (err != NULL) { close_connection(tunnel); return; } reset_timeout(tunnel); if (tunnel->sock[0] == sock) peer = tunnel->sock[1]; else peer = tunnel->sock[0]; h2o_buffer_consume(&peer->input, peer->input->size); h2o_socket_read_start(peer, on_read); }
static void on_head(h2o_socket_t *sock, const char *err) { struct st_h2o_http1client_t *client = sock->data; int minor_version, version, http_status, rlen, is_eos; const char *msg; #define MAX_HEADERS 100 h2o_header_t *headers; h2o_iovec_t *header_names; size_t msg_len, num_headers, i; h2o_socket_cb reader; h2o_timer_unlink(&client->super._timeout); if (err != NULL) { on_error_before_head(client, "I/O error (head)"); return; } headers = h2o_mem_alloc_pool(client->super.pool, *headers, MAX_HEADERS); header_names = h2o_mem_alloc_pool(client->super.pool, *header_names, MAX_HEADERS); /* continue parsing the responses until we see a final one */ while (1) { /* parse response */ struct phr_header src_headers[MAX_HEADERS]; num_headers = MAX_HEADERS; rlen = phr_parse_response(sock->input->bytes, sock->input->size, &minor_version, &http_status, &msg, &msg_len, src_headers, &num_headers, 0); switch (rlen) { case -1: /* error */ on_error_before_head(client, "failed to parse the response"); return; case -2: /* incomplete */ h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout); return; } version = 0x100 | (minor_version != 0); /* fill-in the headers */ for (i = 0; i != num_headers; ++i) { const h2o_token_t *token; char *orig_name = h2o_strdup(client->super.pool, src_headers[i].name, src_headers[i].name_len).base; h2o_strtolower((char *)src_headers[i].name, src_headers[i].name_len); token = h2o_lookup_token(src_headers[i].name, src_headers[i].name_len); if (token != NULL) { headers[i].name = (h2o_iovec_t *)&token->buf; } else { header_names[i] = h2o_iovec_init(src_headers[i].name, src_headers[i].name_len); headers[i].name = &header_names[i]; } headers[i].value = h2o_iovec_init(src_headers[i].value, src_headers[i].value_len); headers[i].orig_name = orig_name; headers[i].flags = (h2o_header_flags_t){0}; } if (!(100 <= http_status && http_status <= 199 && http_status != 101)) break; if (client->super.informational_cb != NULL && client->super.informational_cb(&client->super, version, http_status, h2o_iovec_init(msg, msg_len), headers, num_headers) != 0) { close_client(client); return; } h2o_buffer_consume(&client->sock->input, rlen); if (client->sock->input->size == 0) { h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout); return; } } client->super.timings.response_start_at = h2o_gettimeofday(client->super.ctx->loop); /* parse the headers */ reader = on_body_until_close; client->_do_keepalive = minor_version >= 1; for (i = 0; i != num_headers; ++i) { if (headers[i].name == &H2O_TOKEN_CONNECTION->buf) { if (h2o_contains_token(headers[i].value.base, headers[i].value.len, H2O_STRLIT("keep-alive"), ',')) { client->_do_keepalive = 1; } else { client->_do_keepalive = 0; } } else if (headers[i].name == &H2O_TOKEN_TRANSFER_ENCODING->buf) { if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("chunked"))) { /* precond: _body_decoder.chunked is zero-filled */ client->_body_decoder.chunked.decoder.consume_trailer = 1; reader = on_req_chunked; } else if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("identity"))) { /* continue */ } else { on_error_before_head(client, "unexpected type of transfer-encoding"); return; } } else if (headers[i].name == &H2O_TOKEN_CONTENT_LENGTH->buf) { if ((client->_body_decoder.content_length.bytesleft = h2o_strtosize(headers[i].value.base, headers[i].value.len)) == SIZE_MAX) { on_error_before_head(client, "invalid content-length"); return; } if (reader != on_req_chunked) reader = on_body_content_length; } } /* RFC 2616 4.4 */ if (client->_method_is_head || http_status == 101 || http_status == 204 || http_status == 304) { is_eos = 1; client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop); } else { is_eos = 0; /* close the connection if impossible to determine the end of the response (RFC 7230 3.3.3) */ if (reader == on_body_until_close) client->_do_keepalive = 0; } /* call the callback. sock may be stealed */ client->bytes_to_consume = rlen; client->super._cb.on_body = client->super._cb.on_head(&client->super, is_eos ? h2o_httpclient_error_is_eos : NULL, version, http_status, h2o_iovec_init(msg, msg_len), headers, num_headers, 1); if (is_eos) { close_client(client); return; } else if (client->super._cb.on_body == NULL) { client->_do_keepalive = 0; close_client(client); return; } h2o_buffer_consume(&sock->input, client->bytes_to_consume); client->bytes_to_consume = 0; client->sock->bytes_read = client->sock->input->size; client->super._timeout.cb = on_body_timeout; h2o_socket_read_start(sock, reader); reader(client->sock, 0); #undef MAX_HEADERS }
static void proceed_handshake(h2o_socket_t *sock, const char *err) { h2o_iovec_t first_input = {NULL}; int ret; sock->_cb.write = NULL; if (err != NULL) { goto Complete; } if (sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_RECORD) { if (sock->ssl->input.encrypted->size <= 1024) { /* retain a copy of input if performing async resumption */ first_input = h2o_iovec_init(alloca(sock->ssl->input.encrypted->size), sock->ssl->input.encrypted->size); memcpy(first_input.base, sock->ssl->input.encrypted->bytes, first_input.len); } else { sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; } } Redo: if (SSL_is_server(sock->ssl->ssl)) { ret = SSL_accept(sock->ssl->ssl); } else { ret = SSL_connect(sock->ssl->ssl); } switch (sock->ssl->handshake.server.async_resumption.state) { case ASYNC_RESUMPTION_STATE_RECORD: /* async resumption has not been triggered; proceed the state to complete */ sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; break; case ASYNC_RESUMPTION_STATE_REQUEST_SENT: { /* sent async request, reset the ssl state, and wait for async response */ assert(ret < 0); SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(sock->ssl->ssl); SSL_free(sock->ssl->ssl); create_ssl(sock, ssl_ctx); clear_output_buffer(sock->ssl); h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size); h2o_buffer_reserve(&sock->ssl->input.encrypted, first_input.len); memcpy(sock->ssl->input.encrypted->bytes, first_input.base, first_input.len); sock->ssl->input.encrypted->size = first_input.len; h2o_socket_read_stop(sock); return; } default: break; } if (ret == 0 || (ret < 0 && SSL_get_error(sock->ssl->ssl, ret) != SSL_ERROR_WANT_READ)) { /* failed */ long verify_result = SSL_get_verify_result(sock->ssl->ssl); if (verify_result != X509_V_OK) { err = X509_verify_cert_error_string(verify_result); } else { err = "ssl handshake failure"; } goto Complete; } if (sock->ssl->output.bufs.size != 0) { h2o_socket_read_stop(sock); flush_pending_ssl(sock, ret == 1 ? on_handshake_complete : proceed_handshake); } else { if (ret == 1) { if (!SSL_is_server(sock->ssl->ssl)) { X509 *cert = SSL_get_peer_certificate(sock->ssl->ssl); if (cert != NULL) { switch (validate_hostname(sock->ssl->handshake.client.server_name, cert)) { case MatchFound: /* ok */ break; case MatchNotFound: err = h2o_socket_error_ssl_cert_name_mismatch; break; default: err = h2o_socket_error_ssl_cert_invalid; break; } X509_free(cert); } else { err = h2o_socket_error_ssl_no_cert; } } goto Complete; } if (sock->ssl->input.encrypted->size != 0) goto Redo; h2o_socket_read_start(sock, proceed_handshake); } return; Complete: h2o_socket_read_stop(sock); on_handshake_complete(sock, err); }