Exemple #1
0
void plus(VM* vm, VAL* oldbase) {
    INITFRAME;
    RESERVE(2);
    ADDTOP(2);

    switch(TAG(LOC(0))) {
    case 0:
        PROJECT(vm, LOC(0), 2, 0);
        RVAL = LOC(1);
        TOPBASE(0);
        REBASE;
        break;
    case 1:
        PROJECT(vm, LOC(0), 2, 1);
        RESERVE(2);
        TOP(0) = LOC(2);
        TOP(1) = LOC(1);
        STOREOLD;
        BASETOP(0);
        ADDTOP(2);
        CALL(plus);
        LOC(3) = RVAL;
        RVAL = MKCON(vm, 1, 1, LOC(3));
        TOPBASE(0);
        REBASE;
        break;
    }
}
Exemple #2
0
void natToInt(VM* vm, VAL* oldbase) {
    INITFRAME;
    RESERVE(3);
    ADDTOP(3);

    switch(TAG(LOC(0))) {
    case 0:
        PROJECT(vm, LOC(0), 2, 0);
        RVAL = MKINT(0);
        TOPBASE(0);
        REBASE;
        break;
    case 1:
        PROJECT(vm, LOC(0), 1, 1);
        RESERVE(1);
        TOP(0) = LOC(1);
        STOREOLD;
        BASETOP(0);
        ADDTOP(1);
        CALL(natToInt);
        LOC(2) = RVAL;
        RVAL = ADD(LOC(2), MKINT(1));
        TOPBASE(0);
        REBASE;
        break;
    }
}
Exemple #3
0
/* printf onto the end of a Cstring
 */
void
Cprintf(Cstring *arg, char *fmt, ...)
{
    va_list ptr;
    int avail, needed;

    if ( (*arg).alloc <= S(*arg) )
	RESERVE(*arg,100);

    avail = (*arg).alloc - S(*arg);
    
    /* try writing the fmt into the existing
     * Cstring, and if that fails reserve enough
     * room to fit it and try again.
     */
    va_start(ptr, fmt);
    needed = vsnprintf(T(*arg)+S(*arg), avail, fmt, ptr);
    va_end(ptr);

    if ( needed >= avail ) {
	RESERVE(*arg, needed+2);
	
	va_start(ptr, fmt);
	vsnprintf(T(*arg)+S(*arg), needed+1, fmt, ptr);
	va_end(ptr);
    }
    S(*arg) += needed;
}
Exemple #4
0
/* write() into a cstring
 */
int
Cswrite(Cstring *iot, char *bfr, int size)
{
    RESERVE(*iot, size);
    memcpy(T(*iot)+S(*iot), bfr, size);
    S(*iot) += size;
    return size;
}
Exemple #5
0
static void tokeniser_init(Tokeniser* t, const char* input)
{
    t->cursor     = input;
    t->eof        = 0;
    t->tokenIndex = RESERVE();

    tokeniser_advance(t);
}
Exemple #6
0
/* write an header index
 */
