9 int etag_is_equal(const buffer
*etag
, const char *line
, int weak_ok
) {
20 const char *tok_start
;
21 const char *tok
= NULL
;
24 if ('*' == line
[0] && '\0' == line
[1]) {
28 if (!etag
|| buffer_string_is_empty(etag
)) return 0;
29 tok_start
= etag
->ptr
;
31 if ('W' == tok_start
[0]) {
32 if (!weak_ok
|| '/' != tok_start
[1]) return 0; /* bad etag */
33 tok_start
= tok_start
+ 2;
36 if ('"' != tok_start
[0]) return 0; /* bad etag */
37 /* we start comparing after the first '"' */
40 for (current
= line
; *current
; ++current
) {
43 /* wait for etag to start; ignore whitespace and ',' */
46 /* weak etag always starts with 'W/"' */
47 if ('/' != *++current
) return 0; /* bad etag list */
48 if ('"' != *++current
) return 0; /* bad etag list */
57 /* strong etag starts with '"' */
68 return 0; /* bad etag list */
72 /* compare etags (after the beginning '"')
73 * quoted-pairs must match too (i.e. quoted in both strings):
74 * > (RFC 2616:) both validators MUST be identical in every way
76 matched
= *tok
&& *tok
== *current
;
80 state
= matched
? CHECK_QUOTED
: SKIP_QUOTED
;
84 /* bad etag - string should end after '"' */
88 /* matching etag: strings were equal */
96 /* strings not matching, skip remainder of etag */
103 if (!*tok
|| *tok
!= *current
) {
104 /* strings not matching, skip remainder of etag */
112 /* wait for final (not quoted) '"' */
126 /* search for ',', ignore white space */
137 return 0; /* bad etag list */
142 /* no matching etag found */
146 int etag_create(buffer
*etag
, const struct stat
*st
, etag_flags_t flags
) {
147 if (0 == flags
) return 0;
151 if (flags
& ETAG_USE_INODE
) {
152 buffer_append_int(etag
, st
->st_ino
);
153 buffer_append_string_len(etag
, CONST_STR_LEN("-"));
156 if (flags
& ETAG_USE_SIZE
) {
157 buffer_append_int(etag
, st
->st_size
);
158 buffer_append_string_len(etag
, CONST_STR_LEN("-"));
161 if (flags
& ETAG_USE_MTIME
) {
162 buffer_append_int(etag
, st
->st_mtime
);
163 #ifdef st_mtime /* use high-precision timestamp if available */
164 #if defined(__APPLE__) && defined(__MACH__)
165 buffer_append_int(etag
, st
->st_mtimespec
.tv_nsec
);
167 buffer_append_int(etag
, st
->st_mtim
.tv_nsec
);
175 int etag_mutate(buffer
*mut
, buffer
*etag
) {
179 len
= buffer_string_length(etag
);
180 for (h
=0, i
=0; i
< len
; ++i
) h
= (h
<<5)^(h
>>27)^(etag
->ptr
[i
]);
182 buffer_copy_string_len(mut
, CONST_STR_LEN("\""));
183 buffer_append_int(mut
, h
);
184 buffer_append_string_len(mut
, CONST_STR_LEN("\""));