void h2o_set_header_by_str(h2o_mempool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, const char *value, size_t value_len, int overwrite_if_exists) { ssize_t cursor; if (maybe_token) { const h2o_token_t *token = h2o_lookup_token(name, name_len); if (token != NULL) { h2o_set_header(pool, headers, token ,value, value_len, overwrite_if_exists); return; } } cursor = h2o_find_header_by_str(headers, name, name_len, -1); if (cursor != -1) { if (overwrite_if_exists) { h2o_buf_t *slot = &headers->entries[cursor].value; slot->base = (char*)value; slot->len = value_len; } } else { h2o_buf_t *name_buf = h2o_mempool_alloc(pool, sizeof(h2o_buf_t)); name_buf->base = (char*)name; name_buf->len = name_len; add_header(pool, headers, name_buf, value, value_len); } }
int h2o_is_websocket_handshake(h2o_req_t *req, const char **ws_client_key) { ssize_t key_header_index; *ws_client_key = NULL; /* method */ if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("GET"))) { /* ok */ } else { return 0; } /* upgrade header */ if (req->upgrade.base != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("websocket"))) { /* ok */ } else { return 0; } /* sec-websocket-key header */ if ((key_header_index = h2o_find_header_by_str(&req->headers, H2O_STRLIT("sec-websocket-key"), -1)) != -1) { if (req->headers.entries[key_header_index].value.len != 24) { return -1; } } else { return 0; } *ws_client_key = req->headers.entries[key_header_index].value.base; return 0; }
ssize_t h2o_set_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, const char *value, size_t value_len, int overwrite_if_exists) { ssize_t cursor; if (maybe_token) { const h2o_token_t *token = h2o_lookup_token(name, name_len); if (token != NULL) { return h2o_set_header(pool, headers, token, value, value_len, overwrite_if_exists); } } cursor = h2o_find_header_by_str(headers, name, name_len, -1); if (cursor != -1) { if (overwrite_if_exists) { h2o_iovec_t *slot = &headers->entries[cursor].value; slot->base = (char *)value; slot->len = value_len; } return cursor; } else { h2o_iovec_t *name_buf = h2o_mem_alloc_pool(pool, *name_buf, 1); name_buf->base = (char *)name; name_buf->len = name_len; return add_header(pool, headers, name_buf, NULL, value, value_len, (h2o_header_flags_t){0}); } }
static h2o_iovec_t __get_if_match_header_value(const h2o_req_t* req, const kstr_t* key) { ssize_t header = h2o_find_header(&req->headers, H2O_TOKEN_IF_MATCH, SIZE_MAX); if (-1 == header) return (h2o_iovec_t){.base = NULL, .len = 0 }; return req->headers.entries[header].value; } /** * @return 1 if the client wants an ETag; otherwise 0 */ static int __prefers_etag(const h2o_req_t* req) { ssize_t header = h2o_find_header_by_str( &req->headers, "prefers", strlen("prefers"), SIZE_MAX); if (-1 == header) return 0; if (!strncmp(req->headers.entries[header].value.base, "ETag", min(strlen("ETag"), req->headers.entries[header].value.len))) return 1; return 0; }
static h2o_header_t *find_header(h2o_headers_t *headers, h2o_headers_command_t *cmd) { size_t index; if (h2o_iovec_is_token(cmd->name)) { index = h2o_find_header(headers, (void *)cmd->name, SIZE_MAX); } else { index = h2o_find_header_by_str(headers, cmd->name->base, cmd->name->len, SIZE_MAX); } if (index == SIZE_MAX) return NULL; return headers->entries + index; }
static mrb_value h2o_mrb_get_request_headers_out(mrb_state *mrb, mrb_value self) { h2o_mruby_internal_context_t *mruby_ctx = (h2o_mruby_internal_context_t *)mrb->ud; mrb_value key; ssize_t index; h2o_header_t *h; mrb_get_args(mrb, "o", &key); key = mrb_funcall(mrb, key, "downcase", 0); index = h2o_find_header_by_str(&mruby_ctx->req->res.headers, RSTRING_PTR(key), RSTRING_LEN(key), -1); if (index == -1) return mrb_nil_value(); h = mruby_ctx->req->res.headers.entries + index; return mrb_str_new(mrb, h->value.base, h->value.len); }
static void check(const h2o_url_scheme_t *scheme, const char *host, const char *expected) { h2o_loopback_conn_t *conn = h2o_loopback_create(&ctx, ctx.globalconf->hosts); conn->req.input.method = h2o_iovec_init(H2O_STRLIT("GET")); conn->req.input.scheme = scheme; conn->req.input.authority = h2o_iovec_init(host, strlen(host)); conn->req.input.path = h2o_iovec_init(H2O_STRLIT("/")); h2o_loopback_run_loop(conn); ok(conn->req.res.status == 200); size_t index = h2o_find_header_by_str(&conn->req.res.headers, H2O_STRLIT("x-authority"), SIZE_MAX); ok(index != SIZE_MAX); if (index != SIZE_MAX) { ok(h2o_memis(conn->req.res.headers.entries[index].value.base, conn->req.res.headers.entries[index].value.len, expected, strlen(expected))); } h2o_loopback_destroy(conn); }
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); }