int
mkd_toc(Document *p, char **doc)
{
    Paragraph *tp, *srcp;
    int last_hnumber = 0;
    Cstring res;
    
    CREATE(res);
    RESERVE(res, 100);

    *doc = 0;

    if ( !(p && p->ctx) ) return -1;
    if ( ! (p->ctx->flags & TOC) ) return 0;

    for ( tp = p->code; tp ; tp = tp->next ) {
	if ( tp->typ == SOURCE ) {
	    for ( srcp = tp->down; srcp; srcp = srcp->next ) {
		if ( srcp->typ == HDR && srcp->text ) {
	    
		    if ( last_hnumber == srcp->hnumber )
			Csprintf(&res,  "%*s</li>\n", srcp->hnumber, "");
		    else while ( last_hnumber > srcp->hnumber ) {
			Csprintf(&res, "%*s</li>\n%*s</ul>\n",
					 last_hnumber, "",
					 last_hnumber-1,"");
			--last_hnumber;
		    }

		    while ( srcp->hnumber > last_hnumber ) {
			Csprintf(&res, "\n%*s<ul>\n", srcp->hnumber, "");
			++last_hnumber;
		    }
		    Csprintf(&res, "%*s<li><a href=\"#", srcp->hnumber, "");
		    mkd_string_to_anchor(T(srcp->text->text), S(srcp->text->text), (void (*)(int,void*))Csputc, &res);
		    Csprintf(&res, "\">");
		    Csreparse(&res, T(srcp->text->text), S(srcp->text->text), 0);
		    Csprintf(&res, "</a>");
		}
	    }
        }
    }

    while ( last_hnumber > 0 ) {
	Csprintf(&res, "%*s</li>\n%*s</ul>\n",
			last_hnumber, "", last_hnumber, "");
	--last_hnumber;
    }
			/* HACK ALERT! HACK ALERT! HACK ALERT! */
    *doc = T(res);	/* we know that a T(Cstring) is a character pointer */
			/* so we can simply pick it up and carry it away, */
    return S(res);	/* leaving the husk of the Ctring on the stack */
			/* END HACK ALERT */
}
Exemple #7
0
int do_main(VM* vm, VAL* oldbase) {
    INITFRAME;
    RESERVE(2);
    ADDTOP(2);

    LOC(0) = MKCON(vm, 0, 0);
    LOC(0) = MKCON(vm, 1, 1, LOC(0));
    LOC(0) = MKCON(vm, 1, 1, LOC(0));

    dumpVal(LOC(0));
    printf("\n");

    LOC(1) = MKCON(vm, 0, 0);
    LOC(1) = MKCON(vm, 1, 1, LOC(1));
    LOC(1) = MKCON(vm, 1, 1, LOC(1));

    RESERVE(2);
    TOP(0) = LOC(0);
    TOP(1) = LOC(1);

    STOREOLD;
    BASETOP(0);
    ADDTOP(2);
    CALL(plus);
    LOC(0) = RVAL;    

    RESERVE(1);
    TOP(0) = LOC(0);
    SLIDE(vm, 1);
    TOPBASE(1);
    TAILCALL(natToInt);
/*    STOREOLD;
    BASETOP(0);
    ADDTOP(1);
    CALL(natToInt);
    TOPBASE(0);
    REBASE; */
}
Exemple #8
0
/* printf() into a cstring
 */
