Beispiel #1
0
static struct rp_generator_t *proxy_send_prepare(h2o_req_t *req, int keepalive, int use_proxy_protocol)
{
    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->had_body_error = 0;
    self->up_req.bufs[0] = build_request(req, keepalive, self->is_websocket_handshake, use_proxy_protocol);
    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;
}
Beispiel #2
0
void h2o_get_timestamp(h2o_context_t *ctx, h2o_mem_pool_t *pool, h2o_timestamp_t *ts)
{
    uint64_t now = h2o_now(ctx->loop);

    if (ctx->_timestamp_cache.uv_now_at != now) {
        time_t prev_sec = ctx->_timestamp_cache.tv_at.tv_sec;
        ctx->_timestamp_cache.uv_now_at = now;
        gettimeofday(&ctx->_timestamp_cache.tv_at, NULL);
        if (ctx->_timestamp_cache.tv_at.tv_sec != prev_sec) {
            /* update the string cache */
            if (ctx->_timestamp_cache.value != NULL)
                h2o_mem_release_shared(ctx->_timestamp_cache.value);
            ctx->_timestamp_cache.value = h2o_mem_alloc_shared(NULL, sizeof(h2o_timestamp_string_t), NULL);
            h2o_time2str_rfc1123(ctx->_timestamp_cache.value->rfc1123, ctx->_timestamp_cache.tv_at.tv_sec);
            h2o_time2str_log(ctx->_timestamp_cache.value->log, ctx->_timestamp_cache.tv_at.tv_sec);
        }
    }

    ts->at = ctx->_timestamp_cache.tv_at;
    h2o_mem_link_shared(pool, ctx->_timestamp_cache.value);
    ts->str = ctx->_timestamp_cache.value;
}
Beispiel #3
0
void h2o_headers_append_command(h2o_headers_command_t **cmds, int cmd, h2o_iovec_t *name, h2o_iovec_t value)
{
    h2o_headers_command_t *new_cmds;
    size_t cnt;

    if (*cmds != NULL) {
        for (cnt = 0; (*cmds)[cnt].cmd != H2O_HEADERS_CMD_NULL; ++cnt)
            ;
    } else {
        cnt = 0;
    }

    new_cmds = h2o_mem_alloc_shared(NULL, (cnt + 2) * sizeof(*new_cmds), NULL);
    if (*cmds != NULL)
        memcpy(new_cmds, *cmds, cnt * sizeof(*new_cmds));
    new_cmds[cnt] = (h2o_headers_command_t){cmd, name, value};
    new_cmds[cnt + 1] = (h2o_headers_command_t){H2O_HEADERS_CMD_NULL};

    if (*cmds != NULL)
        h2o_mem_release_shared(*cmds);
    *cmds = new_cmds;
}
Beispiel #4
0
h2o_access_log_filehandle_t *h2o_access_log_open_handle(const char *path, const char *fmt)
{
    struct log_element_t *elements;
    size_t num_elements;
    int fd;
    h2o_access_log_filehandle_t *fh;

    /* default to combined log format */
    if (fmt == NULL)
        fmt = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"";
    if ((elements = compile_log_format(fmt, &num_elements)) == NULL)
        return NULL;

    /* open log file */
    if ((fd = h2o_access_log_open_log(path)) == -1)
        return NULL;

    fh = h2o_mem_alloc_shared(NULL, sizeof(*fh), on_dispose_handle);
    fh->elements = elements;
    fh->num_elements = num_elements;
    fh->fd = fd;

    return fh;
}
Beispiel #5
0
static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req)
{
	thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
	                                                      event_loop.h2o_ctx,
	                                                      req->conn->ctx);

	const size_t num_query = get_query_number(req);

	// MAX_QUERIES is a relatively small number, so assume no overflow in the following
	// arithmetic operations.
	assert(num_query <= MAX_QUERIES);

	size_t base_size = offsetof(multiple_query_ctx_t, res) + num_query * sizeof(query_result_t);

	base_size = ((base_size + _Alignof(query_param_t) - 1) / _Alignof(query_param_t));
	base_size = base_size * _Alignof(query_param_t);

	const size_t num_query_in_progress = MIN(num_query, ctx->config->max_db_conn_num);
	size_t sz = base_size + num_query_in_progress * sizeof(query_param_t);

	if (do_update) {
		const size_t reuse_size = (num_query_in_progress - 1) * sizeof(query_param_t);
		const size_t update_query_len = MAX_UPDATE_QUERY_LEN(num_query);

		if (update_query_len > reuse_size)
			sz += update_query_len - reuse_size;
	}

	multiple_query_ctx_t * const query_ctx = calloc(1, sz);

	if (query_ctx) {
		multiple_query_ctx_t ** const p = h2o_mem_alloc_shared(&req->pool,
		                                                       sizeof(*p),
		                                                       cleanup_multiple_query_request);

		*p = query_ctx;
		query_ctx->ctx = ctx;
		query_ctx->num_query = num_query;
		query_ctx->req = req;
		query_ctx->do_update = do_update;
		query_ctx->use_cache = use_cache;
		query_ctx->query_param = (query_param_t *) ((char *) query_ctx + base_size);
		initialize_ids(num_query, query_ctx->res, &ctx->random_seed);

		if (use_cache) {
			fetch_from_cache(h2o_now(ctx->event_loop.h2o_ctx.loop),
			                 &ctx->global_data->world_cache,
			                 query_ctx);

			if (query_ctx->num_result == query_ctx->num_query) {
				complete_multiple_query(query_ctx);
				return 0;
			}
		}

		query_ctx->num_query_in_progress = MIN(num_query_in_progress,
		                                       query_ctx->num_query - query_ctx->num_result);

		for (size_t i = 0; i < query_ctx->num_query_in_progress; i++) {
			query_ctx->query_param[i].ctx = query_ctx;
			// We need a copy of id because the original may be overwritten
			// by a completed query.
			query_ctx->query_param[i].id = htonl(query_ctx->res[query_ctx->num_result + i].id);
			query_ctx->query_param[i].id_format = 1;
			query_ctx->query_param[i].id_len = sizeof(query_ctx->query_param[i].id);
			query_ctx->query_param[i].id_pointer = (const char *) &query_ctx->query_param[i].id;
			query_ctx->query_param[i].param.command = WORLD_TABLE_NAME;
			query_ctx->query_param[i].param.nParams = 1;
			query_ctx->query_param[i].param.on_error = on_multiple_query_error;
			query_ctx->query_param[i].param.on_result = on_multiple_query_result;
			query_ctx->query_param[i].param.on_timeout = on_multiple_query_timeout;
			query_ctx->query_param[i].param.paramFormats = &query_ctx->query_param[i].id_format;
			query_ctx->query_param[i].param.paramLengths = &query_ctx->query_param[i].id_len;
			query_ctx->query_param[i].param.paramValues = &query_ctx->query_param[i].id_pointer;
			query_ctx->query_param[i].param.flags = IS_PREPARED;
			query_ctx->query_param[i].param.resultFormat = 1;

			if (execute_query(ctx, &query_ctx->query_param[i].param)) {
				query_ctx->num_query_in_progress = i;
				query_ctx->cleanup = true;
				send_service_unavailable_error(DB_REQ_ERROR, req);
				return 0;
			}
		}
	}
	else
		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);

	return 0;
}
Beispiel #6
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;
}
Beispiel #7
0
int h2o_access_log_open_log(const char *path)
{
    int fd;

    if (path[0] == '|') {
        int pipefds[2];
        pid_t pid;
        char *argv[4] = {"/bin/sh", "-c", (char *)(path + 1), NULL};
        /* create pipe */
#ifndef _MSC_VER
        if (pipe(pipefds) != 0) {
            perror("pipe failed");
            return -1;
        }
#else
		if (_pipe(pipefds,4096,O_BINARY) == -1) {
			perror("pipe failed");
			return -1;
		}
#endif

#ifndef _MSC_VER
        if (fcntl(pipefds[1], F_SETFD, FD_CLOEXEC) == -1) {
            perror("failed to set FD_CLOEXEC on pipefds[1]");
            return -1;
        }
#endif
        /* spawn the logger */
        int mapped_fds[] = {pipefds[0], 0, /* map pipefds[0] to stdin */
                            -1};
        if ((pid = h2o_spawnp(argv[0], argv, mapped_fds, 0)) == -1) {
            fprintf(stderr, "failed to open logger: %s:%s\n", path + 1, strerror(errno));
            return -1;
        }
        /* close the read side of the pipefds and return the write side */
        close(pipefds[0]);
        fd = pipefds[1];
    } else {
#ifndef _MSC_VER
        if ((fd = open(path, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) == -1) {
			//(owning) User: read & write
			//*Group: read
			//* Other : read
#else
		if ((fd = _open(path, O_CREAT | O_WRONLY | O_APPEND, _O_RDWR)) == -1) {			
#endif
            fprintf(stderr, "failed to open log file:%s:%s\n", path, strerror(errno));
            return -1;
        }
    }
    return fd;
}

h2o_access_log_filehandle_t *h2o_access_log_open_handle(const char *path, const char *fmt)
{
    h2o_logconf_t *logconf;
    int fd;
    h2o_access_log_filehandle_t *fh;
    char errbuf[256];

    /* default to combined log format */
    if (fmt == NULL)
        fmt = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"";
    if ((logconf = h2o_logconf_compile(fmt, H2O_LOGCONF_ESCAPE_APACHE, errbuf)) == NULL) {
        fprintf(stderr, "%s\n", errbuf);
        return NULL;
    }

    /* open log file */
    if ((fd = h2o_access_log_open_log(path)) == -1) {
        h2o_logconf_dispose(logconf);
        return NULL;
    }

    fh = h2o_mem_alloc_shared(NULL, sizeof(*fh), on_dispose_handle);
    fh->logconf = logconf;
    fh->fd = fd;
    return fh;
}