version 1.1.1.1, 2013/10/14 10:32:48
|
version 1.1.1.2, 2016/11/02 10:35:00
|
Line 1
|
Line 1
|
|
#include "first.h" |
|
|
#include "buffer.h" |
#include "buffer.h" |
#include "etag.h" |
#include "etag.h" |
|
|
Line 9
|
Line 11
|
|
|
#include <string.h> |
#include <string.h> |
|
|
int etag_is_equal(buffer *etag, const char *matches) { | int etag_is_equal(buffer *etag, const char *line, int weak_ok) { |
if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1; | 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; |
return 0; |
} |
} |
|
|
Line 20 int etag_create(buffer *etag, struct stat *st,etag_fla
|
Line 154 int etag_create(buffer *etag, struct stat *st,etag_fla
|
buffer_reset(etag); |
buffer_reset(etag); |
|
|
if (flags & ETAG_USE_INODE) { |
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("-")); |
buffer_append_string_len(etag, CONST_STR_LEN("-")); |
} |
} |
|
|
if (flags & ETAG_USE_SIZE) { |
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("-")); |
buffer_append_string_len(etag, CONST_STR_LEN("-")); |
} |
} |
|
|
if (flags & ETAG_USE_MTIME) { |
if (flags & ETAG_USE_MTIME) { |
buffer_append_long(etag, st->st_mtime); | buffer_append_int(etag, st->st_mtime); |
} |
} |
|
|
return 0; |
return 0; |
} |
} |
|
|
int etag_mutate(buffer *mut, buffer *etag) { |
int etag_mutate(buffer *mut, buffer *etag) { |
size_t i; | size_t i, len; |
uint32_t h; |
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_reset(mut); |
buffer_copy_string_len(mut, CONST_STR_LEN("\"")); |
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("\"")); |
buffer_append_string_len(mut, CONST_STR_LEN("\"")); |
|
|
return 0; |
return 0; |