1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #include "http.h"
38 #include "protocol.h"
39
40 #include "../util/pblock.h"
41 #include "../util/pool.h"
42 #include "../util/util.h"
43
44
45 static int http_etag =
1;
46
47
48
49 NSAPI_PUBLIC void http_format_etag(Session *sn, Request *rq,
char *etagp,
int etaglen,
off_t size,
time_t mtime)
50 {
51
52
53
54
55 if (rq->req_start - mtime <=
1) {
56
57 *etagp++ =
'W';
58 *etagp++ =
'/';
59 etaglen -=
2;
60 }
61
62
63
64
65
66 util_snprintf(etagp, etaglen,
"\"%x-%x\"", (
int)size, (
int)mtime);
67 }
68
69
70
71
72 NSAPI_PUBLIC void http_weaken_etag(Session *sn, Request *rq)
73 {
74
75 pb_param *pp = pblock_findkey(pb_key_etag, rq->srvhdrs);
76 if (pp) {
77 if (pp->value[
0] !=
'W' || pp->value[
1] !=
'/') {
78 char *weak = (
char *) pool_malloc(sn->pool,
2 + strlen(pp->value) +
1);
79
80 weak[
0] =
'W';
81 weak[
1] =
'/';
82 strcpy(weak +
2, pp->value);
83
84 pool_free(sn->pool, pp->value);
85 pp->value = weak;
86 }
87 }
88 }
89
90
91
92
93 NSAPI_PUBLIC int http_match_etag(
const char *header,
const char *etag,
int strong)
94 {
95 if (!etag)
96 return 0;
97
98 if (header[
0] ==
'*')
99 return 1;
100
101 if (etag[
0] ==
'W' && etag[
1] ==
'/') {
102
103 if (strong)
104 return 0;
105
106 etag +=
2;
107 }
108
109
110 const char *found = strstr(header, etag);
111 if (!found)
112 return 0;
113
114
115 if (strong && found >= header +
2 && found[-
2] ==
'W' && found[-
1] ==
'/')
116 return 0;
117
118 return 1;
119 }
120
121
122
123
124 NSAPI_PUBLIC int http_check_preconditions(Session *sn, Request *rq,
struct tm *mtm,
const char *etag)
125 {
126 char *header;
127
128
129 header = pblock_findkeyval(pb_key_if_modified_since, rq->headers);
130 if (header) {
131 if (mtm && util_later_than(mtm, header)) {
132 protocol_status(sn, rq,
PROTOCOL_NOT_MODIFIED,
NULL);
133 return REQ_ABORTED;
134 }
135 }
136
137
138 header = pblock_findkeyval(pb_key_if_unmodified_since, rq->headers);
139 if (header) {
140 if (mtm && !util_later_than(mtm, header)) {
141 if(util_isdate(header)) {
142 protocol_status(sn, rq,
PROTOCOL_PRECONDITION_FAIL,
NULL);
143 return REQ_ABORTED;
144 }
145 }
146 }
147
148
149 header = pblock_findkeyval(pb_key_if_none_match, rq->headers);
150 if (header) {
151
152 if (
ISMGET(rq) ||
ISMHEAD(rq)) {
153 if (http_match_etag(header, etag,
PR_FALSE)) {
154 protocol_status(sn, rq,
PROTOCOL_NOT_MODIFIED,
NULL);
155 return REQ_ABORTED;
156 }
157 }
else {
158 if (http_match_etag(header, etag,
PR_TRUE)) {
159 protocol_status(sn, rq,
PROTOCOL_PRECONDITION_FAIL,
NULL);
160 return REQ_ABORTED;
161 }
162 }
163 }
164
165
166 header = pblock_findkeyval(pb_key_if_match, rq->headers);
167 if (header) {
168
169 if (!http_match_etag(header, etag,
PR_TRUE)) {
170 protocol_status(sn, rq,
PROTOCOL_PRECONDITION_FAIL,
NULL);
171 return REQ_ABORTED;
172 }
173 }
174
175
176 header = pblock_findkeyval(pb_key_if_range, rq->headers);
177 char *range = pblock_findkeyval(pb_key_range, rq->headers);
178 if (range && header) {
179 int rmir =
PR_FALSE;
180 if (util_isdate(header)) {
181 if (mtm && !util_later_than(mtm, header)) {
182 rmir =
PR_TRUE;
183 }
184 }
else {
185 if (!http_match_etag(header, etag,
PR_TRUE)) {
186 rmir =
PR_TRUE;
187 }
188 }
189
190 if(rmir) {
191 pblock_removekey(pb_key_range, rq->headers);
192 }
193 }
194
195 return REQ_PROCEED;
196 }
197
198
199
200
201 static inline
int set_finfo(Session *sn, Request *rq,
off_t size,
time_t mtime)
202 {
203 struct tm mtms;
204 struct tm *mtm = system_gmtime(&mtime, &mtms);
205 pb_param *pp;
206
207
208 if (mtm) {
209 pp = pblock_key_param_create(rq->srvhdrs, pb_key_last_modified,
NULL,
210 HTTP_DATE_LEN);
211 if (!pp || !pp->value)
212 return REQ_ABORTED;
213 strftime(pp->value,
HTTP_DATE_LEN,
HTTP_DATE_FMT, mtm);
214 pblock_kpinsert(pb_key_last_modified, pp, rq->srvhdrs);
215 }
216
217
218 const int content_length_size =
21;
219 pp = pblock_key_param_create(rq->srvhdrs, pb_key_content_length,
NULL,
220 content_length_size);
221 if (!pp || !pp->value)
222 return REQ_ABORTED;
223 snprintf(pp->value, content_length_size,
"%lld", (
long long)size);
224 pblock_kpinsert(pb_key_content_length, pp, rq->srvhdrs);
225
226 char *etag;
227 if (http_etag) {
228
229 pp = pblock_key_param_create(rq->srvhdrs, pb_key_etag,
NULL,
MAX_ETAG);
230 if (!pp || !pp->value)
231 return REQ_ABORTED;
232 http_format_etag(sn, rq, pp->value,
MAX_ETAG, size, mtime);
233 pblock_kpinsert(pb_key_etag, pp, rq->srvhdrs);
234 etag = pp->value;
235 }
else {
236 etag =
NULL;
237 }
238
239
240 return http_check_preconditions(sn, rq, mtm, etag);
241 }
242
243 NSAPI_PUBLIC int http_set_finfo(Session *sn, Request *rq,
struct stat *finfo)
244 {
245 return set_finfo(sn, rq, finfo->st_size, finfo->st_mtime);
246 }
247
248
249
250
251 NSAPI_PUBLIC char **http_hdrs2env(pblock *pb)
252 {
253 char *t, *n, **env;
254 struct pb_entry *p;
255 pb_param *pp;
256 register int x, y, z;
257 int pos, ts, ln;
258
259
260 for(x =
0, y =
0; x < pb->hsize; x++) {
261 p = pb->ht[x];
262 while(p) {
263 ++y;
264 p = p->next;
265 }
266 }
267
268 env = util_env_create(
NULL, y, &pos);
269
270 ts =
1024;
271 t = (
char *)
MALLOC(ts);
272
273 for(x =
0; x < pb->hsize; x++) {
274 p = pb->ht[x];
275
276 while(p) {
277 pp = p->param;
278
279 ln = strlen(pp->name) +
6;
280
281 if(ln >= ts) {
282 ts = ln;
283 t = (
char *)
REALLOC(t, ts);
284 }
285 n = pp->name;
286
287
288 if(strcasecmp(n,
"authorization")) {
289 if(strcasecmp(n,
"content-type") &&
290 strcasecmp(n,
"content-length"))
291 {
292 strncpy(t,
"HTTP_",
5);
293 z =
5;
294 }
295 else
296 z =
0;
297
298 for(y =
0; n[y]; ++y, ++z)
299 t[z] = (n[y] ==
'-' ?
'_' : toupper(n[y]));
300 t[z] =
'\0';
301
302 env[pos++] = util_env_str(t, pp->value);
303 }
304 p = p->next;
305 }
306 }
307 env[pos] =
NULL;
308 FREE(t);
309 return env;
310 }
311