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; } }
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; } }
/* 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; }
/* 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; }
static void tokeniser_init(Tokeniser* t, const char* input) { t->cursor = input; t->eof = 0; t->tokenIndex = RESERVE(); tokeniser_advance(t); }
/* 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 */ }
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; */ }
/* 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; }
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; }
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"); }
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; }
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); }
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; }