1: #include "first.h"
2:
3: #include "buffer.h"
4: #include "etag.h"
5:
6: #if defined HAVE_STDINT_H
7: # include <stdint.h>
8: #elif defined HAVE_INTTYPES_H
9: # include <inttypes.h>
10: #endif
11:
12: #include <string.h>
13:
14: int etag_is_equal(buffer *etag, const char *line, int weak_ok) {
15: enum {
16: START = 0,
17: CHECK,
18: CHECK_QUOTED,
19: SKIP,
20: SKIP_QUOTED,
21: TAIL
22: } state = START;
23:
24: const char *current;
25: const char *tok_start;
26: const char *tok = NULL;
27: int matched;
28:
29: if ('*' == line[0] && '\0' == line[1]) {
30: return 1;
31: }
32:
33: if (!etag || buffer_string_is_empty(etag)) return 0;
34: tok_start = etag->ptr;
35:
36: if ('W' == tok_start[0]) {
37: if (!weak_ok || '/' != tok_start[1]) return 0; /* bad etag */
38: tok_start = tok_start + 2;
39: }
40:
41: if ('"' != tok_start[0]) return 0; /* bad etag */
42: /* we start comparing after the first '"' */
43: ++tok_start;
44:
45: for (current = line; *current; ++current) {
46: switch (state) {
47: case START:
48: /* wait for etag to start; ignore whitespace and ',' */
49: switch (*current) {
50: case 'W':
51: /* weak etag always starts with 'W/"' */
52: if ('/' != *++current) return 0; /* bad etag list */
53: if ('"' != *++current) return 0; /* bad etag list */
54: if (!weak_ok) {
55: state = SKIP;
56: } else {
57: state = CHECK;
58: tok = tok_start;
59: }
60: break;
61: case '"':
62: /* strong etag starts with '"' */
63: state = CHECK;
64: tok = tok_start;
65: break;
66: case ' ':
67: case ',':
68: case '\t':
69: case '\r':
70: case '\n':
71: break;
72: default:
73: return 0; /* bad etag list */
74: }
75: break;
76: case CHECK:
77: /* compare etags (after the beginning '"')
78: * quoted-pairs must match too (i.e. quoted in both strings):
79: * > (RFC 2616:) both validators MUST be identical in every way
80: */
81: matched = *tok && *tok == *current;
82: ++tok;
83: switch (*current) {
84: case '\\':
85: state = matched ? CHECK_QUOTED : SKIP_QUOTED;
86: break;
87: case '"':
88: if (*tok) {
89: /* bad etag - string should end after '"' */
90: return 0;
91: }
92: if (matched) {
93: /* matching etag: strings were equal */
94: return 1;
95: }
96:
97: state = TAIL;
98: break;
99: default:
100: if (!matched) {
101: /* strings not matching, skip remainder of etag */
102: state = SKIP;
103: }
104: break;
105: }
106: break;
107: case CHECK_QUOTED:
108: if (!*tok || *tok != *current) {
109: /* strings not matching, skip remainder of etag */
110: state = SKIP;
111: break;
112: }
113: ++tok;
114: state = CHECK;
115: break;
116: case SKIP:
117: /* wait for final (not quoted) '"' */
118: switch (*current) {
119: case '\\':
120: state = SKIP_QUOTED;
121: break;
122: case '"':
123: state = TAIL;
124: break;
125: }
126: break;
127: case SKIP_QUOTED:
128: state = SKIP;
129: break;
130: case TAIL:
131: /* search for ',', ignore white space */
132: switch (*current) {
133: case ',':
134: state = START;
135: break;
136: case ' ':
137: case '\t':
138: case '\r':
139: case '\n':
140: break;
141: default:
142: return 0; /* bad etag list */
143: }
144: break;
145: }
146: }
147: /* no matching etag found */
148: return 0;
149: }
150:
151: int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
152: if (0 == flags) return 0;
153:
154: buffer_reset(etag);
155:
156: if (flags & ETAG_USE_INODE) {
157: buffer_append_int(etag, st->st_ino);
158: buffer_append_string_len(etag, CONST_STR_LEN("-"));
159: }
160:
161: if (flags & ETAG_USE_SIZE) {
162: buffer_append_int(etag, st->st_size);
163: buffer_append_string_len(etag, CONST_STR_LEN("-"));
164: }
165:
166: if (flags & ETAG_USE_MTIME) {
167: buffer_append_int(etag, st->st_mtime);
168: }
169:
170: return 0;
171: }
172:
173: int etag_mutate(buffer *mut, buffer *etag) {
174: size_t i, len;
175: uint32_t h;
176:
177: len = buffer_string_length(etag);
178: for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
179:
180: buffer_reset(mut);
181: buffer_copy_string_len(mut, CONST_STR_LEN("\""));
182: buffer_append_int(mut, h);
183: buffer_append_string_len(mut, CONST_STR_LEN("\""));
184:
185: return 0;
186: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>