Ejemplo n.º 1
0
Archivo: file.c Proyecto: ancuop/h2o
static void do_proceed(h2o_generator_t *_self, h2o_req_t *req)
{
    struct st_h2o_sendfile_generator_t *self = (void *)_self;
    size_t rlen;
    ssize_t rret;
    h2o_iovec_t vec;
    int is_final;

    /* read the file */
    rlen = self->bytesleft;
    if (rlen > MAX_BUF_SIZE)
        rlen = MAX_BUF_SIZE;
    while ((rret = pread(self->file.ref->fd, self->buf, rlen, self->file.off)) == -1 && errno == EINTR)
        ;
    if (rret == -1) {
        req->http1_is_persistent = 0; /* FIXME need a better interface to dispose an errored response w. content-length */
        h2o_send(req, NULL, 0, 1);
        do_close(&self->super, req);
        return;
    }
    self->file.off += rret;
    self->bytesleft -= rret;
    is_final = self->bytesleft == 0;

    /* send (and close if done) */
    vec.base = self->buf;
    vec.len = rret;
    h2o_send(req, &vec, 1, is_final);
    if (is_final)
        do_close(&self->super, req);
}
Ejemplo n.º 2
0
Archivo: file.c Proyecto: ancuop/h2o
static void do_multirange_proceed(h2o_generator_t *_self, h2o_req_t *req)
{
    struct st_h2o_sendfile_generator_t *self = (void *)_self;
    size_t rlen, used_buf = 0;
    ssize_t rret, vecarrsize;
    h2o_iovec_t vec[2];
    int is_finished;

    if (self->bytesleft == 0) {
        size_t *range_cur = self->ranged.range_infos + 2 * self->ranged.current_range;
        size_t range_end = *range_cur + *(range_cur + 1) - 1;
        if (H2O_LIKELY(self->ranged.current_range != 0))
            used_buf =
                sprintf(self->buf, "\r\n--%s\r\nContent-Type: %s\r\nContent-Range: bytes %zd-%zd/%zd\r\n\r\n",
                        self->ranged.boundary.base, self->ranged.mimetype.base, *range_cur, range_end, self->ranged.filesize);
        else
            used_buf =
                sprintf(self->buf, "--%s\r\nContent-Type: %s\r\nContent-Range: bytes %zd-%zd/%zd\r\n\r\n",
                        self->ranged.boundary.base, self->ranged.mimetype.base, *range_cur, range_end, self->ranged.filesize);
        self->ranged.current_range++;
        self->file.off = *range_cur;
        self->bytesleft = *++range_cur;
    }
    rlen = self->bytesleft;
    if (rlen + used_buf > MAX_BUF_SIZE)
        rlen = MAX_BUF_SIZE - used_buf;
    while ((rret = pread(self->file.ref->fd, self->buf + used_buf, rlen, self->file.off)) == -1 && errno == EINTR)
        ;
    if (rret == -1)
        goto Error;
    self->file.off += rret;
    self->bytesleft -= rret;

    vec[0].base = self->buf;
    vec[0].len = rret + used_buf;
    if (self->ranged.current_range == self->ranged.range_count && self->bytesleft == 0) {
        vec[1].base = h2o_mem_alloc_pool(&req->pool, sizeof("\r\n--") - 1 + BOUNDARY_SIZE + sizeof("--\r\n"));
        vec[1].len = sprintf(vec[1].base, "\r\n--%s--\r\n", self->ranged.boundary.base);
        vecarrsize = 2;
        is_finished = 1;
    } else {
        vecarrsize = 1;
        is_finished = 0;
    }
    h2o_send(req, vec, vecarrsize, is_finished);
    if (is_finished)
        do_close(&self->super, req);
    return;

Error:
    req->http1_is_persistent = 0;
    h2o_send(req, NULL, 0, 1);
    do_close(&self->super, req);
    return;
}
Ejemplo n.º 3
0
static void do_send(struct rp_generator_t *self)
{
    assert(self->buf_sending->size == 0);

    swap_buffer(
        &self->buf_sending,
        self->client != NULL ? &self->client->sock->input : &self->last_content_before_send);

    if (self->buf_sending->size != 0) {
        h2o_iovec_t buf = h2o_iovec_init(self->buf_sending->bytes, self->buf_sending->size);
        h2o_send(self->src_req, &buf, 1, self->client == NULL);
    } else if (self->client == NULL) {
        h2o_send(self->src_req, NULL, 0, 1);
    }
}
Ejemplo n.º 4
0
static void do_send(struct rp_generator_t *self)
{
    h2o_iovec_t vecs[1];
    size_t veccnt;
    h2o_send_state_t ststate;

    assert(self->sending.bytes_inflight == 0);

    vecs[0] = h2o_doublebuffer_prepare(&self->sending,
                                       self->client != NULL ? &self->client->sock->input : &self->last_content_before_send,
                                       self->src_req->preferred_chunk_size);

    if (self->client == NULL && vecs[0].len == self->sending.buf->size && self->last_content_before_send->size == 0) {
        veccnt = vecs[0].len != 0 ? 1 : 0;
        ststate = H2O_SEND_STATE_FINAL;
    } else {
        if (vecs[0].len == 0)
            return;
        veccnt = 1;
        ststate = H2O_SEND_STATE_IN_PROGRESS;
    }

    if (self->had_body_error)
        ststate = H2O_SEND_STATE_ERROR;

    h2o_send(self->src_req, vecs, veccnt, ststate);
}
Ejemplo n.º 5
0
static void do_send(h2o_mruby_generator_t *generator, h2o_buffer_t **input, int is_final)
{
    h2o_mruby_chunked_t *chunked = generator->chunked;

    assert(!chunked->sending.inflight);

    h2o_iovec_t buf = h2o_doublebuffer_prepare(&chunked->sending, input, generator->req->preferred_chunk_size);
    size_t bufcnt = 1;
    h2o_send_state_t send_state;

    if (is_final && buf.len == chunked->sending.buf->size && (*input)->size == 0) {
        if (buf.len == 0)
            --bufcnt;
        /* send error if the length of content served is smaller than content-length header value */
        if (chunked->bytes_left == 0 || chunked->bytes_left == SIZE_MAX) {
            send_state = H2O_SEND_STATE_FINAL;
        } else {
            send_state = H2O_SEND_STATE_ERROR;
        }
    } else {
        if (buf.len == 0)
            return;
        send_state = H2O_SEND_STATE_IN_PROGRESS;
    }

    h2o_send(generator->req, &buf, bufcnt, send_state);
}
Ejemplo n.º 6
0
Archivo: file.c Proyecto: ancuop/h2o
static int send_dir_listing(h2o_req_t *req, const char *path, size_t path_len, int is_get)
{
    static h2o_generator_t generator = {NULL, NULL};
    DIR *dp;
    h2o_buffer_t *body;
    h2o_iovec_t bodyvec;

    /* build html */
    if ((dp = opendir(path)) == NULL)
        return -1;
    body = build_dir_listing_html(&req->pool, req->path_normalized, dp);
    closedir(dp);

    bodyvec = h2o_iovec_init(body->bytes, body->size);
    h2o_buffer_link_to_pool(body, &req->pool);

    /* send response */
    req->res.status = 200;
    req->res.reason = "OK";
    h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, H2O_STRLIT("text/html; charset=utf-8"));

    /* send headers */
    if (!is_get) {
        h2o_send_inline(req, NULL, 0);
        return 0;
    }

    /* send data */
    h2o_start_response(req, &generator);
    h2o_send(req, &bodyvec, 1, 1);
    return 0;
}
Ejemplo n.º 7
0
static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, h2o_iovec_t msg, struct phr_header *headers, size_t num_headers)
{
    struct rp_generator_t *self = client->data;
    size_t i;

    if (errstr != NULL && errstr != h2o_http1client_error_is_eos) {
        self->client = NULL;
        h2o_send_error(self->src_req, 502, "Gateway Error", errstr, 0);
        return NULL;
    }

    /* copy the response */
    self->src_req->res.status = status;
    self->src_req->res.reason = h2o_strdup(&self->src_req->pool, msg.base, msg.len).base;
    for (i = 0; i != num_headers; ++i) {
        const h2o_token_t *token = h2o_lookup_token(headers[i].name, headers[i].name_len);
        h2o_iovec_t value;
        if (token != NULL) {
            if (token->is_connection_specific) {
                goto Skip;
            }
            if (token == H2O_TOKEN_CONTENT_LENGTH) {
                if (self->src_req->res.content_length != SIZE_MAX
                    || (self->src_req->res.content_length = h2o_strtosize(headers[i].value, headers[i].value_len)) == SIZE_MAX) {
                    self->client = NULL;
                    h2o_send_error(self->src_req, 502, "Gateway Error", "invalid response from upstream", 0);
                    return NULL;
                }
                goto Skip;
            } else if (token == H2O_TOKEN_LOCATION) {
                value = rewrite_location(&self->src_req->pool, headers[i].value, headers[i].value_len, self->upstream, self->src_req->scheme, self->src_req->authority, self->src_req->pathconf->path);
                goto AddHeader;
            }
            /* default behaviour, transfer the header downstream */
            value = h2o_strdup(&self->src_req->pool, headers[i].value, headers[i].value_len);
        AddHeader:
            h2o_add_header(&self->src_req->pool, &self->src_req->res.headers, token, value.base, value.len);
        Skip:
            ;
        } else {
            h2o_iovec_t name = h2o_strdup(&self->src_req->pool, headers[i].name, headers[i].name_len);
            h2o_iovec_t value = h2o_strdup(&self->src_req->pool, headers[i].value, headers[i].value_len);
            h2o_add_header_by_str(&self->src_req->pool, &self->src_req->res.headers, name.base, name.len, 0, value.base, value.len);
        }
    }

    /* declare the start of the response */
    h2o_start_response(self->src_req, &self->super);

    if (errstr == h2o_http1client_error_is_eos) {
        self->client = NULL;
        h2o_send(self->src_req, NULL, 0, 1);
        return NULL;
    }

    return on_body;
}
Ejemplo n.º 8
0
static void __get_keys_send(get_keys_generator_t *self, int e, MDB_val* k,
                            h2o_req_t *req)
{
    if (0 == e && 0 >= strncmp(k->mv_data, self->key->s,
                               min(self->key->len, k->mv_size)))
    {
        #define SEND_BUFS 2
        h2o_iovec_t body[SEND_BUFS];
        body[0] = h2o_iovec_init(k->mv_data, k->mv_size);
        body[1] = h2o_iovec_init("\n", 1);
        h2o_send(req, body, SEND_BUFS, 0);
    }
    else
    {
        h2o_send(req, NULL, 0, 1);
        __get_keys_close((h2o_generator_t*)self, req);
    }
}
Ejemplo n.º 9
0
void h2o_send_inline(h2o_req_t *req, const char *body, size_t len)
{
    static h2o_generator_t generator = { NULL, NULL };

    h2o_iovec_t buf = h2o_strdup(&req->pool, body, len);
    /* the function intentionally does not set the content length, since it may be used for generating 304 response, etc. */
    /* req->res.content_length = buf.len; */

    h2o_start_response(req, &generator);
    h2o_send(req, &buf, 1, 1);
}
Ejemplo n.º 10
0
static int post_test(h2o_handler_t *self, h2o_req_t *req)
{
    if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))
        && h2o_memis(req->path.base, req->path.len, H2O_STRLIT("/post-test"))) {
        static h2o_generator_t generator = { NULL, NULL };
        req->res.status = 200;
        req->res.reason = "OK";
        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, H2O_STRLIT("text/plain; charset=utf-8"));
        h2o_start_response(req, &generator);
        h2o_send(req, &req->entity, 1, 1);
        return 0;
    }

    return -1;
}
Ejemplo n.º 11
0
static void complete_fortunes(struct st_h2o_generator_t *self, h2o_req_t *req)
{
	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, generator, self);
	iovec_list_t * const iovec_list = H2O_STRUCT_FROM_MEMBER(iovec_list_t,
	                                                         l,
	                                                         fortune_ctx->iovec_list);

	fortune_ctx->iovec_list = iovec_list->l.next;

	const h2o_send_state_t state = fortune_ctx->iovec_list ?
	                               H2O_SEND_STATE_IN_PROGRESS :
	                               H2O_SEND_STATE_FINAL;

	h2o_send(req, iovec_list->iov, iovec_list->iovcnt, state);
}
Ejemplo n.º 12
0
static int chunked_test(h2o_handler_t *self, h2o_req_t *req)
{
    if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET"))
        && h2o_memis(req->path.base, req->path.len, H2O_STRLIT("/chunked-test"))) {
        static h2o_generator_t generator = { NULL, NULL };
        h2o_buf_t body = h2o_strdup(&req->pool, "hello world\n", SIZE_MAX);
        req->res.status = 200;
        req->res.reason = "OK";
        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, H2O_STRLIT("text/plain"));
        h2o_start_response(req, &generator);
        h2o_send(req, &body, 1, 1);
        return 0;
    }

    return -1;
}
Ejemplo n.º 13
0
Archivo: file.c Proyecto: lhjay1/h2o
static int redirect_to_dir(h2o_req_t *req, const char *path, size_t path_len)
{
    static h2o_generator_t generator = { NULL, NULL };
    static const h2o_buf_t body_prefix = {
        H2O_STRLIT("<!DOCTYPE html><TITLE>301 Moved Permanently</TITLE><P>The document has moved <A HREF=\"")
    };
    static const h2o_buf_t body_suffix = {
        H2O_STRLIT("\">here</A>")
    };

    h2o_buf_t url;
    size_t alloc_size;
    h2o_buf_t bufs[3];

    /* determine the size of the memory needed */
    alloc_size = sizeof(":///") + req->scheme.len + req->authority.len + path_len;

    /* allocate and build url */
    url.base = h2o_mempool_alloc(&req->pool, alloc_size);
    url.len = sprintf(url.base, "%.*s://%.*s%.*s/", (int)req->scheme.len, req->scheme.base, (int)req->authority.len, req->authority.base, (int)path_len, path);
    assert(url.len + 1 == alloc_size);

    /* build response header */
    req->res.status = 301;
    req->res.reason = "Moved Permanently";
    memset(&req->res.headers, 0, sizeof(req->res.headers));
    h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_LOCATION, url.base, url.len);
    h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, H2O_STRLIT("text/html; charset=utf-8"));

    /* build response */
    bufs[0] = body_prefix;
    bufs[1] = h2o_htmlescape(&req->pool, url.base, url.len);
    bufs[2] = body_suffix;

    /* send */
    h2o_start_response(req, &generator);
    h2o_send(req, bufs, 3, 1);

    return 0;
}
Ejemplo n.º 14
0
static void do_send(h2o_mruby_generator_t *generator, h2o_buffer_t **input, int is_final)
{
    h2o_mruby_chunked_t *chunked = generator->chunked;

    assert(chunked->sending.bytes_inflight == 0);

    h2o_iovec_t buf = h2o_doublebuffer_prepare(&chunked->sending, input, generator->req->preferred_chunk_size);
    size_t bufcnt = 1;

    if (is_final && buf.len == chunked->sending.buf->size && (*input)->size == 0) {
        if (buf.len == 0)
            --bufcnt;
        /* terminate the H1 connection if the length of content served did not match the value sent in content-length header */
        if (chunked->bytes_left != SIZE_MAX && chunked->bytes_left != 0)
            generator->req->http1_is_persistent = 0;
    } else {
        if (buf.len == 0)
            return;
        is_final = 0;
    }

    h2o_send(generator->req, &buf, bufcnt, is_final ? H2O_SEND_STATE_FINAL : H2O_SEND_STATE_IN_PROGRESS);
}
Ejemplo n.º 15
0
Archivo: proxy.c Proyecto: firewood/h2o
static void do_send(struct rp_generator_t *self)
{
    h2o_iovec_t vecs[1];
    size_t veccnt;
    int is_eos;

    assert(self->sending.bytes_inflight == 0);

    vecs[0] = h2o_doublebuffer_prepare(&self->sending,
                                       self->client != NULL ? &self->client->sock->input : &self->last_content_before_send,
                                       self->src_req->preferred_chunk_size);

    if (self->client == NULL && vecs[0].len == self->sending.buf->size && self->last_content_before_send->size == 0) {
        veccnt = vecs[0].len != 0 ? 1 : 0;
        is_eos = 1;
    } else {
        if (vecs[0].len == 0)
            return;
        veccnt = 1;
        is_eos = 0;
    }
    h2o_send(self->src_req, vecs, veccnt, is_eos);
}
Ejemplo n.º 16
0
Archivo: file.c Proyecto: ancuop/h2o
static void do_send_file(struct st_h2o_sendfile_generator_t *self, h2o_req_t *req, int status, const char *reason,
                         h2o_iovec_t mime_type, h2o_mime_attributes_t *mime_attr, int is_get)
{
    /* link the request */
    self->req = req;

    /* setup response */
    req->res.status = status;
    req->res.reason = reason;
    req->res.content_length = self->bytesleft;
    req->res.mime_attr = mime_attr;

    if (self->ranged.range_count > 1) {
        mime_type.base = h2o_mem_alloc_pool(&req->pool, 52);
        mime_type.len = sprintf(mime_type.base, "multipart/byteranges; boundary=%s", self->ranged.boundary.base);
    }
    h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, mime_type.base, mime_type.len);
    h2o_filecache_get_last_modified(self->file.ref, self->header_bufs.last_modified);
    h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_LAST_MODIFIED, self->header_bufs.last_modified,
                   H2O_TIMESTR_RFC1123_LEN);
    add_headers_unconditional(self, req);
    if (self->content_encoding.base != NULL)
        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_ENCODING, self->content_encoding.base,
                       self->content_encoding.len);
    if (self->ranged.range_count == 0)
        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_ACCEPT_RANGES, H2O_STRLIT("bytes"));
    else if (self->ranged.range_count == 1) {
        h2o_iovec_t content_range;
        content_range.base = h2o_mem_alloc_pool(&req->pool, 128);
        content_range.len = sprintf(content_range.base, "bytes %zd-%zd/%zd", self->ranged.range_infos[0],
                                    self->ranged.range_infos[0] + self->ranged.range_infos[1] - 1, self->ranged.filesize);
        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_RANGE, content_range.base, content_range.len);
    }

    /* special path for cases where we do not need to send any data */
    if (!is_get || self->bytesleft == 0) {
        static h2o_generator_t generator = {NULL, NULL};
        h2o_start_response(req, &generator);
        h2o_send(req, NULL, 0, 1);
        do_close(&self->super, req);
        return;
    }

    /* send data */
    h2o_start_response(req, &self->super);

    if (self->ranged.range_count == 1)
        self->file.off = self->ranged.range_infos[0];
    if (req->_ostr_top->start_pull != NULL && self->ranged.range_count < 2) {
        req->_ostr_top->start_pull(req->_ostr_top, do_pull);
    } else {
        size_t bufsz = MAX_BUF_SIZE;
        if (self->bytesleft < bufsz)
            bufsz = self->bytesleft;
        self->buf = h2o_mem_alloc_pool(&req->pool, bufsz);
        if (self->ranged.range_count < 2)
            do_proceed(&self->super, req);
        else {
            self->bytesleft = 0;
            self->super.proceed = do_multirange_proceed;
            do_multirange_proceed(&self->super, req);
        }
    }
}
Ejemplo n.º 17
0
static result_return_t on_fortune_result(db_query_param_t *param, PGresult *result)
{
	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, param, param);
	int ret = DONE;
	const ExecStatusType status = PQresultStatus(result);

	if (status == PGRES_TUPLES_OK) {
		const size_t num_rows = PQntuples(result);

		ret = SUCCESS;

		for (size_t i = 0; i < num_rows; i++) {
			fortune_t * const fortune = h2o_mem_alloc_pool(&fortune_ctx->req->pool,
			                                               sizeof(*fortune));

			if (fortune) {
				memset(fortune, 0, sizeof(*fortune));
				fortune->id.base = PQgetvalue(result, i, 0);
				fortune->id.len = PQgetlength(result, i, 0);
				fortune->message = h2o_htmlescape(&fortune_ctx->req->pool,
				                                  PQgetvalue(result, i, 1),
				                                  PQgetlength(result, i, 1));
				fortune->l.next = fortune_ctx->result;
				fortune_ctx->result = &fortune->l;
				fortune_ctx->num_result++;

				if (!i)
					fortune->data = result;
			}
			else {
				send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, fortune_ctx->req);
				ret = DONE;

				if (!i)
					PQclear(result);

				break;
			}
		}
	}
	else if (result) {
		LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
		send_error(BAD_GATEWAY, DB_ERROR, fortune_ctx->req);
		PQclear(result);
	}
	else {
		mustache_api_t api = {.sectget = on_fortune_section,
		                      .varget = on_fortune_variable,
		                      .write = add_iovec};
		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
		                                                      event_loop.h2o_ctx,
		                                                      fortune_ctx->req->conn->ctx);
		const size_t iovcnt = MIN(MAX_IOVEC, fortune_ctx->num_result * 5 + 2);
		const size_t sz = offsetof(iovec_list_t, iov) + iovcnt * sizeof(h2o_iovec_t);
		char _Alignas(iovec_list_t) mem[sz];
		iovec_list_t * const restrict iovec_list = (iovec_list_t *) mem;

		memset(iovec_list, 0, offsetof(iovec_list_t, iov));
		iovec_list->max_iovcnt = iovcnt;
		fortune_ctx->iovec_list_iter = iovec_list;
		fortune_ctx->result = sort_fortunes(fortune_ctx->result);

		if (mustache_render(&api, fortune_ctx, ctx->global_data->fortunes_template)) {
			fortune_ctx->iovec_list = iovec_list->l.next;
			set_default_response_param(HTML, fortune_ctx->content_length, fortune_ctx->req);
			h2o_start_response(fortune_ctx->req, &fortune_ctx->generator);

			const h2o_send_state_t state = fortune_ctx->iovec_list ?
			                               H2O_SEND_STATE_IN_PROGRESS :
			                               H2O_SEND_STATE_FINAL;

			h2o_send(fortune_ctx->req, iovec_list->iov, iovec_list->iovcnt, state);
		}
		else
			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, fortune_ctx->req);
	}

	return ret;
}
Ejemplo n.º 18
0
Archivo: main.c Proyecto: ifzz/ticketd
/** HTTP POST entry point for receiving entries from client
 * Provide the user with an ID */