int
Csprintf(Cstring *iot, char *fmt, ...)
{
    va_list ptr;
    int siz=100;

    do {
	RESERVE(*iot, siz);
	va_start(ptr, fmt);
	siz = vsnprintf(T(*iot)+S(*iot), ALLOCATED(*iot)-S(*iot), fmt, ptr);
	va_end(ptr);
    } while ( siz > (ALLOCATED(*iot)-S(*iot)) );

    S(*iot) += siz;
    return siz;
}
Exemple #9
0
static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket_handshake)
{
    h2o_iovec_t buf;
    size_t offset = 0, remote_addr_len = SIZE_MAX;
    char remote_addr[NI_MAXHOST];
    struct sockaddr_storage ss;
    socklen_t sslen;
    h2o_iovec_t cookie_buf = {}, xff_buf = {}, via_buf = {};

    /* for x-f-f */
    if ((sslen = req->conn->callbacks->get_peername(req->conn, (void *)&ss)) != 0)
        remote_addr_len = h2o_socket_getnumerichost((void *)&ss, sslen, remote_addr);

    /* build response */
    buf.len = req->method.len + req->path.len + req->authority.len + 512;
    buf.base = h2o_mem_alloc_pool(&req->pool, buf.len);

#define RESERVE(sz)                                                                                                                \
    do {                                                                                                                           \
        size_t required = offset + sz + 4 /* for "\r\n\r\n" */;                                                                    \
        if (required > buf.len) {                                                                                                  \
            do {                                                                                                                   \
                buf.len *= 2;                                                                                                      \
            } while (required > buf.len);                                                                                          \
            char *newp = h2o_mem_alloc_pool(&req->pool, buf.len);                                                                  \
            memcpy(newp, buf.base, offset);                                                                                        \
            buf.base = newp;                                                                                                       \
        }                                                                                                                          \
    } while (0)
#define APPEND(s, l)                                                                                                               \
    do {                                                                                                                           \
        memcpy(buf.base + offset, (s), (l));                                                                                       \
        offset += (l);                                                                                                             \
    } while (0)
#define APPEND_STRLIT(lit) APPEND((lit), sizeof(lit) - 1)
#define FLATTEN_PREFIXED_VALUE(prefix, value, add_size)                                                                            \
    do {                                                                                                                           \
        RESERVE(sizeof(prefix) - 1 + value.len + 2 + add_size);                                                                    \
        APPEND_STRLIT(prefix);                                                                                                     \
        if (value.len != 0) {                                                                                                      \
            APPEND(value.base, value.len);                                                                                         \
            if (add_size != 0) {                                                                                                   \
                buf.base[offset++] = ',';                                                                                          \
                buf.base[offset++] = ' ';                                                                                          \
            }                                                                                                                      \
        }                                                                                                                          \
    } while (0)

    APPEND(req->method.base, req->method.len);
    buf.base[offset++] = ' ';
    APPEND(req->path.base, req->path.len);
    APPEND_STRLIT(" HTTP/1.1\r\nconnection: ");
    if (is_websocket_handshake) {
        APPEND_STRLIT("upgrade\r\nupgrade: websocket\r\nhost: ");
    } else if (keepalive) {
        APPEND_STRLIT("keep-alive\r\nhost: ");
    } else {
        APPEND_STRLIT("close\r\nhost: ");
    }
    APPEND(req->authority.base, req->authority.len);
    buf.base[offset++] = '\r';
    buf.base[offset++] = '\n';
    assert(offset <= buf.len);
    if (req->entity.base != NULL) {
        RESERVE(sizeof("content-length: 18446744073709551615") - 1);
        offset += sprintf(buf.base + offset, "content-length: %zu\r\n", req->entity.len);
    }
    {
        const h2o_header_t *h, *h_end;
        for (h = req->headers.entries, h_end = h + req->headers.size; h != h_end; ++h) {
            if (h2o_iovec_is_token(h->name)) {
                const h2o_token_t *token = (void *)h->name;
                if (token->proxy_should_drop) {
                    continue;
                } else if (token == H2O_TOKEN_COOKIE) {
                    /* merge the cookie headers; see HTTP/2 8.1.2.5 and HTTP/1 (RFC6265 5.4) */
                    /* FIXME current algorithm is O(n^2) against the number of cookie headers */
                    cookie_buf = build_request_merge_headers(&req->pool, cookie_buf, h->value, ';');
                    continue;
                } else if (token == H2O_TOKEN_VIA) {
                    via_buf = build_request_merge_headers(&req->pool, via_buf, h->value, ',');
                    continue;
                } else if (token == H2O_TOKEN_X_FORWARDED_FOR) {
                    xff_buf = build_request_merge_headers(&req->pool, xff_buf, h->value, ',');
                    continue;
                }
            }
            if (h2o_lcstris(h->name->base, h->name->len, H2O_STRLIT("x-forwarded-proto")))
                continue;
            RESERVE(h->name->len + h->value.len + 2);
            APPEND(h->name->base, h->name->len);
            buf.base[offset++] = ':';
            buf.base[offset++] = ' ';
            APPEND(h->value.base, h->value.len);
            buf.base[offset++] = '\r';
            buf.base[offset++] = '\n';
        }
    }
    if (cookie_buf.len != 0) {
        FLATTEN_PREFIXED_VALUE("cookie: ", cookie_buf, 0);
        buf.base[offset++] = '\r';
        buf.base[offset++] = '\n';
    }
    FLATTEN_PREFIXED_VALUE("x-forwarded-proto: ", req->input.scheme->name, 0);
    buf.base[offset++] = '\r';
    buf.base[offset++] = '\n';
    if (remote_addr_len != SIZE_MAX) {
        FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, remote_addr_len);
        APPEND(remote_addr, remote_addr_len);
    } else {
        FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, 0);
    }
    buf.base[offset++] = '\r';
    buf.base[offset++] = '\n';
    FLATTEN_PREFIXED_VALUE("via: ", via_buf, sizeof("1.1 ") - 1 + req->input.authority.len);
    if (req->version < 0x200) {
        buf.base[offset++] = '1';
        buf.base[offset++] = '.';
        buf.base[offset++] = '0' + (0x100 <= req->version && req->version <= 0x109 ? req->version - 0x100 : 0);
    } else {
        buf.base[offset++] = '2';
    }
    buf.base[offset++] = ' ';
    APPEND(req->input.authority.base, req->input.authority.len);
    APPEND_STRLIT("\r\n\r\n");

