void h2o_socket_ssl_server_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, h2o_socket_cb handshake_cb) { static BIO_METHOD bio_methods = {BIO_TYPE_FD, "h2o_socket", write_bio, read_bio, puts_bio, NULL, ctrl_bio, new_bio, free_bio, NULL}; BIO *bio; sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); bio = BIO_new(&bio_methods); bio->ptr = sock; bio->init = 1; sock->ssl->ssl = SSL_new(ssl_ctx); SSL_set_bio(sock->ssl->ssl, bio, bio); sock->ssl->handshake.cb = handshake_cb; proceed_handshake(sock, 0); }
static struct rp_generator_t *proxy_send_prepare(h2o_req_t *req, h2o_proxy_location_t *upstream, int keepalive) { struct rp_generator_t *self = h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose); self->super.proceed = do_proceed; self->super.stop = do_close; self->upstream = upstream; self->src_req = req; self->up_req.bufs[0] = build_request(req, upstream, keepalive); self->up_req.bufs[1] = req->entity; self->up_req.is_head = h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD")); h2o_buffer_init(&self->last_content_before_send, &h2o_socket_buffer_prototype); h2o_buffer_init(&self->buf_sending, &h2o_socket_buffer_prototype); return self; }
int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) { int respfds[2] = {-1, -1}; pid_t pid = -1; int mutex_locked = 0, ret = -1; h2o_buffer_init(resp, &h2o_socket_buffer_prototype); pthread_mutex_lock(&cloexec_mutex); mutex_locked = 1; /* create pipe for reading the result */ if (pipe(respfds) != 0) goto Exit; fcntl(respfds[0], F_SETFD, O_CLOEXEC); /* spawn */ int mapped_fds[] = {respfds[1], 1, /* stdout of the child process is read from the pipe */ -1}; if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1) goto Exit; close(respfds[1]); respfds[1] = -1; pthread_mutex_unlock(&cloexec_mutex); mutex_locked = 0; /* read the response from pipe */ while (1) { h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); ssize_t r; while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; if (r <= 0) break; (*resp)->size += r; } Exit: if (mutex_locked) pthread_mutex_unlock(&cloexec_mutex); if (pid != -1) { /* wait for the child to complete */ pid_t r; while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) ; if (r == pid) { /* success */ ret = 0; } } if (respfds[0] != -1) close(respfds[0]); if (respfds[1] != -1) close(respfds[1]); if (ret != 0) h2o_buffer_dispose(resp); return ret; }
void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb) { sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(ssl_ctx) != NULL) sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD; if (sock->ssl->input.encrypted->size != 0) proceed_handshake(sock, 0); else h2o_socket_read_start(sock, proceed_handshake); } else { sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; SSL_set_tlsext_host_name(sock->ssl->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
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); }
void h2o_socket_ssl_server_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, h2o_socket_cb handshake_cb) { static BIO_METHOD bio_methods = { BIO_TYPE_FD, "h2o_socket", write_bio, read_bio, puts_bio, NULL, ctrl_bio, new_bio, free_bio, NULL }; BIO *bio; sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); h2o_mem_init_pool(&sock->ssl->output.pool); bio = BIO_new(&bio_methods); bio->ptr = sock; bio->init = 1; sock->ssl->ssl = SSL_new(ssl_ctx); SSL_set_bio(sock->ssl->ssl, bio, bio); sock->ssl->handshake.cb = handshake_cb; proceed_handshake(sock, 0); }
h2o_http2_stream_t *h2o_http2_stream_open(h2o_http2_conn_t *conn, uint32_t stream_id, const h2o_http2_priority_t *priority, h2o_req_t *src_req) { h2o_http2_stream_t *stream = h2o_mem_alloc(sizeof(*stream)); /* init properties (other than req) */ memset(stream, 0, offsetof(h2o_http2_stream_t, req)); stream->stream_id = stream_id; if (src_req != NULL) stream->is_half_closed = 1; stream->_ostr_final.do_send = finalostream_send; stream->_ostr_final.start_pull = finalostream_start_pull; stream->state = H2O_HTTP2_STREAM_STATE_RECV_PSUEDO_HEADERS; h2o_http2_window_init(&stream->output_window, &conn->peer_settings); h2o_http2_window_init(&stream->input_window, &H2O_HTTP2_SETTINGS_HOST); memcpy(&stream->priority, priority, sizeof(stream->priority)); h2o_buffer_init(&stream->_req_body, &h2o_socket_buffer_prototype); /* init request */ h2o_init_request(&stream->req, &conn->super, src_req); stream->req.version = 0x200; if (src_req != NULL) memset(&stream->req.upgrade, 0, sizeof(stream->req.upgrade)); stream->req._ostr_top = &stream->_ostr_final; h2o_http2_conn_register_stream(conn, stream); return stream; }
static void on_connection_ready(struct st_h2o_http1client_t *client) { h2o_iovec_t proxy_protocol = h2o_iovec_init(NULL, 0); int chunked = 0; h2o_iovec_t connection_header = h2o_iovec_init(NULL, 0); h2o_httpclient_properties_t props = { &proxy_protocol, &chunked, &connection_header, }; h2o_iovec_t method; h2o_url_t url; h2o_header_t *headers; size_t num_headers; h2o_iovec_t body; client->super._cb.on_head = client->super._cb.on_connect(&client->super, NULL, &method, &url, (const h2o_header_t **)&headers, &num_headers, &body, &client->proceed_req, &props, client->_origin); if (client->super._cb.on_head == NULL) { close_client(client); return; } h2o_iovec_t reqbufs[3]; size_t reqbufcnt = 0; if (props.proxy_protocol->base != NULL) reqbufs[reqbufcnt++] = *props.proxy_protocol; reqbufs[reqbufcnt++] = build_request(client, method, url, *props.connection_header, headers, num_headers); client->_is_chunked = *props.chunked; client->_method_is_head = h2o_memis(method.base, method.len, H2O_STRLIT("HEAD")); if (client->proceed_req != NULL) { if (body.base != NULL) { h2o_buffer_init(&client->_body_buf, &h2o_socket_buffer_prototype); if (h2o_buffer_append(&client->_body_buf, body.base, body.len) == 0) { on_send_request(client->sock, "Internal error"); return; } } h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_req_body_done); } else { if (client->_is_chunked) { assert(body.base != NULL); reqbufcnt += encode_chunk(client, reqbufs + reqbufcnt, body); } else if (body.base != NULL) { reqbufs[reqbufcnt++] = body; } h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_send_request); } /* TODO no need to set the timeout if all data has been written into TCP sendbuf */ client->super._timeout.cb = on_send_timeout; h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout); client->super.timings.request_begin_at = h2o_gettimeofday(client->super.ctx->loop); }
void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb) { sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(ssl_ctx) != NULL) sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD; if (sock->ssl->input.encrypted->size != 0) proceed_handshake(sock, 0); else h2o_socket_read_start(sock, proceed_handshake); } else { h2o_cache_t *session_cache = h2o_socket_ssl_get_session_cache(ssl_ctx); if (session_cache != NULL) { struct sockaddr_storage sa; int32_t port; if (h2o_socket_getpeername(sock, (struct sockaddr *)&sa) != 0 && (port = h2o_socket_getport((struct sockaddr *)&sa)) != -1) { /* session cache is available */ h2o_iovec_t session_cache_key; session_cache_key.base = h2o_mem_alloc(strlen(server_name) + sizeof(":" H2O_UINT16_LONGEST_STR)); session_cache_key.len = sprintf(session_cache_key.base, "%s:%" PRIu16, server_name, (uint16_t)port); sock->ssl->handshake.client.session_cache = session_cache; sock->ssl->handshake.client.session_cache_key = session_cache_key; sock->ssl->handshake.client.session_cache_key_hash = h2o_cache_calchash(session_cache_key.base, session_cache_key.len); /* fetch from session cache */ h2o_cache_ref_t *cacheref = h2o_cache_fetch(session_cache, h2o_now(h2o_socket_get_loop(sock)), sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash); if (cacheref != NULL) { SSL_set_session(sock->ssl->ssl, (SSL_SESSION *)cacheref->value.base); h2o_cache_release(session_cache, cacheref); } } } sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; SSL_set_tlsext_host_name(sock->ssl->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) { int respfds[2] = {-1, -1}; posix_spawn_file_actions_t file_actions; pid_t pid = -1; int ret = -1; extern char **environ; h2o_buffer_init(resp, &h2o_socket_buffer_prototype); /* create pipe for reading the result */ if (pipe(respfds) != 0) goto Exit; /* spawn */ posix_spawn_file_actions_init(&file_actions); posix_spawn_file_actions_adddup2(&file_actions, respfds[1], 1); if ((errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, environ)) != 0) { pid = -1; goto Exit; } close(respfds[1]); respfds[1] = -1; /* read the response from pipe */ while (1) { h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); ssize_t r; while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; if (r <= 0) break; (*resp)->size += r; } Exit: if (pid != -1) { /* wait for the child to complete */ pid_t r; while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) ; if (r == pid) { /* success */ ret = 0; } } if (respfds[0] != -1) close(respfds[0]); if (respfds[1] != -1) close(respfds[1]); if (ret != 0) h2o_buffer_dispose(resp); return ret; }
static void check_flatten(h2o_hpack_header_table_t *header_table, h2o_res_t *res, const char *expected, size_t expected_len) { h2o_buffer_t *buf; h2o_http2_frame_t frame; h2o_buffer_init(&buf, &h2o_socket_buffer_prototype); h2o_hpack_flatten_headers(&buf, header_table, 1, H2O_HTTP2_SETTINGS_DEFAULT.max_frame_size, res, NULL, NULL); ok(h2o_http2_decode_frame(&frame, (uint8_t*)buf->bytes, buf->size, &H2O_HTTP2_SETTINGS_DEFAULT) > 0); ok(h2o_memis(frame.payload, frame.length, expected, expected_len)); h2o_buffer_dispose(&buf); }
static int on_body(h2o_http1client_t *client, const char *errstr) { struct rp_generator_t *self = client->data; /* FIXME should there be a way to notify error downstream? */ if (errstr != NULL) { /* detach the content */ self->last_content_before_send = self->client->sock->input; h2o_buffer_init(&self->client->sock->input, &h2o_socket_buffer_prototype); self->client = NULL; } if (self->buf_sending->size == 0) do_send(self); return 0; }
static int on_body(h2o_http1client_t *client, const char *errstr) { struct rp_generator_t *self = client->data; if (errstr != NULL) { /* detach the content */ self->last_content_before_send = self->client->sock->input; h2o_buffer_init(&self->client->sock->input, &h2o_socket_buffer_prototype); self->client = NULL; if (errstr != h2o_http1client_error_is_eos) { h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr); self->had_body_error = 1; } } if (self->sending.bytes_inflight == 0) do_send(self); return 0; }
int h2o_socket_export(h2o_socket_t *sock, h2o_socket_export_t *info) { static h2o_buffer_prototype_t nonpooling_prototype = {}; assert(!h2o_socket_is_writing(sock)); if (do_export(sock, info) == -1) return -1; if ((info->ssl = sock->ssl) != NULL) { sock->ssl = NULL; h2o_buffer_set_prototype(&info->ssl->input.encrypted, &nonpooling_prototype); } info->input = sock->input; h2o_buffer_set_prototype(&info->input, &nonpooling_prototype); h2o_buffer_init(&sock->input, &h2o_socket_buffer_prototype); h2o_socket_close(sock); return 0; }
static void on_shortcut_notify(h2o_mruby_generator_t *generator) { h2o_mruby_chunked_t *chunked = generator->chunked; int is_final; h2o_buffer_t **input = h2o_mruby_http_peek_content(chunked->shortcut.client, &is_final); /* trim data too long */ if (chunked->bytes_left != SIZE_MAX && chunked->bytes_left < (*input)->size) (*input)->size = chunked->bytes_left; /* if final, steal socket input buffer to shortcut.remaining, and reset pointer to client */ if (is_final) { chunked->shortcut.remaining = *input; h2o_buffer_init(input, &h2o_socket_buffer_prototype); input = &chunked->shortcut.remaining; chunked->shortcut.client = NULL; } if (chunked->sending.bytes_inflight == 0) do_send(generator, input, is_final); }
static struct rp_generator_t *proxy_send_prepare(h2o_req_t *req, int keepalive) { struct rp_generator_t *self = h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose); h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); self->super.proceed = do_proceed; self->super.stop = do_close; self->src_req = req; if (client_ctx->websocket_timeout != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("websocket"))) { self->is_websocket_handshake = 1; } else { self->is_websocket_handshake = 0; } self->up_req.bufs[0] = build_request(req, keepalive, self->is_websocket_handshake); self->up_req.bufs[1] = req->entity; self->up_req.is_head = h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD")); h2o_buffer_init(&self->last_content_before_send, &h2o_socket_buffer_prototype); h2o_doublebuffer_init(&self->sending, &h2o_socket_buffer_prototype); return self; }
mrb_value h2o_mruby_send_chunked_init(h2o_mruby_generator_t *generator, mrb_value body) { h2o_mruby_chunked_t *chunked = h2o_mem_alloc_pool(&generator->req->pool, sizeof(*chunked)); h2o_doublebuffer_init(&chunked->sending, &h2o_socket_buffer_prototype); chunked->bytes_left = h2o_memis(generator->req->method.base, generator->req->method.len, H2O_STRLIT("HEAD")) ? 0 : generator->req->res.content_length; generator->super.proceed = do_proceed; generator->chunked = chunked; if ((chunked->shortcut.client = h2o_mruby_http_set_shortcut(generator->ctx->shared->mrb, body, on_shortcut_notify)) != NULL) { chunked->type = H2O_MRUBY_CHUNKED_TYPE_SHORTCUT; chunked->shortcut.remaining = NULL; on_shortcut_notify(generator); return mrb_nil_value(); } else { chunked->type = H2O_MRUBY_CHUNKED_TYPE_CALLBACK; h2o_buffer_init(&chunked->callback.receiving, &h2o_socket_buffer_prototype); mrb_gc_register(generator->ctx->shared->mrb, body); chunked->callback.body_obj = body; return mrb_ary_entry(generator->ctx->shared->constants, H2O_MRUBY_CHUNKED_PROC_EACH_TO_FIBER); } }
static int do_write_req(h2o_httpclient_t *_client, h2o_iovec_t chunk, int is_end_stream) { struct st_h2o_http1client_t *client = (struct st_h2o_http1client_t *)_client; client->_body_buf_is_done = is_end_stream; if (client->_body_buf == NULL) h2o_buffer_init(&client->_body_buf, &h2o_socket_buffer_prototype); if (chunk.len != 0) { if (h2o_buffer_append(&client->_body_buf, chunk.base, chunk.len) == 0) return -1; } if (client->sock->_cb.write != NULL) return 0; assert(client->_body_buf_in_flight == NULL || client->_body_buf_in_flight->size == 0); swap_buffers(&client->_body_buf, &client->_body_buf_in_flight); if (client->_body_buf_in_flight->size == 0) { /* return immediately if the chunk is empty */ on_req_body_done(client->sock, NULL); return 0; } h2o_iovec_t iov = h2o_iovec_init(client->_body_buf_in_flight->bytes, client->_body_buf_in_flight->size); if (client->_is_chunked) { h2o_iovec_t bufs[3]; size_t bufcnt = encode_chunk(client, bufs, iov); h2o_socket_write(client->sock, bufs, bufcnt, on_req_body_done); } else { h2o_socket_write(client->sock, &iov, 1, on_req_body_done); } return 0; }
static mrb_value http_request_method(mrb_state *mrb, mrb_value self) { h2o_mruby_generator_t *generator; struct st_h2o_mruby_http_request_context_t *ctx; const char *arg_url; mrb_int arg_url_len; mrb_value arg_hash; h2o_iovec_t method; h2o_url_t url; /* parse args */ arg_hash = mrb_nil_value(); mrb_get_args(mrb, "s|H", &arg_url, &arg_url_len, &arg_hash); /* precond check */ if ((generator = h2o_mruby_current_generator) == NULL || generator->req == NULL) mrb_exc_raise(mrb, create_downstream_closed_exception(mrb)); /* allocate context and initialize */ ctx = h2o_mem_alloc_shared(&generator->req->pool, sizeof(*ctx), on_dispose); memset(ctx, 0, sizeof(*ctx)); ctx->generator = generator; ctx->receiver = mrb_nil_value(); h2o_buffer_init(&ctx->req.buf, &h2o_socket_buffer_prototype); h2o_buffer_init(&ctx->resp.after_closed, &h2o_socket_buffer_prototype); ctx->refs.request = mrb_nil_value(); ctx->refs.input_stream = mrb_nil_value(); /* uri */ if (h2o_url_parse(arg_url, arg_url_len, &url) != 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "invaild URL"); /* method */ method = h2o_iovec_init(H2O_STRLIT("GET")); if (mrb_hash_p(arg_hash)) { mrb_value t = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->symbols.sym_method)); if (!mrb_nil_p(t)) { t = mrb_str_to_str(mrb, t); method = h2o_iovec_init(RSTRING_PTR(t), RSTRING_LEN(t)); } } /* start building the request */ h2o_buffer_reserve(&ctx->req.buf, method.len + 1); append_to_buffer(&ctx->req.buf, method.base, method.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(" ")); h2o_buffer_reserve(&ctx->req.buf, url.path.len + url.authority.len + sizeof(" HTTP/1.1\r\nConnection: close\r\nHost: \r\n") - 1); append_to_buffer(&ctx->req.buf, url.path.base, url.path.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(" HTTP/1.1\r\nConnection: close\r\nHost: ")); append_to_buffer(&ctx->req.buf, url.authority.base, url.authority.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); /* headers */ if (mrb_hash_p(arg_hash)) { mrb_value headers = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->symbols.sym_headers)); if (!mrb_nil_p(headers)) { if (h2o_mruby_iterate_headers(generator->ctx, headers, flatten_request_header, ctx) != 0) { mrb_value exc = mrb_obj_value(mrb->exc); mrb->exc = NULL; mrb_exc_raise(mrb, exc); } } } /* body */ if (mrb_hash_p(arg_hash)) { mrb_value body = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->symbols.sym_body)); if (!mrb_nil_p(body)) { if (mrb_obj_eq(mrb, body, generator->rack_input)) { /* fast path */ mrb_int pos; mrb_input_stream_get_data(mrb, body, NULL, NULL, &pos, NULL, NULL); ctx->req.body = generator->req->entity; ctx->req.body.base += pos; ctx->req.body.len -= pos; } else { if (!mrb_string_p(body)) { body = mrb_funcall(mrb, body, "read", 0); if (!mrb_string_p(body)) mrb_raise(mrb, E_ARGUMENT_ERROR, "body.read did not return string"); } ctx->req.body = h2o_strdup(&ctx->generator->req->pool, RSTRING_PTR(body), RSTRING_LEN(body)); } if (!ctx->req.has_transfer_encoding) { char buf[64]; size_t l = (size_t)sprintf(buf, "content-length: %zu\r\n", ctx->req.body.len); h2o_buffer_reserve(&ctx->req.buf, l); append_to_buffer(&ctx->req.buf, buf, l); } } } h2o_buffer_reserve(&ctx->req.buf, 2); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); /* build request and connect */ h2o_http1client_connect(&ctx->client, ctx, &generator->req->conn->ctx->proxy.client_ctx, url.host, h2o_url_get_port(&url), on_connect); ctx->refs.request = h2o_mruby_create_data_instance(mrb, mrb_ary_entry(generator->ctx->constants, H2O_MRUBY_HTTP_REQUEST_CLASS), ctx, &request_type); return ctx->refs.request; }
int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) { int respfds[2] = {-1, -1}; pid_t pid = -1; int mutex_locked = 0, ret = -1; h2o_buffer_init(resp, &h2o_socket_buffer_prototype); #ifndef _MSC_VER pthread_mutex_lock(&cloexec_mutex); mutex_locked = 1; #else uv_mutex_lock(&cloexec_mutex); mutex_locked = 1; #endif /* create pipe for reading the result */ #ifdef _MSC_VER if (_pipe(respfds, 4096, O_BINARY) == -1) //on fail //-- : Debug{ //printf("Pipe Failed \n"); goto Exit; #else if (pipe(respfds) != 0) //on fail goto Exit; #endif #ifndef _MSC_VER fcntl(respfds[0], F_SETFD, O_CLOEXEC); #endif /* spawn */ int mapped_fds[] = {respfds[1], 1, /* stdout of the child process is read from the pipe */ -1}; if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1) goto Exit; close(respfds[1]); respfds[1] = -1; #ifndef _MSC_VER pthread_mutex_unlock(&cloexec_mutex); #else uv_mutex_unlock(&cloexec_mutex); #endif mutex_locked = 0; /* read the response from pipe */ while (1) { h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); ssize_t r; #ifndef _MSC_VER while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; #else while ((r = _read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; #endif if (r <= 0) break; (*resp)->size += r; } Exit: if (mutex_locked) #ifndef _MSC_VER pthread_mutex_unlock(&cloexec_mutex); #else uv_mutex_unlock(&cloexec_mutex); #endif //Child _ waiting doesn't work same way in Windows so #ifndef _MSC_VER if (pid != -1) { /* wait for the child to complete */ pid_t r; while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) ; if (r == pid) { /* success */ ret = 0; } } #else //If you can come up with a way to wait for a child to exist in Windows put here.s #endif #ifndef _MSC_VER if (respfds[0] != -1) close(respfds[0]); if (respfds[1] != -1) close(respfds[1]); #else if (respfds[0] != -1) _close(respfds[0]); if (respfds[1] != -1) _close(respfds[1]); #endif if (ret != 0) h2o_buffer_dispose(resp); return ret; }