--- embedaddon/lighttpd/src/etag.c 2013/10/14 10:32:48 1.1.1.1 +++ embedaddon/lighttpd/src/etag.c 2016/11/02 10:35:00 1.1.1.2 @@ -1,3 +1,5 @@ +#include "first.h" + #include "buffer.h" #include "etag.h" @@ -9,8 +11,140 @@ #include -int etag_is_equal(buffer *etag, const char *matches) { - if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1; +int etag_is_equal(buffer *etag, const char *line, int weak_ok) { + enum { + START = 0, + CHECK, + CHECK_QUOTED, + SKIP, + SKIP_QUOTED, + TAIL + } state = START; + + const char *current; + const char *tok_start; + const char *tok = NULL; + int matched; + + if ('*' == line[0] && '\0' == line[1]) { + return 1; + } + + if (!etag || buffer_string_is_empty(etag)) return 0; + tok_start = etag->ptr; + + if ('W' == tok_start[0]) { + if (!weak_ok || '/' != tok_start[1]) return 0; /* bad etag */ + tok_start = tok_start + 2; + } + + if ('"' != tok_start[0]) return 0; /* bad etag */ + /* we start comparing after the first '"' */ + ++tok_start; + + for (current = line; *current; ++current) { + switch (state) { + case START: + /* wait for etag to start; ignore whitespace and ',' */ + switch (*current) { + case 'W': + /* weak etag always starts with 'W/"' */ + if ('/' != *++current) return 0; /* bad etag list */ + if ('"' != *++current) return 0; /* bad etag list */ + if (!weak_ok) { + state = SKIP; + } else { + state = CHECK; + tok = tok_start; + } + break; + case '"': + /* strong etag starts with '"' */ + state = CHECK; + tok = tok_start; + break; + case ' ': + case ',': + case '\t': + case '\r': + case '\n': + break; + default: + return 0; /* bad etag list */ + } + break; + case CHECK: + /* compare etags (after the beginning '"') + * quoted-pairs must match too (i.e. quoted in both strings): + * > (RFC 2616:) both validators MUST be identical in every way + */ + matched = *tok && *tok == *current; + ++tok; + switch (*current) { + case '\\': + state = matched ? CHECK_QUOTED : SKIP_QUOTED; + break; + case '"': + if (*tok) { + /* bad etag - string should end after '"' */ + return 0; + } + if (matched) { + /* matching etag: strings were equal */ + return 1; + } + + state = TAIL; + break; + default: + if (!matched) { + /* strings not matching, skip remainder of etag */ + state = SKIP; + } + break; + } + break; + case CHECK_QUOTED: + if (!*tok || *tok != *current) { + /* strings not matching, skip remainder of etag */ + state = SKIP; + break; + } + ++tok; + state = CHECK; + break; + case SKIP: + /* wait for final (not quoted) '"' */ + switch (*current) { + case '\\': + state = SKIP_QUOTED; + break; + case '"': + state = TAIL; + break; + } + break; + case SKIP_QUOTED: + state = SKIP; + break; + case TAIL: + /* search for ',', ignore white space */ + switch (*current) { + case ',': + state = START; + break; + case ' ': + case '\t': + case '\r': + case '\n': + break; + default: + return 0; /* bad etag list */ + } + break; + } + } + /* no matching etag found */ return 0; } @@ -20,31 +154,32 @@ int etag_create(buffer *etag, struct stat *st,etag_fla buffer_reset(etag); if (flags & ETAG_USE_INODE) { - buffer_append_off_t(etag, st->st_ino); + buffer_append_int(etag, st->st_ino); buffer_append_string_len(etag, CONST_STR_LEN("-")); } if (flags & ETAG_USE_SIZE) { - buffer_append_off_t(etag, st->st_size); + buffer_append_int(etag, st->st_size); buffer_append_string_len(etag, CONST_STR_LEN("-")); } if (flags & ETAG_USE_MTIME) { - buffer_append_long(etag, st->st_mtime); + buffer_append_int(etag, st->st_mtime); } return 0; } int etag_mutate(buffer *mut, buffer *etag) { - size_t i; + size_t i, len; uint32_t h; - for (h=0, i=0; i < etag->used-1; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]); + len = buffer_string_length(etag); + for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]); buffer_reset(mut); buffer_copy_string_len(mut, CONST_STR_LEN("\"")); - buffer_append_off_t(mut, h); + buffer_append_int(mut, h); buffer_append_string_len(mut, CONST_STR_LEN("\"")); return 0;