diff --git a/README b/README index ebcd69b..243f860 100644 --- a/README +++ b/README @@ -15,7 +15,7 @@ Limitations Currently only inspects the following headers: Range, If-Range, If-Unmodified-Since, If-Modified-Since, Date, Accept-Encoding, - Accept-Language, Accept-Charset, Max-Forwards + Accept-Language, Accept-Charset, Max-Forwards, If-Match Report Bugs Create a ticket on the issue tracking interface of GitHub: diff --git a/ngx_http_header_inspect.c b/ngx_http_header_inspect.c index b1e2983..0edfd9a 100644 --- a/ngx_http_header_inspect.c +++ b/ngx_http_header_inspect.c @@ -24,12 +24,14 @@ 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_entity_tag(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_acceptencoding_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); static ngx_int_t ngx_header_inspect_acceptlanguage_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); static ngx_int_t ngx_header_inspect_acceptcharset_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); static ngx_int_t ngx_header_inspect_maxforwards_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); +static ngx_int_t ngx_header_inspect_ifmatch_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); static ngx_int_t ngx_header_inspect_ifrange_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_process_request(ngx_http_request_t *r); @@ -617,40 +619,42 @@ return NGX_OK; } -static ngx_int_t ngx_header_inspect_entity_tag(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) { ngx_uint_t i = 0; if ( maxlen < 2 ) { + *len = 0; return NGX_ERROR; } if ( data[0] == 'W' ) { if ( data[1] != '/' ) { + *len = 2; return NGX_ERROR; } i = 2; } if ( i+1 >= maxlen ) { + *len = i; return NGX_ERROR; } if ( data[i] != '"' ) { + *len = i+1; return NGX_ERROR; } i++; for ( ; i < maxlen-1 ; i++ ) { if ( data[i] == '"' ) { - return NGX_ERROR; + *len = i+1; + return NGX_OK; } } - if ( data[maxlen-1] != '"' ) { - return NGX_ERROR; - } - - return NGX_OK; + *len = maxlen; + return NGX_ERROR; } static ngx_int_t ngx_header_inspect_parse_qvalue(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { @@ -867,6 +871,53 @@ } } +static ngx_int_t ngx_header_inspect_ifmatch_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ( (value.len == 1) && (value.data[0] == '*') ) { + return NGX_OK; + } + + if ( value.len < 2 ) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: If-Match header \"%s\" too short", value.data); + return NGX_ERROR; + } + + while ( i < value.len ) { + if ( ngx_header_inspect_parse_entity_tag(&(value.data[i]), value.len-i, &v) != NGX_OK ) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid entity-tag at position %d in If-Match header \"%s\"", i, value.data); + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] != ',') { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: illegal char at position %d in If-Match header \"%s\"", i, value.data); + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of If-Match header \"%s\"", value.data); + rc = NGX_ERROR; + } + + return rc; +} + static ngx_int_t ngx_header_inspect_maxforwards_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { ngx_uint_t i = 0; @@ -1084,9 +1135,11 @@ } static ngx_int_t ngx_header_inspect_ifrange_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t v = 0; + if (((value.data[0] == 'W') && (value.data[1] == '/'))|| (value.data[0] == '"')) { /* 1. entity-tag */ - if ( ngx_header_inspect_entity_tag(value.data, value.len) != NGX_OK ) { + if ( (ngx_header_inspect_parse_entity_tag(value.data, value.len, &v) != NGX_OK) || (v != value.len) ) { if ( conf->log ) { ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid entity-tag in If-Range header \"%s\"", value.data); } @@ -1172,6 +1225,11 @@ if ((rc != NGX_OK) && conf->block) { return NGX_HTTP_BAD_REQUEST; } + } else if ((h[i].key.len == 8) && (ngx_strcmp("If-Match", h[i].key.data) == 0) ) { + rc = ngx_header_inspect_ifmatch_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) {