Inspect Warning header, fixes #19
1 parent 91a09c2 commit 8109af01ce8506ec07d83c44c86f6305351b3379
@Andreas Jaggi Andreas Jaggi authored on 18 Sep 2011
x-way committed on 18 Sep 2011
Showing 2 changed files
View
2
■■■
README
If-Match, If-None-Match, Last-Modified, Content-Length,
Expires, Content-Language, Content-Encoding, Allow, Host,
Accept, Connection, Content-Range, User-Agent, Upgrade, Via,
From, Pragma, Content-Type, Content-MD5, Authorization, Expect,
Proxy-Authorization
Proxy-Authorization, Warning
 
Report Bugs
Create a ticket on the issue tracking interface of GitHub:
http://github.com/x-way/ngx_http_header_inspect/issues
View
237
ngx_http_header_inspect.c
 
 
 
static ngx_int_t ngx_header_inspect_init(ngx_conf_t *cf);
static ngx_int_t ngx_header_inspect_http_date(u_char *data, ngx_uint_t maxlen);
static ngx_int_t ngx_header_inspect_http_date(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len);
static ngx_int_t ngx_header_inspect_parse_base64(char* header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, u_char *data, ngx_uint_t maxlen);
static ngx_int_t ngx_header_inspect_parse_entity_tag(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len);
static ngx_int_t ngx_header_inspect_parse_languagerange(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len);
static ngx_int_t ngx_header_inspect_range_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value);
static ngx_int_t ngx_header_inspect_date_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, char *header, ngx_str_t value);
static ngx_int_t ngx_header_inspect_contentmd5_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value);
static ngx_int_t ngx_header_inspect_authorization_header(char* header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value);
static ngx_int_t ngx_header_inspect_expect_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value);
static ngx_int_t ngx_header_inspect_warning_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value);
static ngx_int_t ngx_header_inspect_process_request(ngx_http_request_t *r);
 
static void *ngx_header_inspect_create_conf(ngx_conf_t *cf);
static char *ngx_header_inspect_merge_conf(ngx_conf_t *cf, void *parent, void *child);
 
return rc;
}
 
static ngx_int_t ngx_header_inspect_http_date(u_char *data, ngx_uint_t maxlen) {
ngx_uint_t i;
static ngx_int_t ngx_header_inspect_http_date(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) {
ngx_uint_t i = 0;
enum http_date_type {RFC1123, RFC850, ASCTIME} type;
 
if ( maxlen < 24 ) {
*len = i;
return NGX_ERROR;
}
 
if ((data[0] == 'M') && (data[1] == 'o') && (data[2] == 'n')) {
(data[4] != 'a') ||
(data[5] != 'y') ||
(data[6] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 7;
break;
default:
*len = i;
return NGX_ERROR;
}
} else if ((data[0] == 'T') && (data[1] == 'u') && (data[2] == 'e')) {
/* Tue(sday) */
(data[5] != 'a') ||
(data[6] != 'y') ||
(data[7] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 8;
break;
default:
*len = i;
return NGX_ERROR;
}
} else if ((data[0] == 'W') && (data[1] == 'e') && (data[2] == 'd')) {
/* Wed(nesday) */
(data[7] != 'a') ||
(data[8] != 'y') ||
(data[9] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 10;
break;
default:
*len = i;
return NGX_ERROR;
}
} else if ((data[0] == 'T') && (data[1] == 'h') && (data[2] == 'u')) {
/* Thu(rsday) */
(data[6] != 'a') ||
(data[7] != 'y') ||
(data[8] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 9;
break;
default:
*len = i;
return NGX_ERROR;
}
} else if ((data[0] == 'F') && (data[1] == 'r') && (data[2] == 'i')) {
/* Fri(day) */
(data[4] != 'a') ||
(data[5] != 'y') ||
(data[6] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 7;
break;
default:
*len = i;
return NGX_ERROR;
}
} else if ((data[0] == 'S') && (data[1] == 'a') && (data[2] == 't')) {
/* Sat(urday) */
(data[6] != 'a') ||
(data[7] != 'y') ||
(data[8] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 9;
break;
default:
*len = i;
return NGX_ERROR;
}
} else if ((data[0] == 'S') && (data[1] == 'u') && (data[2] == 'n')) {
/* Sun(day) */
(data[4] != 'a') ||
(data[5] != 'y') ||
(data[6] != ',')
) {
*len = i;
return NGX_ERROR;
}
i = 7;
break;
default:
*len = i;
return NGX_ERROR;
}
} else {
*len = i;
return NGX_ERROR;
}
 