#undef RESERVE
#undef APPEND
#undef APPEND_STRLIT
#undef FLATTEN_PREFIXED_VALUE

    /* set the length */
    assert(offset <= buf.len);
    buf.len = offset;

    return buf;
}
Exemple #10
0
    Keywords::Keywords() {
        RESERVE(RW_ABSENT, "ABSENT");
        RESERVE(RW_FALSE, "FALSE");
        RESERVE(RW_TRUE, "TRUE");
        RESERVE(RW_UNDEFINED, "UNDEFINED");
        RESERVE(RW_BASED, "based");
        RESERVE(RW_BREAK, "break");
        RESERVE(RW_CASE, "case");
        RESERVE(RW_CLASS, "class");
        RESERVE(RW_CREATE, "create");
        RESERVE(RW_DEFAULT, "default");
        RESERVE(RW_DESTROY, "destroy");
        RESERVE(RW_DISPLAY, "display");
        RESERVE(RW_DO, "do");
        RESERVE(RW_EACH, "each");
        RESERVE(RW_ELSE, "else");
        RESERVE(RW_END, "end");
        RESERVE(RW_FOR, "for");
        RESERVE(RW_IF, "if");
        RESERVE(RW_INCLUDE, "include");
        RESERVE(RW_KEY, "key");
        RESERVE(RW_KEYWORD, "keyword");
        RESERVE(RW_MESSAGE, "message");
        RESERVE(RW_METHODS, "methods");
        RESERVE(RW_NAMED, "named");
        RESERVE(RW_OF, "of");
        RESERVE(RW_ON, "on");
        RESERVE(RW_READ, "read");
        RESERVE(RW_SELF, "self");
        RESERVE(RW_SENDER, "sender");
        RESERVE(RW_STOP, "stop");
        RESERVE(RW_THEN, "then");
        RESERVE(RW_TYPE, "type");
        RESERVE(RW_WHILE, "while");
        RESERVE(RW_WRITE, "write");
        RESERVE(RW_WRITES, "writes");

        OPERATOR(OP_PAIR, "@");
        OPERATOR(OP_CONCAT, "&");
        OPERATOR(OP_C_CONCAT, "&:=");
        OPERATOR(OP_MULTIPLY, "*");
        OPERATOR(OP_C_MULTIPLY, "*:=");
        OPERATOR(OP_PLUS, "+");
        OPERATOR(OP_C_PLUS, "+:=");
        OPERATOR(OP_MINUS, "-");
        OPERATOR(OP_PASS, "-->");
        OPERATOR(OP_C_MINUS, "-:=");
        OPERATOR(OP_SEND, "->");
        OPERATOR(OP_DOT, ".");
        OPERATOR(OP_DIVIDE, "/");
        OPERATOR(OP_C_DIVIDE, "/:=");
        OPERATOR(OP_ASSIGN, ":=");
        OPERATOR(OP_LT, "<");
        OPERATOR(OP_LE, "<=");
        OPERATOR(OP_EQ, "=");
        OPERATOR(OP_NE, "~=");
        OPERATOR(OP_GT, ">");
        OPERATOR(OP_GE, ">=");
        OPERATOR(OP_RANDOM, "?");
        OPERATOR(OP_POWER, "^");
        OPERATOR(OP_AND, "and");
        OPERATOR(OP_CHS, "chs");
        OPERATOR(OP_LEFTFROM, "leftfrom");
        OPERATOR(OP_LENGTH, "length");
        OPERATOR(OP_NOT, "not");
        OPERATOR(OP_NUMERIC, "numeric");
        OPERATOR(OP_OR, "or");
        OPERATOR(OP_RIGHTFROM, "rightfrom");
        OPERATOR(OP_STRING, "string");
        OPERATOR(OP_WITHIN, "within");
        OPERATOR(OP_HEAD, "head");
        OPERATOR(OP_TAIL, "tail");
    }