static int __http_get_id(h2o_handler_t *self, h2o_req_t *req)
{
    static h2o_generator_t generator = { NULL, NULL };

    if (!h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST")))
        return -1;

    /* redirect to leader if needed */
    int leader = raft_get_current_leader(sv->raft);
    if (-1 == leader)
    {
        return h2oh_respond_with_error(req, 503, "Leader unavailable");
    }
    else if (leader != sv->node_idx)
    {
        raft_node_t* node = raft_get_node(sv->raft, leader);
        peer_connection_t* leader_conn = raft_node_get_udata(node);
        char leader_url[LEADER_URL_LEN];

        static h2o_generator_t generator = { NULL, NULL };
        static h2o_iovec_t body = { .base = "", .len = 0 };
        req->res.status = 301;
        req->res.reason = "Moved Permanently";
        h2o_start_response(req, &generator);
        snprintf(leader_url, LEADER_URL_LEN, "http://%s:%d/",
                 inet_ntoa(leader_conn->addr.sin_addr),
                 leader_conn->http_port);
        h2o_add_header(&req->pool,
                       &req->res.headers,
                       H2O_TOKEN_LOCATION,
                       leader_url,
                       strlen(leader_url));
        h2o_send(req, &body, 1, 1);
        return 0;
    }

    int e;

    unsigned int ticket = __generate_ticket();

    msg_entry_t entry;
    entry.id = rand();
    entry.data.buf = (void*)&ticket;
    entry.data.len = sizeof(ticket);

    uv_mutex_lock(&sv->raft_lock);

    msg_entry_response_t r;
    e = raft_recv_entry(sv->raft, sv->node_idx, &entry, &r);
    if (0 != e)
        return h2oh_respond_with_error(req, 500, "BAD");

    /* block until the entry is committed */
    int done = 0;
    do
    {
        uv_cond_wait(&sv->appendentries_received, &sv->raft_lock);
        e = raft_msg_entry_response_committed(sv->raft, &r);
        switch (e)
        {
        case 0:
            /* not committed yet */
            break;
        case 1:
            done = 1;
            uv_mutex_unlock(&sv->raft_lock);
            break;
        case -1:
            uv_mutex_unlock(&sv->raft_lock);
            return h2oh_respond_with_error(req, 400, "TRY AGAIN");
        }
    }
    while (!done);

    /* serialize ID */
    char id_str[100];
    h2o_iovec_t body;
    sprintf(id_str, "%d", entry.id);
    body = h2o_iovec_init(id_str, strlen(id_str));

    req->res.status = 200;
    req->res.reason = "OK";
    h2o_start_response(req, &generator);
    h2o_send(req, &body, 1, 1);
    return 0;
}
Ejemplo n.º 19
0
Archivo: proxy.c Proyecto: firewood/h2o
static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status,
                                       h2o_iovec_t msg, struct phr_header *headers, size_t num_headers)
{
    struct rp_generator_t *self = client->data;
    h2o_req_t *req = self->src_req;
    size_t i;

    if (errstr != NULL && errstr != h2o_http1client_error_is_eos) {
        self->client = NULL;
        h2o_req_log_error(req, "lib/core/proxy.c", "%s", errstr);
        h2o_send_error(req, 502, "Gateway Error", errstr, 0);
        return NULL;
    }

    /* copy the response (note: all the headers must be copied; http1client discards the input once we return from this callback) */
    req->res.status = status;
    req->res.reason = h2o_strdup(&req->pool, msg.base, msg.len).base;
    for (i = 0; i != num_headers; ++i) {
        const h2o_token_t *token = h2o_lookup_token(headers[i].name, headers[i].name_len);
        h2o_iovec_t value;
        if (token != NULL) {
            if (token->proxy_should_drop) {
                goto Skip;
            }
            if (token == H2O_TOKEN_CONTENT_LENGTH) {
                if (req->res.content_length != SIZE_MAX ||
                    (req->res.content_length = h2o_strtosize(headers[i].value, headers[i].value_len)) == SIZE_MAX) {
                    self->client = NULL;
                    h2o_req_log_error(req, "lib/core/proxy.c", "%s", "invalid response from upstream (malformed content-length)");
                    h2o_send_error(req, 502, "Gateway Error", "invalid response from upstream", 0);
                    return NULL;
                }
                goto Skip;
            } else if (token == H2O_TOKEN_LOCATION) {
                if (req->res_is_delegated && (300 <= status && status <= 399) && status != 304) {
                    self->client = NULL;
                    h2o_iovec_t method = h2o_get_redirect_method(req->method, status);
                    h2o_send_redirect_internal(req, method, headers[i].value, headers[i].value_len, 1);
                    return NULL;
                }
                if (req->overrides != NULL && req->overrides->location_rewrite.match != NULL) {
                    value =
                        rewrite_location(&req->pool, headers[i].value, headers[i].value_len, req->overrides->location_rewrite.match,
                                         req->input.scheme, req->input.authority, req->overrides->location_rewrite.path_prefix);
                    if (value.base != NULL)
                        goto AddHeader;
                }
                goto AddHeaderDuped;
            } else if (token == H2O_TOKEN_LINK) {
                h2o_puth_path_in_link_header(req, headers[i].value, headers[i].value_len);
            }
        /* default behaviour, transfer the header downstream */
        AddHeaderDuped:
            value = h2o_strdup(&req->pool, headers[i].value, headers[i].value_len);
        AddHeader:
            h2o_add_header(&req->pool, &req->res.headers, token, value.base, value.len);
        Skip:
            ;
        } else {
            h2o_iovec_t name = h2o_strdup(&req->pool, headers[i].name, headers[i].name_len);
            h2o_iovec_t value = h2o_strdup(&req->pool, headers[i].value, headers[i].value_len);
            h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, value.base, value.len);
        }
    }

    if (self->is_websocket_handshake && req->res.status == 101) {
        h2o_http1client_ctx_t *client_ctx = get_client_ctx(req);
        assert(client_ctx->websocket_timeout != NULL);
        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, H2O_STRLIT("websocket"));
        on_websocket_upgrade(self, client_ctx->websocket_timeout);
        self->client = NULL;
        return NULL;
    }
    /* declare the start of the response */
    h2o_start_response(req, &self->super);

    if (errstr == h2o_http1client_error_is_eos) {
        self->client = NULL;
        h2o_send(req, NULL, 0, 1);
        return NULL;
    }

    return on_body;
}