Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1195 lines (987 sloc) 27.759 kB
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* Cherokee
*
* Authors:
* Alvaro Lopez Ortega <alvaro@alobbs.com>
*
* Copyright (C) 2001-2011 Alvaro Lopez Ortega
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "common-internal.h"
#include "header.h"
#include "header-protected.h"
#include "util.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <ctype.h>
#define ENTRIES "header"
#if 0
# define HEADER_INTERNAL_DEBUG
#endif
#ifdef HEADER_INTERNAL_DEBUG
# define HEADER_INTERNAL_CHECK(h) \
do { if (cherokee_buffer_crc32 (h->input_buffer) != h->input_buffer_crc) \
fprintf (stderr, "Header sanity check failed: %s, line %d\n", __FILE__, __LINE__); \
} while(0)
#else
# define HEADER_INTERNAL_CHECK(h)
#endif
#define cmp_str(l,s) (strncmp(l, s, sizeof(s)-1) == 0)
static void
clean_known_headers (cherokee_header_t *hdr)
{
int i;
for (i=0; i<HEADER_LENGTH; i++) {
hdr->header[i].info_off = 0;
hdr->header[i].info_len = -1;
}
}
static void
clean_unknown_headers (cherokee_header_t *hdr)
{
if (hdr->unknowns != NULL) {
free (hdr->unknowns);
hdr->unknowns = NULL;
hdr->unknowns_len = 0;
}
}
static void
clean_headers (cherokee_header_t *hdr)
{
clean_known_headers (hdr);
clean_unknown_headers (hdr);
}
ret_t
cherokee_header_init (cherokee_header_t *hdr, cherokee_header_type_t type)
{
/* Known headers
*/
hdr->type = type;
clean_known_headers (hdr);
/* Unknown headers
*/
hdr->unknowns = NULL;
hdr->unknowns_len = 0;
/* Properties
*/
hdr->method = http_unknown;
hdr->version = http_version_unknown;
hdr->response = http_unset;
/* Request
*/
hdr->request_off = 0;
hdr->request_len = 0;
hdr->request_args_len = 0;
/* Query string
*/
hdr->query_string_off = 0;
hdr->query_string_len = 0;
/* Sanity
*/
hdr->input_buffer = NULL;
hdr->input_buffer_crc = 0;
hdr->input_header_len = 0;
return ret_ok;
}
ret_t
cherokee_header_mrproper (cherokee_header_t *hdr)
{
clean_unknown_headers (hdr);
return ret_ok;
}
ret_t
cherokee_header_new (cherokee_header_t **hdr, cherokee_header_type_t type)
{
ret_t ret;
CHEROKEE_NEW_STRUCT (n, header);
ret = cherokee_header_init (n, type);
if (unlikely (ret != ret_ok)) return ret;
*hdr = n;
return ret_ok;
}
CHEROKEE_ADD_FUNC_FREE (header);
ret_t
cherokee_header_clean (cherokee_header_t *hdr)
{
clean_headers (hdr);
hdr->method = http_unknown;
hdr->version = http_version_unknown;
hdr->response = http_unset;
hdr->input_header_len = 0;
hdr->request_off = 0;
hdr->request_len = 0;
hdr->query_string_off = 0;
hdr->query_string_len = 0;
return ret_ok;
}
static ret_t
add_known_header (cherokee_header_t *hdr, cherokee_common_header_t header, off_t info_off, int info_len)
{
HEADER_INTERNAL_CHECK(hdr);
hdr->header[header].info_off = info_off;
hdr->header[header].info_len = info_len;
return ret_ok;
}
static ret_t
add_unknown_header (cherokee_header_t *hdr, off_t header_off, off_t info_off, int info_len)
{
cherokee_header_unknown_entry_t *entry;
hdr->unknowns_len++;
hdr->unknowns = (cherokee_header_unknown_entry_t *) realloc (
hdr->unknowns, sizeof(cherokee_header_unknown_entry_t) * hdr->unknowns_len);
if (hdr->unknowns == NULL) {
return ret_nomem;
}
entry = &hdr->unknowns[hdr->unknowns_len-1];
entry->header_off = header_off;
entry->header_info_off = info_off;
entry->header_info_len = info_len;
return ret_ok;
}
static ret_t
parse_response_first_line (cherokee_header_t *hdr, cherokee_buffer_t *buf, char **next_pos, cherokee_http_t *error_code)
{
ret_t ret;
char tmp[4];
char *end;
size_t len;
char *line = buf->buf;
char *begin = buf->buf;
/* NOTE: here we deal only with HTTP/1.0 or higher.
*/
len = strcspn(line, CRLF);
end = &line[len];
/* Some security checks
*/
if (len < 14 || buf->len < 14) {
return ret_error;
}
/* Return next line
*/
switch (*end) {
case CHR_CR:
if (end[1] != CHR_LF)
return ret_error;
*next_pos = end + 2;
break;
case CHR_LF:
*next_pos = end + 1;
break;
default:
return ret_error;
}
/* Example:
* HTTP/1.0 403 Forbidden
*/
if (unlikely(! cmp_str(begin, "HTTP/1."))) {
/* TODO: improve parser
* (if ! "HTTP/" then leave default http_bad_request).
*/
*error_code = http_version_not_supported;
return ret_error;
}
if (unlikely(! isdigit(begin[7]))) {
return ret_error;
}
/* Get the HTTP version
*/
switch (begin[7]) {
case '0':
hdr->version = http_version_10;
break;
case '1':
default:
hdr->version = http_version_11;
break;
}
/* Read the response code
* TODO: skip spaces properly (usually there is only one blank).
*/
memcpy (tmp, begin+9, 3);
tmp[3] = '\0';
ret = cherokee_atoi (tmp, (int *)&hdr->response);
if (unlikely (ret != ret_ok)) {
return ret_error;
}
return ret_ok;
}
static ret_t
parse_method (cherokee_header_t *hdr, char *line, char *end, char **pointer)
{
char *p;
char chr = *line;
#define detect_method(l,str,mthd) \
if (cmp_str (line, (str" "))) { \
hdr->method = http_ ## mthd; \
*pointer += sizeof(str); \
return ret_ok; \
}
/* Check the first letter of the method name, if it matches it
* can continue with the rest.
*/
switch (chr) {
case 'G':
detect_method (line, "GET", get)
break;
case 'P':
detect_method (line, "POST", post)
else
detect_method (line, "PUT", put)
else
detect_method (line, "PURGE", purge)
else
detect_method (line, "POLL", poll)
else
detect_method (line, "PROPFIND", propfind)
else
detect_method (line, "PROPPATCH", proppatch)
break;
case 'H':
detect_method (line, "HEAD", head)
break;
case 'O':
detect_method (line, "OPTIONS", options)
break;
case 'D':
detect_method (line, "DELETE", delete)
break;
case 'T':
detect_method (line, "TRACE", trace)
break;
case 'C':
detect_method (line, "CHECKIN", checkin)
else
detect_method (line, "CHECKOUT", checkout)
else
detect_method (line, "CONNECT", connect)
else
detect_method (line, "COPY", copy)
break;
case 'L':
detect_method (line, "LABEL", label)
else
detect_method (line, "LOCK", lock)
break;
case 'M':
detect_method (line, "MERGE", merge)
else
detect_method (line, "MKACTIVITY", mkactivity)
else
detect_method (line, "MKCOL", mkcol)
else
detect_method (line, "MKWORKSPACE", mkworkspace)
else
detect_method (line, "MOVE", move)
break;
case 'N':
detect_method (line, "NOTIFY", notify)
break;
case 'S':
detect_method (line, "SEARCH", search)
else
detect_method (line, "SUBSCRIBE", subscribe)
break;
case 'U':
detect_method (line, "UPDATE", update)
else
detect_method (line, "UNCHECKOUT", uncheckout)
else
detect_method (line, "UNLOCK", unlock)
else
detect_method (line, "UNSUBSCRIBE", unsubscribe)
break;
case 'R':
detect_method (line, "REPORT", report)
break;
case 'V':
detect_method (line, "VERSION_CONTROL", version_control)
break;
case 'B':
detect_method (line, "BASELINE_CONTROL", baseline_control)
break;
case 'I':
detect_method (line, "INVALID", invalid)
break;
}
/* The method was not matched. Skip the first word.
*/
p = line;
while (p < end) {
if (*p == ' ') {
hdr->method = http_unknown;
*pointer += p - line;
return ret_ok;
}
p++;
}
return ret_error;
}
static ret_t
parse_request_first_line (cherokee_header_t *hdr, cherokee_buffer_t *buf, char **next_pos, cherokee_http_t *error_code)
{
ret_t ret;
char *line = buf->buf;
char *begin = buf->buf;
char *begin_ver = buf->buf;
char *end;
char *ptr;
char *restore;
char chr_end;
size_t len = 0;
size_t len_ver = 0;
/* Basic security check. The shortest possible request
* "GET / HTTP/1.0" is 14 characters long but we want
* to reply (with an error message) to HTTP/0.9 requests too
* (HTTP/0.9 don't have " HTTP/x.x" version).
*/
if (unlikely(buf->len < 6)) {
return ret_error;
}
/* Look for the end of the request line
*/
end = strchr (line, CHR_LF);
if (unlikely(end == NULL || line == end)) {
return ret_error;
}
--end;
if (unlikely(*end != CHR_CR)) {
++end;
/* Return begin of next line
*/
len = (size_t) (end - line);
*next_pos = end + 1;
} else {
/* Return begin of next line
*/
len = (size_t) (end - line);
*next_pos = end + 2;
}
chr_end = *end;
*end = '\0';
restore = end;
/* Check shortest string length "GET /"
*/
if (len < 5)
goto error;
/* Get the method
*/
ret = parse_method (hdr, line, end, &begin);
if (unlikely (ret != ret_ok)) {
*error_code = http_not_implemented;
goto error;
}
/* Skip other blank spaces between method and URI.
*/
begin += strspn (begin, LBS);
/* Length of URI.
*/
len = strcspn (begin, LBS);
if (len == 0)
goto error;
if (begin[len] == '\0') {
/* HTTP/0.9 has no HTTP version string and
* it is not supported by this server.
*/
*error_code = http_version_not_supported;
goto error;
}
begin_ver = &begin[len];
begin_ver += strspn (begin_ver, LBS);
len_ver = (size_t) (end - begin_ver);
/* Verify "HTTP/x.x" pattern.
*/
if (len_ver != 8 ||
!isdigit(begin_ver[5]) ||
begin_ver[6] != '.' ||
!isdigit(begin_ver[7]) ||
!cmp_str (begin_ver, "HTTP/")) {
goto error;
}
/* Get the protocol version.
*/
if (begin_ver[5] != '1' || begin_ver[7] > '1') {
*error_code = http_version_not_supported;
goto error;
}
hdr->version = (begin_ver[7] == '1' ? http_version_11 : http_version_10);
/* Skip the HTTP version string: " HTTP/x.y"
*/
end = &begin[len];
/* Look for the QueryString
*/
hdr->request_args_len = len;
ptr = strchr (begin, '?');
if (ptr) {
end = ptr;
hdr->query_string_off = (off_t) (++ptr - buf->buf);
hdr->query_string_len = (cint_t) (&begin[len] - ptr);
} else {
hdr->query_string_len = 0;
}
/* Get the request
*/
hdr->request_off = (off_t) (begin - buf->buf);
hdr->request_len = (cint_t) (end - begin);
/* Check if the request is a full URL
*/
begin = buf->buf + hdr->request_off;
if (cmp_str (begin, "http://")) {
char *dir;
char *host = begin + 7;
char end_chr = *end;
if (host[0] == '/' || host[0] == '.')
goto error;
*end = '\0';
dir = strchr (host, '/');
*end = end_chr;
if (dir == NULL)
goto error;
/* Add the host header
*/
add_known_header (hdr, header_host, host - buf->buf, dir - host);
/* Fix the URL
*/
hdr->request_len -= (dir - begin);
hdr->request_off = dir - buf->buf;
}
*restore = chr_end;
return ret_ok;
error:
*restore = chr_end;
return ret_error;
}
ret_t
cherokee_header_get_length (cherokee_header_t *hdr, cuint_t *len)
{
*len = hdr->input_header_len;
return ret_ok;
}
ret_t
cherokee_header_get_unknown (cherokee_header_t *hdr,
const char *name, cuint_t name_len,
char **header, cuint_t *header_len)
{
int i;
HEADER_INTERNAL_CHECK(hdr);
for (i=0; i < hdr->unknowns_len; i++) {
char *h = hdr->unknowns[i].header_off + hdr->input_buffer->buf;
if (strncasecmp (h, name, name_len) == 0) {
*header = hdr->unknowns[i].header_info_off + hdr->input_buffer->buf;
*header_len = hdr->unknowns[i].header_info_len;
return ret_ok;
}
}
return ret_not_found;
}
ret_t
cherokee_header_copy_unknown (cherokee_header_t *hdr,
const char *name,
cuint_t name_len,
cherokee_buffer_t *buf)
{
ret_t ret;
char *info;
cuint_t info_len;
ret = cherokee_header_get_unknown (hdr, name, name_len, &info, &info_len);
if (unlikely(ret != ret_ok))
return ret;
return cherokee_buffer_add (buf, info, info_len);
}
ret_t
cherokee_header_has_known (cherokee_header_t *hdr, cherokee_common_header_t header)
{
if (hdr->header[header].info_off != 0) {
return ret_ok;
}
return ret_not_found;
}
ret_t
cherokee_header_get_known (cherokee_header_t *hdr, cherokee_common_header_t header, char **info, cuint_t *info_len)
{
HEADER_INTERNAL_CHECK(hdr);
if (hdr->header[header].info_off == 0) {
return ret_not_found;
}
*info = hdr->header[header].info_off + hdr->input_buffer->buf;
*info_len = hdr->header[header].info_len;
return ret_ok;
}
ret_t
cherokee_header_copy_known (cherokee_header_t *hdr, cherokee_common_header_t header, cherokee_buffer_t *buf)
{
ret_t ret;
char *info = NULL;
cuint_t info_len = 0;
ret = cherokee_header_get_known (hdr, header, &info, &info_len);
if (unlikely(ret != ret_ok))
return ret;
return cherokee_buffer_add (buf, info, info_len);
}
static ret_t
sanitize_buffer (cherokee_buffer_t *buf)
{
cuint_t i, j;
cuint_t removed = 0;
/* Look for the ANSI CSIs (0x1B+[, and 0x9B)
*/
for (i=0,j=0; j<buf->len;) {
if (unlikely ((j+1 < buf->len) &&
(buf->buf[i] == 0x1B) &&
(buf->buf[i+1] == '[' || buf->buf[i+1] == ']')))
{
j += 2;
removed += 2;
}
if (removed) {
buf->buf[i] = buf->buf[j];
}
i++;
j++;
}
/* Fix the buffer length
*/
if (removed) {
buf->len -= removed;
buf->buf[buf->len] = 0;
}
return ret_ok;
}
ret_t
cherokee_header_copy_request (cherokee_header_t *hdr, cherokee_buffer_t *request)
{
ret_t ret;
if ((hdr->request_off == 0) ||
(hdr->request_len <= 0)) {
return ret_error;
}
ret = cherokee_buffer_add (request, hdr->input_buffer->buf + hdr->request_off, hdr->request_len);
if (unlikely(ret < ret_ok)) {
return ret;
}
ret = cherokee_buffer_unescape_uri (request);
if (unlikely (ret != ret_ok)) {
return ret_error;
}
return sanitize_buffer (request);
}
ret_t
cherokee_header_copy_query_string (cherokee_header_t *hdr, cherokee_buffer_t *query_string)
{
ret_t ret;
if ((hdr->query_string_off == 0) ||
(hdr->query_string_len <= 0)) {
return ret_not_found;
}
ret = cherokee_buffer_add (query_string, hdr->input_buffer->buf + hdr->query_string_off, hdr->query_string_len);
if (unlikely(ret < ret_ok))
return ret;
return ret_ok;
}
ret_t
cherokee_header_get_request_w_args (cherokee_header_t *hdr, char **req, int *req_len)
{
if ((hdr->request_off == 0) ||
(hdr->request_args_len <= 0)) {
return ret_error;
}
if (req != NULL)
*req = hdr->input_buffer->buf + hdr->request_off;
if (req_len != NULL)
*req_len = hdr->request_args_len;
return ret_ok;
}
ret_t
cherokee_header_copy_request_w_args (cherokee_header_t *hdr, cherokee_buffer_t *request)
{
ret_t ret;
if ((hdr->request_off == 0) ||
(hdr->request_args_len <= 0)) {
return ret_error;
}
ret = cherokee_buffer_add (request, hdr->input_buffer->buf + hdr->request_off, hdr->request_args_len);
if (unlikely(ret < ret_ok))
return ret;
return cherokee_buffer_unescape_uri (request);
}
ret_t
cherokee_header_copy_method (cherokee_header_t *hdr, cherokee_buffer_t *buf)
{
ret_t ret;
const char *tmp;
cuint_t len;
ret = cherokee_http_method_to_string (HDR_METHOD(hdr), &tmp, &len);
if (unlikely(ret != ret_ok))
return ret;
return cherokee_buffer_add (buf, tmp, len);
}
ret_t
cherokee_header_copy_version (cherokee_header_t *hdr, cherokee_buffer_t *buf)
{
ret_t ret;
const char *tmp;
cuint_t len;
ret = cherokee_http_version_to_string (HDR_VERSION(hdr), &tmp, &len);
if (unlikely(ret != ret_ok))
return ret;
return cherokee_buffer_add (buf, tmp, len);
}
static ret_t
has_header_response (cherokee_header_t *hdr, cherokee_buffer_t *buffer)
{
char *tmp;
tmp = strstr (buffer->buf, CRLF_CRLF);
if (tmp == NULL)
return ret_not_found;
/* Content until CRLF_CRLF plus two of the last line CRLF
*/
hdr->input_header_len = (tmp - buffer->buf) + 2;
return ret_ok;
}
static ret_t
has_header_request (cherokee_header_t *hdr, cherokee_buffer_t *buffer, cuint_t tail_len)
{
ret_t ret;
char *start;
char *end;
cuint_t crlf_len = 0;
/* Skip initial CRLFs:
* NOTE: they are not allowed by standard (RFC) but many
* popular HTTP clients (including MSIE, etc.) may send a
* couple of them between two requests, so every widely used
* web server has to deal with them.
*/
crlf_len = cherokee_buffer_cnt_spn (buffer, 0, CRLF);
if (unlikely (crlf_len > MAX_HEADER_CRLF)) {
/* Too many initial CRLF
*/
return ret_error;
}
if ((crlf_len > 0) && (crlf_len < buffer->len)) {
/* Found heading CRLFs and their length is less than
* buffer length so we have to move the real content
* to the beginning of the buffer.
*/
cherokee_buffer_move_to_begin (buffer, (int) crlf_len);
}
/* Do we have enough information ?
* len("GET /" LF_LF) = 7 (HTTP/0.9)
* len("GET /" CRLF_CRLF) = 9 (HTTP/0.9)
* len("GET / HTTP/1.0" CRLF_CRLF) = 18 (HTTP/1.x)
*/
if (unlikely (buffer->len < 7)) {
return ret_not_found;
}
/* Look for the starting point
*/
start = (tail_len >= buffer->len) ?
buffer->buf : buffer->buf + (buffer->len - tail_len);
/* It could be a partial header, or maybe a POST request
*/
ret = cherokee_find_header_end_cstr (start,
(buffer->buf + buffer->len) - start,
&end, &crlf_len);
if (ret != ret_ok) {
return ret_not_found;
}
hdr->input_header_len = ((int) (end - buffer->buf)) + crlf_len;
return ret_ok;
}
ret_t
cherokee_header_has_header (cherokee_header_t *hdr, cherokee_buffer_t *buffer, int tail_len)
{
switch (hdr->type) {
case header_type_request:
return has_header_request (hdr, buffer, tail_len);
case header_type_response:
case header_type_basic:
return has_header_response (hdr, buffer);
default:
SHOULDNT_HAPPEN;
}
return ret_error;
}
ret_t
cherokee_header_parse (cherokee_header_t *hdr, cherokee_buffer_t *buffer, cherokee_http_t *error_code)
{
ret_t ret;
char *val_beg;
char *val_end;
char *header_end;
char chr_header_end;
char *begin = buffer->buf;
char *end = NULL;
/* Set default error code.
*/
*error_code = http_bad_request;
/* Check the buffer content
*/
if ((buffer->buf == NULL) || (buffer->len < 5)) {
LOG_ERROR_S (CHEROKEE_ERROR_HEADER_EMPTY);
return ret_error;
}
/* Set the header buffer
*/
hdr->input_buffer = buffer;
#ifdef HEADER_INTERNAL_DEBUG
hdr->input_buffer_crc = cherokee_buffer_crc32 (buffer);
#endif
/* header_len should have already been set by a previous call
* to cherokee_header_has_header() but if not we call it now.
*/
if (unlikely (hdr->input_header_len < 1)) {
/* Strange, anyway go on and look for EOH
*/
ret = has_header_request (hdr, buffer, buffer->len);
if (ret != ret_ok) {
if (ret == ret_not_found) {
LOG_ERROR (CHEROKEE_ERROR_HEADER_NO_EOH,
buffer->len, buffer->buf);
} else {
LOG_ERROR_S (CHEROKEE_ERROR_HEADER_TOO_MANY_CRLF);
}
return ret_error;
}
}
header_end = &(buffer->buf[hdr->input_header_len]);
/* Terminate current request space (there may be other
* pipelined requests in the buffer) after the EOH.
*/
chr_header_end = *header_end;
*header_end = '\0';
TRACE(ENTRIES, "Incoming header:\n%s", buffer->buf);
/* Parse the special first line
*/
switch (hdr->type) {
case header_type_request:
/* Parse request. Something like this:
* GET /icons/compressed.png HTTP/1.1CRLF
*/
ret = parse_request_first_line (hdr, buffer, &begin, error_code);
if (unlikely(ret < ret_ok)) {
PRINT_DEBUG ("ERROR: Failed to parse header_type_request:\n===\n%s===\n", buffer->buf);
*header_end = chr_header_end;
return ret;
}
break;
case header_type_response:
ret = parse_response_first_line (hdr, buffer, &begin, error_code);
if (unlikely(ret < ret_ok)) {
PRINT_DEBUG ("ERROR: Failed to parse header_type_response:\n===\n%s===\n", buffer->buf);
*header_end = chr_header_end;
return ret;
}
break;
case header_type_basic:
/* Don't do anything
*/
break;
default:
*header_end = chr_header_end;
SHOULDNT_HAPPEN;
}
/* Parse the rest of headers
*/
while ((begin < header_end)) {
cuint_t header_len;
int val_offs;
int val_len;
char first_char;
char chr_end;
/* Check where the line ends
*/
end = cherokee_header_get_next_line (begin);
if (end == NULL)
break;
chr_end = *end;
*end = '\0';
/* Current line may have embedded CR+SP or CRLF+SP
*/
val_beg = strchr (begin, ':');
if (unlikely (val_beg == NULL))
goto next;
/* Header name must be at least 1 character long.
*/
if (unlikely (val_beg == begin))
goto next;
/* Empty values are skipped.
*/
if (unlikely (end <= val_beg + 1))
goto next;
header_len = val_beg - begin;
/* Trim heading and leading spaces from header value.
*/
++val_beg;
val_beg += strspn(val_beg, LWS);
val_end = end - 1;
while (val_end > val_beg && isspace(*val_end)) {
val_end--;
}
val_end++;
val_offs = val_beg - buffer->buf;
val_len = val_end - val_beg;
if (unlikely (val_len < 1))
goto next;
first_char = *begin;
if (first_char > 'Z')
first_char -= 'a' - 'A';
#define header_equals(str,hdr_enum,begin,len) ((len == (sizeof(str)-1)) && \
(hdr->header[hdr_enum].info_off == 0) && \
(strncasecmp (begin, str, sizeof(str)-1) == 0))
switch (first_char) {
case 'A':
if (header_equals ("Accept-Encoding", header_accept_encoding, begin, header_len)) {
ret = add_known_header (hdr, header_accept_encoding, val_offs, val_len);
} else if (header_equals ("Accept-Charset", header_accept_charset, begin, header_len)) {
ret = add_known_header (hdr, header_accept_charset, val_offs, val_len);
} else if (header_equals ("Accept-Language", header_accept_language, begin, header_len)) {
ret = add_known_header (hdr, header_accept_language, val_offs, val_len);
} else if (header_equals ("Accept", header_accept, begin, header_len)) {
ret = add_known_header (hdr, header_accept, val_offs, val_len);
} else if (header_equals ("Authorization", header_authorization, begin, header_len)) {
ret = add_known_header (hdr, header_authorization, val_offs, val_len);
} else
goto unknown;
break;
case 'C':
if (header_equals ("Connection", header_connection, begin, header_len)) {
ret = add_known_header (hdr, header_connection, val_offs, val_len);
} else if (header_equals ("Content-Length", header_content_length, begin, header_len)) {
ret = add_known_header (hdr, header_content_length, val_offs, val_len);
} else if (header_equals ("Content-Type", header_content_type, begin, header_len)) {
ret = add_known_header (hdr, header_content_type, val_offs, val_len);
} else if (header_equals ("Cookie", header_cookie, begin, header_len)) {
ret = add_known_header (hdr, header_cookie, val_offs, val_len);
} else
goto unknown;
break;
case 'E':
if (header_equals ("Expect", header_expect, begin, header_len)) {
ret = add_known_header (hdr, header_expect, val_offs, val_len);
} else
goto unknown;
break;
case 'H':
if (header_equals ("Host", header_host, begin, header_len)) {
ret = add_known_header (hdr, header_host, val_offs, val_len);
} else
goto unknown;
break;
case 'I':
if (header_equals ("If-Modified-Since", header_if_modified_since, begin, header_len)) {
ret = add_known_header (hdr, header_if_modified_since, val_offs, val_len);
} else if (header_equals ("If-None-Match", header_if_none_match, begin, header_len)) {
ret = add_known_header (hdr, header_if_none_match, val_offs, val_len);
} else if (header_equals ("If-Range", header_if_range, begin, header_len)) {
ret = add_known_header (hdr, header_if_range, val_offs, val_len);
} else
goto unknown;
break;
case 'K':
if (header_equals ("Keep-Alive", header_keepalive, begin, header_len)) {
ret = add_known_header (hdr, header_keepalive, val_offs, val_len);
} else
goto unknown;
break;
case 'L':
if (header_equals ("Location", header_location, begin, header_len)) {
ret = add_known_header (hdr, header_location, val_offs, val_len);
} else
goto unknown;
break;
case 'R':
if (header_equals ("Range", header_range, begin, header_len)) {
ret = add_known_header (hdr, header_range, val_offs, val_len);
} else if (header_equals ("Referer", header_referer, begin, header_len)) {
ret = add_known_header (hdr, header_referer, val_offs, val_len);
} else
goto unknown;
break;
case 'S':
if (header_equals ("Set-Cookie", header_set_cookie, begin, header_len)) {
ret = add_known_header (hdr, header_set_cookie, val_offs, val_len);
} else
goto unknown;
break;
case 'T':
if (header_equals ("Transfer-Encoding", header_transfer_encoding, begin, header_len)) {
ret = add_known_header (hdr, header_transfer_encoding, val_offs, val_len);
} else
goto unknown;
break;
case 'U':
if (header_equals ("Upgrade", header_upgrade, begin, header_len)) {
ret = add_known_header (hdr, header_upgrade, val_offs, val_len);
} else if (header_equals ("User-Agent", header_user_agent, begin, header_len)) {
ret = add_known_header (hdr, header_user_agent, val_offs, val_len);
} else
goto unknown;
break;
case 'X':
if (header_equals ("X-Forwarded-For", header_x_forwarded_for, begin, header_len)) {
ret = add_known_header (hdr, header_x_forwarded_for, val_offs, val_len);
} else if (header_equals ("X-Forwarded-Host", header_x_forwarded_host, begin, header_len)) {
ret = add_known_header (hdr, header_x_forwarded_host, val_offs, val_len);
} else if (header_equals ("X-Real-IP", header_x_real_ip, begin, header_len)) {
ret = add_known_header (hdr, header_x_real_ip, val_offs, val_len);
} else
goto unknown;
break;
default:
unknown:
/* Add a unknown header
*/
ret = add_unknown_header (hdr, begin-buffer->buf, val_offs, val_len);
}
if (ret < ret_ok) {
LOG_ERROR_S (CHEROKEE_ERROR_HEADER_ADD_HEADER);
*header_end = chr_header_end;
return ret;
}
next:
*end = chr_end;
while ((*end == CHR_CR) || (*end == CHR_LF))
end++;
begin = end;
}
*header_end = chr_header_end;
return ret_ok;
}
ret_t
cherokee_header_foreach_unknown (cherokee_header_t *hdr, cherokee_header_foreach_func_t func, void *data)
{
int i;
cherokee_buffer_t tmp_hdr = CHEROKEE_BUF_INIT;
cherokee_buffer_t tmp_val = CHEROKEE_BUF_INIT;
HEADER_INTERNAL_CHECK(hdr);
for (i=0; i < hdr->unknowns_len; i++) {
char *begin = hdr->unknowns[i].header_off + hdr->input_buffer->buf;
char *begin_info = hdr->unknowns[i].header_info_off + hdr->input_buffer->buf;
cherokee_buffer_add (&tmp_hdr, begin,
(hdr->unknowns[i].header_info_off - 2) - hdr->unknowns[i].header_off);
cherokee_buffer_add (&tmp_val, begin_info,
hdr->unknowns[i].header_info_len);
func (&tmp_hdr, &tmp_val, data);
cherokee_buffer_clean (&tmp_hdr);
cherokee_buffer_clean (&tmp_val);
}
cherokee_buffer_mrproper (&tmp_hdr);
cherokee_buffer_mrproper (&tmp_val);
return ret_ok;
}
Jump to Line
Something went wrong with that request. Please try again.