Exemple #11
0
static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket_handshake, int use_proxy_protocol)
{
    h2o_iovec_t buf;
    size_t offset = 0, remote_addr_len = SIZE_MAX;
    char remote_addr[NI_MAXHOST];
    struct sockaddr_storage ss;
    socklen_t sslen;
    h2o_iovec_t cookie_buf = {NULL}, xff_buf = {NULL}, via_buf = {NULL};
    int preserve_x_forwarded_proto = req->conn->ctx->globalconf->proxy.preserve_x_forwarded_proto;
    int emit_x_forwarded_headers = req->conn->ctx->globalconf->proxy.emit_x_forwarded_headers;
    int emit_via_header = req->conn->ctx->globalconf->proxy.emit_via_header;

    /* for x-f-f */
    if ((sslen = req->conn->callbacks->get_peername(req->conn, (void *)&ss)) != 0)
        remote_addr_len = h2o_socket_getnumerichost((void *)&ss, sslen, remote_addr);

    /* build response */
    buf.len = req->method.len + req->path.len + req->authority.len + 512;
    if (use_proxy_protocol)
        buf.len += H2O_PROXY_HEADER_MAX_LENGTH;
    buf.base = h2o_mem_alloc_pool(&req->pool, buf.len);

#define RESERVE(sz)                                                                                                                \
    do {                                                                                                                           \
        size_t required = offset + sz + 4 /* for "\r\n\r\n" */;                                                                    \
        if (required > buf.len) {                                                                                                  \
            do {                                                                                                                   \
                buf.len *= 2;                                                                                                      \
            } while (required > buf.len);                                                                                          \
            char *newp = h2o_mem_alloc_pool(&req->pool, buf.len);                                                                  \
            memcpy(newp, buf.base, offset);                                                                                        \
            buf.base = newp;                                                                                                       \
        }                                                                                                                          \
    } while (0)
#define APPEND(s, l)                                                                                                               \
    do {                                                                                                                           \
        memcpy(buf.base + offset, (s), (l));                                                                                       \
        offset += (l);                                                                                                             \
    } while (0)
#define APPEND_STRLIT(lit) APPEND((lit), sizeof(lit) - 1)
#define FLATTEN_PREFIXED_VALUE(prefix, value, add_size)                                                                            \
    do {                                                                                                                           \
        RESERVE(sizeof(prefix) - 1 + value.len + 2 + add_size);                                                                    \
        APPEND_STRLIT(prefix);                                                                                                     \
        if (value.len != 0) {                                                                                                      \
            APPEND(value.base, value.len);                                                                                         \
            if (add_size != 0) {                                                                                                   \
                buf.base[offset++] = ',';                                                                                          \
                buf.base[offset++] = ' ';                                                                                          \
            }                                                                                                                      \
        }                                                                                                                          \
    } while (0)

    if (use_proxy_protocol)
        offset += h2o_stringify_proxy_header(req->conn, buf.base + offset);

    APPEND(req->method.base, req->method.len);
    buf.base[offset++] = ' ';
    APPEND(req->path.base, req->path.len);
    APPEND_STRLIT(" HTTP/1.1\r\nconnection: ");
    if (is_websocket_handshake) {
        APPEND_STRLIT("upgrade\r\nupgrade: websocket\r\nhost: ");
    } else if (keepalive) {
        APPEND_STRLIT("keep-alive\r\nhost: ");
    } else {
        APPEND_STRLIT("close\r\nhost: ");
    }
    APPEND(req->authority.base, req->authority.len);
    buf.base[offset++] = '\r';
    buf.base[offset++] = '\n';
    assert(offset <= buf.len);
    if (req->entity.base != NULL || req_requires_content_length(req)) {
        RESERVE(sizeof("content-length: " H2O_UINT64_LONGEST_STR) - 1);
        offset += sprintf(buf.base + offset, "content-length: %zu\r\n", req->entity.len);
    }

    /* rewrite headers if necessary */
    h2o_headers_t req_headers = req->headers;
    if (req->overrides != NULL && req->overrides->headers_cmds != NULL) {
        req_headers.entries = NULL;
        req_headers.size = 0;
        req_headers.capacity = 0;
        h2o_headers_command_t *cmd;
        h2o_vector_reserve(&req->pool, &req_headers, req->headers.capacity);
        memcpy(req_headers.entries, req->headers.entries, sizeof(req->headers.entries[0]) * req->headers.size);
        req_headers.size = req->headers.size;
        for (cmd = req->overrides->headers_cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd)
            h2o_rewrite_headers(&req->pool, &req_headers, cmd);
    }

    {
        const h2o_header_t *h, *h_end;
        for (h = req_headers.entries, h_end = h + req_headers.size; h != h_end; ++h) {
            if (h2o_iovec_is_token(h->name)) {
                const h2o_token_t *token = (void *)h->name;
                if (token->proxy_should_drop) {
                    continue;
                } else if (token == H2O_TOKEN_COOKIE) {
                    /* merge the cookie headers; see HTTP/2 8.1.2.5 and HTTP/1 (RFC6265 5.4) */
                    /* FIXME current algorithm is O(n^2) against the number of cookie headers */
                    cookie_buf = build_request_merge_headers(&req->pool, cookie_buf, h->value, ';');
                    continue;
                } else if (token == H2O_TOKEN_VIA) {
                    if (!emit_via_header) {
                        goto AddHeader;
                    }
                    via_buf = build_request_merge_headers(&req->pool, via_buf, h->value, ',');
                    continue;
                } else if (token == H2O_TOKEN_X_FORWARDED_FOR) {
                    if (!emit_x_forwarded_headers) {
                        goto AddHeader;
                    }
                    xff_buf = build_request_merge_headers(&req->pool, xff_buf, h->value, ',');
                    continue;
                }
            }
            if (!preserve_x_forwarded_proto && h2o_lcstris(h->name->base, h->name->len, H2O_STRLIT("x-forwarded-proto")))
                continue;
        AddHeader:
            RESERVE(h->name->len + h->value.len + 2);
            APPEND(h->orig_name ? h->orig_name : h->name->base, h->name->len);
            buf.base[offset++] = ':';
            buf.base[offset++] = ' ';
            APPEND(h->value.base, h->value.len);
            buf.base[offset++] = '\r';
            buf.base[offset++] = '\n';
        }
    }
    if (cookie_buf.len != 0) {
        FLATTEN_PREFIXED_VALUE("cookie: ", cookie_buf, 0);
        buf.base[offset++] = '\r';
        buf.base[offset++] = '\n';
    }
    if (emit_x_forwarded_headers) {
        if (!preserve_x_forwarded_proto) {
            FLATTEN_PREFIXED_VALUE("x-forwarded-proto: ", req->input.scheme->name, 0);
            buf.base[offset++] = '\r';
            buf.base[offset++] = '\n';
        }
        if (remote_addr_len != SIZE_MAX) {
            FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, remote_addr_len);
            APPEND(remote_addr, remote_addr_len);
        } else {
            FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, 0);
        }
        buf.base[offset++] = '\r';
        buf.base[offset++] = '\n';
    }
    if (emit_via_header) {
        FLATTEN_PREFIXED_VALUE("via: ", via_buf, sizeof("1.1 ") - 1 + req->input.authority.len);
        if (req->version < 0x200) {
            buf.base[offset++] = '1';
            buf.base[offset++] = '.';
            buf.base[offset++] = '0' + (0x100 <= req->version && req->version <= 0x109 ? req->version - 0x100 : 0);
        } else {
            buf.base[offset++] = '2';
        }
        buf.base[offset++] = ' ';
        APPEND(req->input.authority.base, req->input.authority.len);
        buf.base[offset++] = '\r';
        buf.base[offset++] = '\n';
    }
    APPEND_STRLIT("\r\n");

