Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement http client for mruby handler #637

Merged
merged 39 commits into from
Dec 27, 2015
Merged
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2105973
mruby: support env[rack.input]
takahashim Sep 18, 2015
f5c41da
clang-format
kazuho Dec 23, 2015
66677d3
run the Rack handler in fiber
kazuho Dec 23, 2015
f48b355
add failing test
kazuho Dec 23, 2015
f5d9ccd
capture exceptions in fiber context and send to C-side
kazuho Dec 23, 2015
e2f6d9e
implement HTTP client; it works!
kazuho Dec 23, 2015
bf3e566
remove unnecessary prefix
kazuho Dec 24, 2015
0238171
simplify the way exceptions are reported (partially reverts f5d9ccd)
kazuho Dec 24, 2015
9438306
send headers
kazuho Dec 24, 2015
a990c58
no need to lowercase header name supplied by http1client
kazuho Dec 24, 2015
a077740
alter the response structure of `http_request` to match that of Rack
kazuho Dec 24, 2015
56625f3
retain reference to fiber in the mruby handler to allow overlapping r…
kazuho Dec 25, 2015
3d8c30b
cache the fiber for performance (61k reqs => 67k reqs/sec-thread on M…
kazuho Dec 25, 2015
adbc759
Merge branch 'master' into pr/515
kazuho Dec 25, 2015
a7ea741
extract https://github.com/kazuho/mruby-input-stream @ f4acc9f at dep…
kazuho Dec 25, 2015
ff5fbd1
mv deps/mruby-input-steam deps/mruby-input-stream
kazuho Dec 25, 2015
0a01e40
use the prototype defined in mruby_input_stream.h
kazuho Dec 25, 2015
86ea02f
extract https://github.com/kazuho/mruby-input-stream @ a849db8 at dep…
kazuho Dec 25, 2015
05efce2
manage the request body zero-copy
kazuho Dec 25, 2015
ecf166e
add tests
kazuho Dec 25, 2015
3be2a08
update copyright
kazuho Dec 25, 2015
f4a70d1
Merge branch 'kazuho/pr/515' into kazuho/mruby-fiber
kazuho Dec 25, 2015
d74cec6
fix the number of threads to one to feed all requests to a single mru…
kazuho Dec 25, 2015
717e030
Merge branch 'kazuho/pr/515' into kazuho/mruby-fiber
kazuho Dec 25, 2015
f7028a5
set MRB_INT64 on 64-bit system
kazuho Dec 25, 2015
9ebe49e
turn off debug option of mruby
kazuho Dec 25, 2015
bc90d3e
add request body to http_request (with zero-copy optimization)
kazuho Dec 25, 2015
36a08d5
suppress compiler warning
kazuho Dec 25, 2015
9a831f6
drop content-length and transfer-encoding header; without doing so, r…
kazuho Dec 26, 2015
953e28b
add tests
kazuho Dec 26, 2015
a41aebd
extract https://github.com/kazuho/mruby-input-stream @ bbb68bc at dep…
kazuho Dec 26, 2015
a220ea9
respect the input stream position when posting the content using fast…
kazuho Dec 26, 2015
3256797
fix compiler warnings caused by f7028a5
kazuho Dec 26, 2015
c09c330
drop special headers (`connection`, `transfer-encoding`, etc.); corre…
kazuho Dec 27, 2015
11bbc6a
suppress compiler warning
kazuho Dec 27, 2015
eedec09
apply workaround for https://github.com/mruby/mruby/issues/3063
kazuho Dec 27, 2015
a6b6dfb
create generator (and thereby avoid unnecessary copy in `h2o_send_inl…
kazuho Dec 27, 2015
8794973
cancel operation when `h2o_req_t` gets disposed
kazuho Dec 27, 2015
6ceb21f
drop `content-length` header sent from rack app, and set ourselves
kazuho Dec 27, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add request body to http_request (with zero-copy optimization)
  • Loading branch information
kazuho committed Dec 25, 2015
commit bc90d3ef3075475bfaf736bf612080aeb45641e3
96 changes: 70 additions & 26 deletions lib/handler/mruby/http_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@

struct st_h2o_mruby_http_request_context_t {
h2o_mruby_request_t *rreq;
h2o_buffer_t *req_buf;
struct {
h2o_buffer_t *buf;
h2o_iovec_t body; /* body.base != NULL indicates that post content exists (and the length MAY be zero) */
int method_is_head : 1;
int has_transfer_encoding : 1;
} req;
struct {
int status;
struct phr_header *headers;
Expand Down Expand Up @@ -137,10 +142,12 @@ static h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char
return NULL;
}

*reqbufs = h2o_mem_alloc_pool(&ctx->rreq->req->pool, sizeof(**reqbufs));
**reqbufs = h2o_iovec_init(ctx->req_buf->bytes, ctx->req_buf->size);
*reqbufs = h2o_mem_alloc_pool(&ctx->rreq->req->pool, sizeof(**reqbufs) * 2);
**reqbufs = h2o_iovec_init(ctx->req.buf->bytes, ctx->req.buf->size);
*reqbufcnt = 1;
*method_is_head = ctx->req_buf->size >= 5 && memcmp(ctx->req_buf->bytes, "HEAD ", 5) == 0;
if (ctx->req.body.base != NULL)
(*reqbufs)[(*reqbufcnt)++] = ctx->req.body;
*method_is_head = ctx->req.method_is_head;
return on_head;
}

Expand All @@ -150,15 +157,21 @@ static inline void append_to_buffer(h2o_buffer_t **buf, const void *src, size_t
(*buf)->size += len;
}

static int flatten_request_header(h2o_mruby_context_t *handler_ctx, h2o_iovec_t name, h2o_iovec_t value, void *_req_buf)
static int flatten_request_header(h2o_mruby_context_t *handler_ctx, h2o_iovec_t name, h2o_iovec_t value, void *_ctx)
{
h2o_buffer_t **req_buf = _req_buf;
struct st_h2o_mruby_http_request_context_t *ctx = _ctx;

if (h2o_lcstris(name.base, name.len, H2O_STRLIT("content-length"))) {
return 0; /* ignored */
} else if (h2o_lcstris(name.base, name.len, H2O_STRLIT("transfer-encoding"))) {
ctx->req.has_transfer_encoding = 1;
}

h2o_buffer_reserve(req_buf, name.len + value.len + sizeof(": \r\n") - 1);
append_to_buffer(req_buf, name.base, name.len);
append_to_buffer(req_buf, H2O_STRLIT(": "));
append_to_buffer(req_buf, value.base, value.len);
append_to_buffer(req_buf, H2O_STRLIT("\r\n"));
h2o_buffer_reserve(&ctx->req.buf, name.len + value.len + sizeof(": \r\n") - 1);
append_to_buffer(&ctx->req.buf, name.base, name.len);
append_to_buffer(&ctx->req.buf, H2O_STRLIT(": "));
append_to_buffer(&ctx->req.buf, value.base, value.len);
append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n"));

return 0;
}
Expand All @@ -170,7 +183,10 @@ mrb_value h2o_mruby_http_request_callback(h2o_mruby_request_t *rreq, mrb_value i
h2o_url_t url;

ctx->rreq = rreq;
h2o_buffer_init(&ctx->req_buf, &h2o_socket_buffer_prototype);
h2o_buffer_init(&ctx->req.buf, &h2o_socket_buffer_prototype);
ctx->req.body = h2o_iovec_init(NULL, 0);
ctx->req.method_is_head = 0;
ctx->req.has_transfer_encoding = 0;

if (!mrb_array_p(input)) {
mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "http_request: unexpected input"));
Expand All @@ -181,9 +197,11 @@ mrb_value h2o_mruby_http_request_callback(h2o_mruby_request_t *rreq, mrb_value i
mrb_value method = mrb_str_to_str(mrb, mrb_ary_entry(input, 0));
if (mrb->exc != NULL)
goto RaiseException;
h2o_buffer_reserve(&ctx->req_buf, RSTRING_LEN(method) + 1);
append_to_buffer(&ctx->req_buf, RSTRING_PTR(method), RSTRING_LEN(method));
append_to_buffer(&ctx->req_buf, H2O_STRLIT(" "));
h2o_buffer_reserve(&ctx->req.buf, RSTRING_LEN(method) + 1);
append_to_buffer(&ctx->req.buf, RSTRING_PTR(method), RSTRING_LEN(method));
append_to_buffer(&ctx->req.buf, H2O_STRLIT(" "));
if (h2o_memis(RSTRING_PTR(method), RSTRING_LEN(method), H2O_STRLIT("HEAD")))
ctx->req.method_is_head = 1;
}
{ /* uri */
mrb_value t = mrb_str_to_str(mrb, mrb_ary_entry(input, 1));
Expand All @@ -198,31 +216,57 @@ mrb_value h2o_mruby_http_request_callback(h2o_mruby_request_t *rreq, mrb_value i
mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "scheme is not HTTP"));
goto RaiseException;
}
h2o_buffer_reserve(&ctx->req_buf,
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"));
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 */
mrb_value headers = mrb_ary_entry(input, 2);
if (!mrb_nil_p(headers)) {
if (h2o_mruby_iterate_headers(rreq->ctx, headers, flatten_request_header, &ctx->req_buf) != 0)
if (h2o_mruby_iterate_headers(rreq->ctx, headers, flatten_request_header, ctx) != 0)
goto RaiseException;
}
}
h2o_buffer_reserve(&ctx->req_buf, 2);
append_to_buffer(&ctx->req_buf, H2O_STRLIT("\r\n"));
/* TODO handle body */
{ /* body */
mrb_value body = mrb_ary_entry(input, 3);
if (!mrb_nil_p(body)) {
if (mrb_obj_eq(mrb, body, rreq->rack_input)) {
/* fast path (FIXME respect seek) */
ctx->req.body = rreq->req->entity;
} else {
if (!mrb_string_p(body)) {
body = mrb_funcall(mrb, body, "read", 0);
if (mrb->exc != NULL)
goto RaiseException;
if (!mrb_string_p(body)) {
mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "body.read did not return string"));
goto RaiseException;
}
}
ctx->req.body = h2o_strdup(&ctx->rreq->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_buffer_link_to_pool(ctx->req_buf, &rreq->req->pool);
h2o_buffer_link_to_pool(ctx->req.buf, &rreq->req->pool);
h2o_http1client_connect(NULL, ctx, &rreq->req->conn->ctx->proxy.client_ctx, url.host, h2o_url_get_port(&url), on_connect);
return mrb_nil_value();

RaiseException:
h2o_buffer_dispose(&ctx->req_buf);
h2o_buffer_dispose(&ctx->req.buf);
{
mrb_value t = mrb_obj_value(mrb->exc);
mrb->exc = NULL;
Expand Down