switch (type) {
case RFC1123:
if (maxlen != 29) {
if (maxlen < 29) {
*len = i;
return NGX_ERROR;
}
break;
case RFC850:
if (maxlen != 30) {
if (maxlen < 30) {
*len = i;
return NGX_ERROR;
}
break;
case ASCTIME:
if (maxlen != 24) {
if (maxlen < 24) {
*len = i;
return NGX_ERROR;
}
break;
default:
*len = i;
return NGX_ERROR;
}
 
if (data[i] != ' ') {
*len = i;
return NGX_ERROR;
}
i++;
 
if (type == RFC1123) {
/* rfc1123: day */
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if (data[i] != ' ') {
*len = i;
return NGX_ERROR;
}
i++;
} else if (type == RFC850) {
/* rfc850: day */
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if (data[i] != '-') {
*len = i;
return NGX_ERROR;
}
i++;
}
((data[i] == 'D') && (data[i+1] == 'e') && (data[i+2] == 'c'))
) {
i += 3;
} else {
*len = i;
return NGX_ERROR;
}
 
if (type == RFC1123) {
/* rfc1123: year */
if (data[i] != ' ') {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
} else if (type == RFC850) {
/* rfc850: year */
if (data[i] != '-') {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
} else if (type == ASCTIME) {
/* asctime: day */
if (data[i] != ' ') {
*len = i;
return NGX_ERROR;
}
i++;
if ((data[i] != ' ') || (data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
}
if ((data[i] < '0') || (data[i] > '9')) {
*len = i;
return NGX_ERROR;
}
i++;
if (data[i] != ' ') {
*len = i;
return NGX_ERROR;
}
i++;
 
(data[i] < '0') || (data[i] > '9') ||
(data[i+1] < '0') || (data[i+1] > '9') ||
(data[i+2] != ':')
) {
*len = i;
return NGX_ERROR;
}
i += 3;
if (
(data[i] < '0') || (data[i] > '9') ||
(data[i+1] < '0') || (data[i+1] > '9') ||
(data[i+2] != ':')
) {
*len = i;
return NGX_ERROR;
}
i += 3;
if (
(data[i] < '0') || (data[i] > '9') ||
(data[i+1] < '0') || (data[i+1] > '9') ||
(data[i+2] != ' ')
) {
*len = i;
return NGX_ERROR;
}
i += 3;
 
(data[i+1] < '0') || (data[i+1] > '9') ||
(data[i+2] < '0') || (data[i+2] > '9') ||
(data[i+3] < '0') || (data[i+3] > '9')
) {
*len = i;
return NGX_ERROR;
}
i += 4;
} else {
/* GMT */
if ((data[i] != 'G') || (data[i+1] != 'M') || (data[i+2] != 'T')) {
*len = i;
return NGX_ERROR;
}
i += 3;
}
 
if ( i != maxlen ) {
return NGX_ERROR;
}
 
*len = i;
return NGX_OK;
}
 
static ngx_int_t ngx_header_inspect_parse_entity_tag(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) {
rc = NGX_ERROR;
}
 
return rc;
}
 
static ngx_int_t ngx_header_inspect_warning_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) {
ngx_uint_t i;
ngx_uint_t v;
ngx_int_t rc = NGX_OK;
enum warn_header_states { WS_START, WS_CODE1, WS_CODE2, WS_CODE3, WS_SP1, WS_HOST, WS_COLON, WS_PORT, WS_SP2, WS_TXT, WS_TXTE, WS_SP3, WS_DATE, WS_DELIM, WS_SPACE } state;
u_char d;
 
state = WS_START;
for ( i = 0; i < value.len ; i++ ) {
d = value.data[i];
 
if ( (d >= '0') && (d <= '9') ) {
switch ( state ) {
case WS_START:
case WS_SPACE:
state = WS_CODE1;
break;
case WS_CODE1:
state = WS_CODE2;
break;
case WS_CODE2:
state = WS_CODE3;
break;
case WS_SP1:
state = WS_HOST;
break;
case WS_COLON:
state = WS_PORT;
break;
case WS_HOST:
case WS_PORT:
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
} else if ( ((d >= 'a') && (d <= 'z')) || ((d >= 'A') && (d <= 'Z')) ) {
switch ( state ) {
case WS_SP1:
state = WS_HOST;
break;
case WS_HOST:
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
} else if ( (d == '-') || (d == '.') ) {
switch ( state ) {
case WS_HOST:
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
} else if ( d == ':' ) {
switch ( state ) {
case WS_HOST:
state = WS_COLON;
break;
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
} else if ( d == ',' ) {
switch ( state ) {
case WS_DATE:
case WS_TXTE:
state = WS_DELIM;
break;
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
} else if ( d == ' ' ) {
switch ( state ) {
case WS_CODE3:
state = WS_SP1;
break;
case WS_HOST:
case WS_PORT:
state = WS_SP2;
break;
case WS_TXTE:
state = WS_SP3;
break;
case WS_DELIM:
state = WS_SPACE;
break;
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
} else if ( d == '"' ) {
switch ( state ) {
case WS_SP2:
state = WS_TXT;
break;
case WS_TXT:
state = WS_TXTE;
break;
case WS_SP3:
state = WS_DATE;
i++; /* skip qoute */
if ( ngx_header_inspect_http_date(&(value.data[i]), value.len-i, &v) != NGX_OK ) {
if ( conf->log ) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: illegal date at position %d in Warning header \"%s\"", i, value.data);
}
return NGX_ERROR;
}
i += v;
if ( i >= value.len ) {
if ( conf->log ) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Warning header \"%s\"", value.data);
}
return NGX_ERROR;
}
if ( value.data[i] != '"' ) {
rc = NGX_ERROR;
}
break;
default:
rc = NGX_ERROR;
}
} else {
switch ( state ) {
case WS_TXT:
break;
default:
rc = NGX_ERROR;
}
}
if ( rc == NGX_ERROR ) {
if ( conf->log ) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: illegal character at position %d in Warning header \"%s\"", i, value.data);
}
return NGX_ERROR;
}
}
switch ( state ) {
case WS_TXTE:
case WS_DATE:
break;
default:
if ( conf->log ) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Warning header \"%s\"", value.data);
}
return NGX_ERROR;
}
 
