Esempio n. 1
0
static void post_response(struct st_h2o_mruby_http_request_context_t *ctx, int status,
                          const h2o_http1client_header_t *headers_sorted, size_t num_headers)
{
    mrb_state *mrb = ctx->generator->ctx->shared->mrb;
    int gc_arena = mrb_gc_arena_save(mrb);
    size_t i;

    mrb_value resp = mrb_ary_new_capa(mrb, 3);

    /* set status */
    mrb_ary_set(mrb, resp, 0, mrb_fixnum_value(status));

    /* set headers */
    mrb_value headers_hash = mrb_hash_new_capa(mrb, (int)num_headers);
    for (i = 0; i < num_headers; ++i) {
        /* skip the headers, we determine the eos! */
        if (h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, H2O_STRLIT("content-length")) ||
            h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, H2O_STRLIT("transfer-encoding")))
            continue;
        /* build and set the hash entry */
        mrb_value k = mrb_str_new(mrb, headers_sorted[i].name, headers_sorted[i].name_len);
        mrb_value v = mrb_str_new(mrb, headers_sorted[i].value, headers_sorted[i].value_len);
        while (i + 1 < num_headers && h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, headers_sorted[i + 1].name,
                                                headers_sorted[i + 1].name_len)) {
            ++i;
            v = mrb_str_cat_lit(mrb, v, "\n");
            v = mrb_str_cat(mrb, v, headers_sorted[i].value, headers_sorted[i].value_len);
        }
        mrb_hash_set(mrb, headers_hash, k, v);
    }
    mrb_ary_set(mrb, resp, 1, headers_hash);

    /* set input stream */
    assert(mrb_nil_p(ctx->refs.input_stream));
    ctx->refs.input_stream = h2o_mruby_create_data_instance(
        mrb, mrb_ary_entry(ctx->generator->ctx->shared->constants, H2O_MRUBY_HTTP_INPUT_STREAM_CLASS), ctx, &input_stream_type);
    mrb_ary_set(mrb, resp, 2, ctx->refs.input_stream);

    if (mrb_nil_p(ctx->receiver)) {
        /* is async */
        mrb_funcall(mrb, ctx->refs.request, "_set_response", 1, resp);
        if (mrb->exc != NULL) {
            fprintf(stderr, "_set_response failed\n");
            abort();
        }
    } else {
        /* send response to the waiting receiver */
        h2o_mruby_run_fiber(ctx->generator, detach_receiver(ctx), resp, NULL);
    }

    mrb_gc_arena_restore(mrb, gc_arena);
}
Esempio n. 2
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;
}