diff options
Diffstat (limited to 'data/lighttpd/lighttpd-1.4.53/src/etag.c')
-rw-r--r-- | data/lighttpd/lighttpd-1.4.53/src/etag.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/data/lighttpd/lighttpd-1.4.53/src/etag.c b/data/lighttpd/lighttpd-1.4.53/src/etag.c new file mode 100644 index 000000000..7aab2bbb7 --- /dev/null +++ b/data/lighttpd/lighttpd-1.4.53/src/etag.c @@ -0,0 +1,180 @@ +#include "first.h" + +#include "buffer.h" +#include "etag.h" + +#include <sys/stat.h> +#include <string.h> + +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; +} + +int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) { + if (0 == flags) return 0; + + buffer_clear(etag); + + if (flags & ETAG_USE_INODE) { + buffer_append_int(etag, st->st_ino); + buffer_append_string_len(etag, CONST_STR_LEN("-")); + } + + if (flags & ETAG_USE_SIZE) { + buffer_append_int(etag, st->st_size); + buffer_append_string_len(etag, CONST_STR_LEN("-")); + } + + if (flags & ETAG_USE_MTIME) { + buffer_append_int(etag, st->st_mtime); + } + + return 0; +} + +int etag_mutate(buffer *mut, buffer *etag) { + size_t i, len; + uint32_t h; + + len = buffer_string_length(etag); + for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]); + + buffer_copy_string_len(mut, CONST_STR_LEN("\"")); + buffer_append_int(mut, h); + buffer_append_string_len(mut, CONST_STR_LEN("\"")); + + return 0; +} |