return NGX_OK;
}
 
static ngx_int_t ngx_header_inspect_expect_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) {
 
return NGX_OK;
}
 
static ngx_int_t ngx_header_inspect_date_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, char *header, ngx_str_t value) {
ngx_uint_t v;
 
/* HTTP-date */
if ( ngx_header_inspect_http_date(value.data, value.len) != NGX_OK ) {
if ( ngx_header_inspect_http_date(value.data, value.len, &v) != NGX_OK ) {
if ( conf->log ) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid HTTP-date in \"%s\" header \"%s\"", header, value.data);
}
return NGX_ERROR;
}
if ( value.len != v ) {
if ( conf->log ) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: trailing characters in \"%s\" header \"%s\"", header, value.data);
}
return NGX_ERROR;
}
 
rc = ngx_header_inspect_expect_header(conf, r->connection->log, h[i].value);
if ((rc != NGX_OK) && conf->block) {
return NGX_HTTP_BAD_REQUEST;
}
} else if ((h[i].key.len == 7) && (ngx_strcmp("Warning", h[i].key.data) == 0) ) {
rc = ngx_header_inspect_warning_header(conf, r->connection->log, h[i].value);
if ((rc != NGX_OK) && conf->block) {
return NGX_HTTP_BAD_REQUEST;
}
} else {
/* TODO: support for other headers */
if (conf->log_uninspected) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "header_inspect: uninspected header \"%s: %s\"", h[i].key.data, h[i].value.data);