#undef RESERVE
#undef APPEND
#undef APPEND_STRLIT
#undef FLATTEN_PREFIXED_VALUE

    /* set the length */
    assert(offset <= buf.len);
    buf.len = offset;

    return buf;
}
Exemple #12
0
static void log_access(h2o_logger_t *_self, h2o_req_t *req)
{
    struct st_h2o_access_logger_t *self = (struct st_h2o_access_logger_t *)_self;
    h2o_access_log_filehandle_t *fh = self->fh;
    char *line, *pos, *line_end;
    size_t element_index;

    /* note: LOG_ALLOCA_SIZE should be much greater than NI_MAXHOST to avoid unnecessary reallocations */
    line = alloca(LOG_ALLOCA_SIZE);
    pos = line;
    line_end = line + LOG_ALLOCA_SIZE;

    for (element_index = 0; element_index != fh->num_elements; ++element_index) {
        struct log_element_t *element = fh->elements + element_index;

/* reserve capacity + suffix.len */
#define RESERVE(capacity)                                                                                                          \
    do {                                                                                                                           \
        if ((capacity) + element->suffix.len > line_end - pos) {                                                                   \
            size_t off = pos - line;                                                                                               \
            line = expand_line_buf(line, line_end - line, off + (capacity) + element->suffix.len);                                 \
            pos = line + off;                                                                                                      \
        }                                                                                                                          \
    } while (0)

        switch (element->type) {
        case ELEMENT_TYPE_EMPTY:
            RESERVE(0);
            break;
        case ELEMENT_TYPE_BYTES_SENT: /* %b */
            RESERVE(sizeof("18446744073709551615") - 1);
            pos += sprintf(pos, "%llu", (unsigned long long)req->bytes_sent);
            break;
        case ELEMENT_TYPE_PROTOCOL: /* %H */
            RESERVE(sizeof("HTTP/1.1"));
            pos += h2o_stringify_protocol_version(pos, req->version);
            break;
        case ELEMENT_TYPE_REMOTE_ADDR: /* %h */ {
            struct sockaddr_storage ss;
            socklen_t sslen;
            if ((sslen = req->conn->get_peername(req->conn, (void *)&ss)) != 0) {
                RESERVE(NI_MAXHOST);
                size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, pos);
                if (l != SIZE_MAX)
                    pos += l;
                else
                    *pos++ = '-';
            } else {
                RESERVE(1);
                *pos++ = '-';
            }
        } break;
        case ELEMENT_TYPE_METHOD: /* %m */
            RESERVE(req->input.method.len * 4);
            pos = append_unsafe_string(pos, req->input.method.base, req->input.method.len);
            break;
        case ELEMENT_TYPE_QUERY: /* %q */
            if (req->input.query_at != SIZE_MAX) {
                size_t len = req->input.path.len - req->input.query_at;
                RESERVE(len * 4);
                pos = append_unsafe_string(pos, req->input.path.base + req->input.query_at, len);
            }
            break;
        case ELEMENT_TYPE_REQUEST_LINE: /* %r */
            RESERVE((req->input.method.len + req->input.path.len) * 4 + sizeof("  HTTP/1.1"));
            pos = append_unsafe_string(pos, req->input.method.base, req->input.method.len);
            *pos++ = ' ';
            pos = append_unsafe_string(pos, req->input.path.base, req->input.path.len);
            *pos++ = ' ';
            pos += h2o_stringify_protocol_version(pos, req->version);
            break;
        case ELEMENT_TYPE_STATUS: /* %s */
            RESERVE(sizeof("2147483647") - 1);
            pos += sprintf(pos, "%d", req->res.status);
            break;
        case ELEMENT_TYPE_TIMESTAMP: /* %t */
            RESERVE(H2O_TIMESTR_LOG_LEN + 2);
            *pos++ = '[';
            pos = append_safe_string(pos, req->processed_at.str->log, H2O_TIMESTR_LOG_LEN);
            *pos++ = ']';
            break;
        case ELEMENT_TYPE_URL_PATH: /* %U */
        {
            size_t path_len = req->input.query_at == SIZE_MAX ? req->input.path.len : req->input.query_at;
            RESERVE(req->input.scheme->name.len + (sizeof("://") - 1) + (req->input.authority.len + path_len) * 4);
            pos = append_safe_string(pos, req->input.scheme->name.base, req->input.scheme->name.len);
            pos = append_safe_string(pos, H2O_STRLIT("://"));
            pos = append_unsafe_string(pos, req->input.authority.base, req->input.authority.len);
            pos = append_unsafe_string(pos, req->input.path.base, path_len);
        } break;
        case ELEMENT_TYPE_AUTHORITY: /* %V */
            RESERVE(req->input.authority.len * 4);
            pos = append_unsafe_string(pos, req->input.authority.base, req->input.authority.len);
            break;
        case ELEMENT_TYPE_HOSTCONF: /* %v */
            RESERVE(req->hostconf->authority.hostport.len * 4);
            pos = append_unsafe_string(pos, req->hostconf->authority.hostport.base, req->hostconf->authority.hostport.len);
            break;

        case ELEMENT_TYPE_LOGNAME:     /* %l */
        case ELEMENT_TYPE_REMOTE_USER: /* %u */
            RESERVE(1);
            *pos++ = '-';
            break;

#define EMIT_HEADER(headers, _index)                                                                                               \
    do {                                                                                                                           \
        ssize_t index = (_index);                                                                                                  \
        if (index != -1) {                                                                                                         \
            const h2o_header_t *header = (headers)->entries + index;                                                               \
            RESERVE(header->value.len * 4);                                                                                        \
            pos = append_unsafe_string(pos, header->value.base, header->value.len);                                                \
        } else {                                                                                                                   \
            RESERVE(1);                                                                                                            \
            *pos++ = '-';                                                                                                          \
        }                                                                                                                          \
    } while (0)
        case ELEMENT_TYPE_IN_HEADER_TOKEN:
            EMIT_HEADER(&req->headers, h2o_find_header(&req->headers, element->data.header_token, SIZE_MAX));
            break;
        case ELEMENT_TYPE_IN_HEADER_STRING:
            EMIT_HEADER(&req->headers, h2o_find_header_by_str(&req->headers, element->data.header_string.base,
                                                              element->data.header_string.len, SIZE_MAX));
            break;
        case ELEMENT_TYPE_OUT_HEADER_TOKEN:
            EMIT_HEADER(&req->res.headers, h2o_find_header(&req->res.headers, element->data.header_token, SIZE_MAX));
            break;
        case ELEMENT_TYPE_OUT_HEADER_STRING:
            EMIT_HEADER(&req->res.headers, h2o_find_header_by_str(&req->res.headers, element->data.header_string.base,
                                                                  element->data.header_string.len, SIZE_MAX));
            break;
#undef EMIT_HEADER

        default:
            assert(!"unknown type");
            break;
        }

#undef RESERVE

        pos = append_safe_string(pos, element->suffix.base, element->suffix.len);
    }

    write(fh->fd, line, pos - line);

    if (line_end - line != LOG_ALLOCA_SIZE)
        free(line);
}
Exemple #13
0
static void log_access(h2o_logger_t *_self, h2o_req_t *req)
{
    struct st_h2o_access_logger_t *self = (struct st_h2o_access_logger_t*)_self;
    char *line, *pos, *line_end;
    size_t element_index;

    line = alloca(LOG_ALLOCA_SIZE);
    pos = line;
    line_end = line + LOG_ALLOCA_SIZE;

    for (element_index = 0; element_index != self->num_elements; ++element_index) {
        struct log_element_t *element = self->elements + element_index;

    /* reserve capacity + suffix.len */
#define RESERVE(capacity) \
    do { \
        if ((capacity) + element->suffix.len > line_end - pos) { \
            size_t off = pos - line; \
            line = expand_line_buf(line, line_end - line, off + (capacity) + element->suffix.len); \
            pos = line + off; \
        } \
    } while (0)

        switch (element->type) {
        case ELEMENT_TYPE_EMPTY:
            RESERVE(0);
            break;
        case ELEMENT_TYPE_REMOTE_ADDR:
            if (req->conn->peername != NULL && req->conn->peername->sa_family == AF_INET) {
                uint32_t addr;
                RESERVE(sizeof("255.255.255.255") - 1);
                addr = htonl(((struct sockaddr_in*)req->conn->peername)->sin_addr.s_addr);
                pos += sprintf(pos, "%d.%d.%d.%d", addr >> 24, (addr >> 16) & 255, (addr >> 8) & 255, addr & 255);
            } else {
                RESERVE(1);
                *pos++ = '-';
            }
            break;
        case ELEMENT_TYPE_LOGNAME:
        case ELEMENT_TYPE_REMOTE_USER:
            RESERVE(1);
            *pos++ = '-';
            break;
        case ELEMENT_TYPE_TIMESTAMP:
            RESERVE(H2O_TIMESTR_LOG_LEN + 2);
            *pos++ = '[';
            pos = append_safe_string(pos, req->processed_at.str->log, H2O_TIMESTR_LOG_LEN);
            *pos++ = ']';
            break;
        case ELEMENT_TYPE_REQUEST_LINE:
            RESERVE((req->method.len + req->path.len) * 4 + sizeof("  HTTP/1.2147483647") - 1);
            pos = append_unsafe_string(pos, req->method.base, req->method.len);
            *pos++ = ' ';
            pos = append_unsafe_string(pos, req->path.base, req->path.len);
            *pos++ = ' ';
            if (req->version < 0x200) {
                pos = append_safe_string(pos, H2O_STRLIT("HTTP/1."));
                if ((req->version & 0xff) <= 9) {
                    *pos++ = '0' + (req->version & 0xff);
                } else {
                    pos += sprintf(pos, "%d", req->version);
                }
            } else {
                pos = append_safe_string(pos, H2O_STRLIT("HTTP/2"));
            }
            break;
        case ELEMENT_TYPE_STATUS:
            RESERVE(sizeof("2147483647") - 1);
            pos += sprintf(pos, "%d", req->res.status);
            break;
        case ELEMENT_TYPE_BYTES_SENT:
            RESERVE(sizeof("18446744073709551615") - 1);
            pos += sprintf(pos, "%llu", (unsigned long long)req->bytes_sent);
            break;
        default:
            assert(!"unknown type");
            break;
        }