r17870 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r17869‎ | r17870 | r17871 >
Date:01:07, 23 November 2006
Author:river
Status:old
Tags:
Comment:
obsolete
Modified paths:
  • /trunk/willow/src/willow/whttp_entity.cc (deleted) (history)

Diff [purge]

Index: trunk/willow/src/willow/whttp_entity.cc
@@ -1,1081 +0,0 @@
2 -/* @(#) $Id$ */
3 -/* This source code is in the public domain. */
4 -/*
5 - * Willow: Lightweight HTTP reverse-proxy.
6 - * whttp_entity: HTTP entity handling.
7 - */
8 -
9 -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
10 -# pragma ident "@(#)$Id$"
11 -#endif
12 -
13 -/* How does this work?
14 - *
15 - * Each HTTP request can be divided into two entities: the request and the
16 - * response. The client sends the request, i.e. the headers and possibly
17 - * a body, to the server, which considers it and sends a reply.
18 - *
19 - * Internally, we read the request headers and ignore the
20 - * body [entity_read_headers]. We then examine the headers
21 - * [whttp:client_read_done] and decide if it has a body. We modify
22 - * the entry slightly, and send it to the backend with either no source
23 - * or, if it had a body, the client's FDE as the source [entity_send].
24 - * We then wait for the server to reply with its header. When it does
25 - * [whttp:backend_headers_done], we send the request to the client, using
26 - * the backend's FDE as the body, if it has one, and close it.
27 - *
28 - * See "Entity sending" below for a detailed description of how entity
29 - * sending works.
30 - *
31 - * TODO: We don't have to buffer the headers, _but_ it makes things easier
32 - * for now and doesn't cost much. if we start not buffering we need to
33 - * decide what to do when the client goes away unexpectedly. probably it's
34 - * easiest to just drop the backend connection (this is wasteful of backends
35 - * but we don't cache them at the moment anyway). what do we do when the
36 - * client sends "Foo: bar\r\n baz\r\n" and we decide after baz that we
37 - * shouldn't send that header after all?
38 - *
39 - * There is a trade-off in some places between excessive copying and
40 - * excessive syscalls. In some cases we copy data (headers) when we could
41 - * undo the parser mangling and send them as-is. IMO this is not likely
42 - * to be a worthwhile optimisation, needs profiling.
43 - *
44 - * As for FDE backending, Unix sucks:
45 - *
46 - * The sendfile() function copies data from in_fd to out_fd starting
47 - * at offset off and of length len bytes. The in_fd argument should
48 - * be a file descriptor to a regular file opened for reading.
49 - */
50 -
51 -#include <sys/uio.h>
52 -
53 -#include <unistd.h>
54 -#include <errno.h>
55 -#include <string.h>
56 -#include <stdlib.h>
57 -#include <stdio.h>
58 -#include <assert.h>
59 -/*LINTED*/
60 -#include <fcntl.h>
61 -#include <strings.h>
62 -#include <ctype.h>
63 -#include <zlib.h>
64 -
65 -#include <vector>
66 -using std::vector;
67 -#include <utility>
68 -#include <algorithm>
69 -using std::search;
70 -using std::max;
71 -using std::min;
72 -
73 -#include "willow.h"
74 -#include "whttp.h"
75 -#include "whttp_entity.h"
76 -#include "wnet.h"
77 -#include "wlog.h"
78 -#include "wconfig.h"
79 -
80 -#define ENTITY_STATE_START 0
81 -#define ENTITY_STATE_HDR 1
82 -#define ENTITY_STATE_DONE 2
83 -#define ENTITY_STATE_SEND_HDR 3
84 -#define ENTITY_STATE_SEND_BODY 4
85 -#define ENTITY_STATE_SEND_BUF 5
86 -
87 -#define ZLIB_BLOCK (1024 * 32)
88 -
89 -static void entity_error_callback(struct bufferevent *, short, void *);
90 -static void entity_read_callback(struct bufferevent *, void *);
91 -static int parse_headers(struct http_entity *);
92 -static int parse_reqtype(struct http_entity *);
93 -static int validhost(const char *);
94 -static int via_includes_me(const char *);
95 -static int write_zlib_eof(struct http_entity *);
96 -static int write_data(struct http_entity *, void *buf, size_t len);
97 -
98 -static void entity_send_file_done(struct fde *, void *, int);
99 -static void entity_send_target_write(struct bufferevent *, void *);
100 -static void entity_send_target_error(struct bufferevent *, short, void *);
101 -
102 -const char *ent_errors[] = {
103 - /* 0 */ "Unknown error",
104 - /* -1 */ "Read error",
105 - /* -2 */ "Could not parse request headers",
106 - /* -3 */ "Invalid Host",
107 - /* -4 */ "Invalid request type",
108 - /* -5 */ "Too many headers",
109 - /* -6 */ "Forwarding loop detected",
110 - /* -7 */ "Invalid Accept-Encoding",
111 -};
112 -
113 -const char *ent_encodings[] = {
114 - "identity",
115 - "deflate",
116 - "x-deflate",
117 - "gzip",
118 - "x-gzip",
119 -};
120 -
121 -void
122 -entity_set_response(http_entity *ent, int isresp)
123 -{
124 - if (isresp) {
125 - if (ent->he_flags.response)
126 - return;
127 - if (ent->he_rdata.request.path)
128 - wfree(ent->he_rdata.request.path);
129 - if (ent->he_rdata.request.host)
130 - wfree(ent->he_rdata.request.host);
131 - bzero(&ent->he_rdata.response, sizeof(ent->he_rdata.response));
132 - ent->he_flags.response = 1;
133 - } else {
134 - if (!ent->he_flags.response)
135 - return;
136 - bzero(&ent->he_rdata.request, sizeof(ent->he_rdata.request));
137 - ent->he_flags.response = 0;
138 - }
139 -}
140 -
141 -void
142 -entity_read_headers(http_entity *entity, header_cb func, void *udata)
143 -{
144 - entity->_he_cbdata = udata;
145 - entity->_he_func = func;
146 - entity->he_flags.hdr_only = 1;
147 -
148 - WDEBUG((WLOG_DEBUG, "entity_read_headers: starting, source %d",
149 - entity->he_source.fde.fde->fde_fd));
150 - /* XXX source for an entity header read is _always_ an fde */
151 - entity->_he_frombuf = bufferevent_new(entity->he_source.fde.fde->fde_fd,
152 - entity_read_callback, NULL, entity_error_callback, entity);
153 - event_base_set(evb, &entity->_he_frombuf->ev_read);
154 - event_base_set(evb, &entity->_he_frombuf->ev_write);
155 - bufferevent_disable(entity->_he_frombuf, EV_WRITE);
156 - bufferevent_enable(entity->_he_frombuf, EV_READ);
157 -}
158 -
159 -void
160 -entity_send(fde *fde, http_entity *entity, header_cb cb, void *data, int flags)
161 -{
162 -struct header_list *hl;
163 - int window = 15;
164 -
165 - errno = 0;
166 -
167 - entity->_he_func = cb;
168 - entity->_he_cbdata = data;
169 - entity->_he_target = fde;
170 - entity->he_flags.hdr_only = 0;
171 - if (!entity->he_flags.response && entity->he_rdata.request.reqtype == REQTYPE_POST) {
172 - entity->he_source.fde._wrt = entity->he_rdata.request.contlen;
173 - } else if (entity->he_flags.response)
174 - entity->he_source.fde._wrt = entity->he_rdata.request.contlen;
175 -
176 - entity->_he_tobuf = bufferevent_new(entity->_he_target->fde_fd,
177 - NULL, entity_send_target_write,
178 - entity_send_target_error, entity);
179 - event_base_set(evb, &entity->_he_tobuf->ev_read);
180 - event_base_set(evb, &entity->_he_tobuf->ev_write);
181 -
182 - bufferevent_disable(entity->_he_tobuf, EV_READ);
183 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
184 - if (entity->_he_frombuf) {
185 - bufferevent_disable(entity->_he_frombuf, EV_READ);
186 - bufferevent_disable(entity->_he_frombuf, EV_WRITE);
187 - }
188 - entity->_he_state = ENTITY_STATE_SEND_HDR;
189 -
190 - WDEBUG((WLOG_DEBUG, "entity_send: writing to %d [%s], enc=%d", fde->fde_fd, fde->fde_desc,
191 - entity->he_encoding));
192 -
193 - if (entity->he_flags.response) {
194 - evbuffer_add_printf(entity->_he_tobuf->output, "HTTP/1.1 %d %s\r\n",
195 - entity->he_rdata.response.status, entity->he_rdata.response.status_str);
196 - } else {
197 - evbuffer_add_printf(entity->_he_tobuf->output, "%s %s HTTP/1.%d\r\n",
198 - request_string[entity->he_rdata.request.reqtype],
199 - entity->he_rdata.request.path,
200 - entity->he_rdata.request.host ? 1 : 0);
201 - }
202 -
203 - if (flags & ENT_CHUNKED_OKAY) {
204 - struct header *contlen;
205 - entity->he_flags.chunked = 1;
206 - if (!entity->he_h_transfer_encoding)
207 - entity->he_headers.add("Transfer-Encoding", "chunked");
208 - if ((contlen = entity->he_headers.find("Content-Length")) != NULL)
209 - entity->he_headers.remove("Content-Length");
210 - }
211 -
212 - switch (entity->he_encoding) {
213 - case E_NONE:
214 - break;
215 - case E_GZIP: case E_X_GZIP:
216 - window += 16;
217 - case E_DEFLATE: case E_X_DEFLATE: {
218 - int err;
219 -
220 - if ((err = deflateInit2(&entity->_he_zbuf, config.complevel, Z_DEFLATED,
221 - window, 8, Z_DEFAULT_STRATEGY)) != Z_OK) {
222 - wlog(WLOG_WARNING, "deflateInit: %s", zError(err));
223 - entity->he_encoding = E_NONE;
224 - }
225 - break;
226 - }
227 - }
228 - evbuffer_add_printf(entity->_he_tobuf->output, "Content-Encoding: %s\r\n",
229 - ent_encodings[entity->he_encoding]);
230 - for (vector<header>::iterator it = entity->he_headers.hl_hdrs.begin(),
231 - end = entity->he_headers.hl_hdrs.end(); it != end; ++it)
232 - evbuffer_add_printf(entity->_he_tobuf->output, "%s: %s\r\n",
233 - it->hr_name, it->hr_value);
234 - evbuffer_add_buffer(entity->_he_tobuf->output, entity->he_extraheaders);
235 - bufferevent_write(entity->_he_tobuf, const_cast<char *>("\r\n"), 2);
236 -}
237 -
238 -static void
239 -entity_error_callback(struct bufferevent *be, short what, void *d)
240 -{
241 -struct http_entity *entity = (http_entity *)d;
242 -
243 - /*
244 - * Some kind of error occured while we were reading from the backend.
245 - */
246 - WDEBUG((WLOG_DEBUG, "entity_error_callback called, what=%hd errno=%d %s", what,
247 - errno, strerror(errno)));
248 -
249 - if (what & EVBUFFER_EOF) {
250 - /*
251 - * End of file from backend.
252 - */
253 - if (entity->he_encoding) {
254 - if (write_zlib_eof(entity) == -1) {
255 - entity->_he_func(entity, entity->_he_cbdata, -1);
256 - return;
257 - }
258 - }
259 -
260 - if (entity->he_flags.chunked && !entity->he_flags.eof) {
261 - WDEBUG((WLOG_DEBUG, "writing chunked data, append EOF"));
262 - entity->he_flags.eof = 1;
263 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
264 - bufferevent_write(entity->_he_tobuf, const_cast<void *>((void *)"0\r\n"), 3);
265 - return;
266 - }
267 - WDEBUG((WLOG_DEBUG, "entity_error_callback: EOF"));
268 - bufferevent_disable(entity->_he_frombuf, EV_READ);
269 - entity->_he_func(entity, entity->_he_cbdata, 1);
270 - //entity->he_flags.eof = 1;
271 - return;
272 - }
273 -
274 - entity->he_flags.error = 1;
275 - entity->_he_func(entity, entity->_he_cbdata, -1);
276 -}
277 -
278 -static int
279 -write_zlib_eof(http_entity *entity)
280 -{
281 - int zerr;
282 - unsigned char zbuf[16384];
283 - int n;
284 -
285 - entity->_he_zbuf.avail_in = 0;
286 - entity->_he_zbuf.next_out = zbuf;
287 - entity->_he_zbuf.avail_out = sizeof zbuf;
288 -
289 - zerr = deflate(&entity->_he_zbuf, Z_FINISH);
290 -
291 - if (zerr != Z_STREAM_END) {
292 - wlog(WLOG_WARNING, "deflate: %s", zError(zerr));
293 - deflateEnd(&entity->_he_zbuf);
294 - return -1;
295 - }
296 - n = sizeof zbuf - entity->_he_zbuf.avail_out;
297 - WDEBUG((WLOG_DEBUG, "writing zlib, append finish, left=%d avail=%d",
298 - n, entity->_he_zbuf.avail_out));
299 - if (n) {
300 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
301 - if (entity->he_flags.chunked)
302 - evbuffer_add_printf(entity->_he_tobuf->output, "%x\r\n", n);
303 - bufferevent_write(entity->_he_tobuf, zbuf, n);
304 - if (entity->he_flags.chunked)
305 - evbuffer_add_printf(entity->_he_tobuf->output, "\r\n");
306 - }
307 - deflateEnd(&entity->_he_zbuf);
308 - return 0;
309 -}
310 -static char *
311 -find_rn(char *buf, char *end)
312 -{
313 -char *s;
314 - for (s = buf; s < end; s += 2) {
315 - if (likely(*s != '\r' && *s != '\n'))
316 - continue;
317 - if (likely((s + 1 < end) && s[0] == '\r' && s[1] == '\n'))
318 - return s;
319 - if (likely(s > buf && s[-1] == '\r' && s[0] == '\n'))
320 - return s - 1;
321 - }
322 - return NULL;
323 -}
324 -
325 -static char *
326 -find_rnrn(char *buf, char *end)
327 -{
328 -char *s;
329 - /* find any \r or \n */
330 - for (s = buf; s < end; s += 4) {
331 - if (*s == '\r' || *s == '\n') {
332 - char *q = s;
333 - while (q > buf && (q[-1] == '\r' || q[-1] == '\n'))
334 - q--;
335 - if (q + 3 >= end)
336 - continue;
337 - if (q[0] == '\r' && q[1] == '\n'
338 - && q[2] == '\r' && q[3] == '\n')
339 - return q;
340 - }
341 - }
342 - /* nothing found... */
343 - return NULL;
344 -}
345 -
346 -static void
347 -entity_read_callback(bufferevent *be, void *d)
348 -{
349 -struct http_entity *entity = (http_entity *) d;
350 - int i;
351 -#define RD_BUFSZ 16386
352 - char buf[RD_BUFSZ];
353 - int wrote = 0, contdone = 0;
354 -
355 - /*
356 - * Data was available from the backend. If state is ENTITY_STATE_SEND_BODY,
357 - * we're moving the request from backend->client, so do that. Otherwise,
358 - * we're still reading header information.
359 - */
360 - WDEBUG((WLOG_DEBUG, "entity_read_callback: called, source %d",
361 - entity->he_source.fde.fde->fde_fd));
362 -
363 - if (entity->_he_state < ENTITY_STATE_SEND_BODY) {
364 - char *buf = ((char *)EVBUFFER_DATA(entity->_he_frombuf->input)) + entity->_he_hdroff;
365 - char *end, *found;
366 -static char const *rnrn = "\r\n\r\n";
367 - if (entity->_he_hdroff == 0)
368 - buf = (char *)EVBUFFER_DATA(entity->_he_frombuf->input);
369 - end = (char *)EVBUFFER_DATA(entity->_he_frombuf->input) + EVBUFFER_LENGTH(entity->_he_frombuf->input);
370 - WDEBUG((WLOG_DEBUG, "entity_read_callback: end=%p; buf=%p; data=%p",
371 - end, buf, EVBUFFER_DATA(entity->_he_frombuf->input)));
372 -
373 - if ((found = find_rnrn(buf, end)) == NULL) {
374 - // need more data
375 - entity->_he_hdroff = max(buf, min(buf, end - 4)) - buf;
376 - WDEBUG((WLOG_DEBUG, "entity_read_callback: need more data, read %d [%s], hdroff=%d",
377 - end - buf, buf, entity->_he_hdroff));
378 - return;
379 - }
380 -
381 - entity->_he_hdroff = (found + 4) - buf; // so parse_headers knows how much to search
382 - if ((i = parse_headers(entity)) < 0) {
383 - WDEBUG((WLOG_DEBUG, "entity_read_callback: parse_headers returned -1"));
384 - entity->he_flags.error = 1;
385 - bufferevent_disable(entity->_he_frombuf, EV_READ);
386 - entity->_he_func(entity, entity->_he_cbdata, i);
387 - return;
388 - }
389 - WDEBUG((WLOG_DEBUG, "parse_headers returned; client now %d hdr_only=%d",
390 - entity->_he_state, entity->he_flags.hdr_only));
391 -
392 - if (entity->_he_state == ENTITY_STATE_DONE) {
393 - if (entity->he_flags.hdr_only) {
394 - WDEBUG((WLOG_DEBUG, "entity_read_callback: client is ENTITY_STATE_DONE"));
395 - bufferevent_disable(entity->_he_frombuf, EV_READ);
396 - entity->_he_func(entity, entity->_he_cbdata, 0);
397 - return;
398 - } else
399 - entity->_he_state = ENTITY_STATE_SEND_BODY;
400 - }
401 - //bufferevent_disable(entity->_he_frombuf, EV_READ);
402 - //if (entity->he_flags.hdr_only)
403 - return;
404 - }
405 -
406 - if (entity->he_flags.eof) {
407 - entity->_he_func(entity, entity->_he_cbdata, 0);
408 - return;
409 - }
410 -
411 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
412 -
413 - if (entity->he_flags.eof) {
414 - /*
415 - * This means the last chunk was written (see below).
416 - */
417 - bufferevent_disable(entity->_he_frombuf, EV_READ);
418 - entity->_he_func(entity, entity->_he_cbdata, 0);
419 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
420 - return;
421 - }
422 -
423 - /*
424 - * While data is available, read it and forward. If we're using chunked encoding,
425 - * don't read past the end of the chunk.
426 - */
427 - for (;;) {
428 - size_t read;
429 - size_t want = RD_BUFSZ;
430 -
431 - /*
432 - * If we're reading chunked data, check if we're starting a new chunk.
433 - */
434 - if ((entity->he_te & TE_CHUNKED) && entity->_he_chunk_size == 0) {
435 - char *chunks;
436 - if ((chunks = evbuffer_readline(entity->_he_frombuf->input)) == NULL)
437 - return;
438 - entity->_he_chunk_size = strtol(chunks, NULL, 16);
439 - free(chunks);
440 - WDEBUG((WLOG_DEBUG, "new chunk, size=%d", entity->_he_chunk_size));
441 - if (entity->_he_chunk_size == 0) {
442 - /*
443 - * Zero-sized chunk = end of request.
444 - *
445 - * If this client is receiving TE:chunked data, we have to write
446 - * the terminating block and finish up the next time round. If
447 - * not, mark it finished now.
448 - */
449 - int more = 0;
450 -
451 - if (entity->he_encoding) {
452 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
453 - write_zlib_eof(entity);
454 - more = 1;
455 - }
456 -
457 - if (entity->he_flags.chunked) {
458 - bufferevent_disable(entity->_he_frombuf, EV_READ);
459 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
460 - bufferevent_write(entity->_he_tobuf, const_cast<void *>((void *)"0\r\n"), 3);
461 - more = 1;
462 - }
463 -
464 - if (more) {
465 - entity->he_flags.eof = 1;
466 - return;
467 - }
468 -
469 - bufferevent_disable(entity->_he_frombuf, EV_READ);
470 - if (!wrote)
471 - entity->_he_func(entity, entity->_he_cbdata, 0);
472 - else
473 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
474 - return;
475 - }
476 - /* +2 for CRLF */
477 - entity->_he_chunk_size += 2;
478 - }
479 -
480 - want = RD_BUFSZ;
481 - if (entity->_he_chunk_size)
482 - want = entity->_he_chunk_size;
483 - else if (entity->he_source.fde._wrt)
484 - want = entity->_he_chunk_size;
485 -
486 - want = entity->_he_chunk_size ? entity->_he_chunk_size : RD_BUFSZ;
487 -
488 - read = bufferevent_read(entity->_he_frombuf, buf, want);
489 - WDEBUG((WLOG_DEBUG, "rw %d, got %d wrote=%d wrt=%d", want, read, wrote,
490 - entity->he_source.fde._wrt));
491 -
492 - /*
493 - * _wrt holds the remaining data to read from the source, if we know
494 - * it (e.g. Content-Length header). Decrement it by the amount we just
495 - * read; if it ends up 0, we read the entire entity.
496 - */
497 - if (entity->he_source.fde._wrt) {
498 - entity->he_source.fde._wrt -= read;
499 - if (entity->he_source.fde._wrt == 0)
500 - contdone = 1;
501 - }
502 - WDEBUG((WLOG_DEBUG, "contdone=%d", contdone));
503 -
504 - /*
505 - * We ran out of data and haven't reached the end of the source entity.
506 - * Schedule another read on the source and return.
507 - */
508 - if (read == 0 && !contdone) {
509 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
510 - bufferevent_enable(entity->_he_frombuf, EV_READ);
511 - return;
512 - }
513 -
514 - if (entity->_he_chunk_size)
515 - entity->_he_chunk_size -= read;
516 -
517 - if ((entity->he_te & TE_CHUNKED) && entity->_he_chunk_size == 0)
518 - /* subtract the +2 we added above */
519 - read -= 2;
520 -
521 - entity->he_size += read;
522 -
523 - if (entity->he_cache_callback) {
524 - entity->he_cache_callback(buf, read, entity->he_cache_callback_data);
525 - }
526 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
527 -
528 - if ((i = write_data(entity, buf, read)) == -1) {
529 - entity->_he_func(entity, entity->_he_cbdata, -1);
530 - return;
531 - }
532 - if (read > 0) {
533 - bufferevent_disable(entity->_he_frombuf, EV_READ);
534 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
535 - return;
536 - }
537 - wrote++;
538 - if (contdone) {
539 - if (entity->he_flags.chunked)
540 - bufferevent_write(entity->_he_tobuf, const_cast<char *>("0\r\n"), 3);
541 - bufferevent_disable(entity->_he_frombuf, EV_READ);
542 - //entity->_he_func(entity, entity->_he_cbdata, 0);
543 - entity->he_flags.eof = 1;
544 - return;
545 - }
546 - }
547 -
548 - bufferevent_disable(entity->_he_frombuf, EV_READ);
549 -}
550 -
551 -static int
552 -write_data(http_entity *entity, void *buf, size_t len)
553 -{
554 -static unsigned char zbuf[ZLIB_BLOCK * 2];
555 -
556 - WDEBUG((WLOG_DEBUG, "write_data: writing %d", len));
557 -
558 - switch (entity->he_encoding) {
559 - case E_NONE:
560 - if (entity->he_flags.chunked)
561 - evbuffer_add_printf(entity->_he_tobuf->output, "%x\r\n", len);
562 - bufferevent_write(entity->_he_tobuf, buf, len);
563 - if (entity->he_flags.chunked)
564 - evbuffer_add_printf(entity->_he_tobuf->output, "\r\n");
565 - return 0;
566 -
567 - case E_DEFLATE: case E_X_DEFLATE: case E_GZIP: case E_X_GZIP: {
568 - int zerr;
569 -
570 - entity->_he_zbuf.next_in = (unsigned char *)buf;
571 - entity->_he_zbuf.avail_in = len;
572 - entity->_he_zbuf.next_out = zbuf;
573 - entity->_he_zbuf.avail_out = sizeof zbuf;
574 - while (entity->_he_zbuf.avail_in) {
575 - zerr = deflate(&entity->_he_zbuf, Z_SYNC_FLUSH);
576 - if (zerr != Z_OK) {
577 - wlog(WLOG_WARNING, "deflate: %s", zError(zerr));
578 - return -1;
579 - }
580 - WDEBUG((WLOG_DEBUG, "avail_in=%d avail_out=%d",
581 - entity->_he_zbuf.avail_in, entity->_he_zbuf.avail_out));
582 - if (entity->he_flags.chunked)
583 - evbuffer_add_printf(entity->_he_tobuf->output, "%x\r\n",
584 - (sizeof zbuf - entity->_he_zbuf.avail_out));
585 - bufferevent_write(entity->_he_tobuf, zbuf,
586 - (sizeof zbuf - entity->_he_zbuf.avail_out));
587 - if (entity->he_flags.chunked)
588 - evbuffer_add_printf(entity->_he_tobuf->output, "\r\n");
589 - entity->_he_zbuf.next_out = zbuf;
590 - entity->_he_zbuf.avail_out = sizeof zbuf;
591 - }
592 - return 0;
593 - }
594 - }
595 - abort();
596 -}
597 -
598 -static void
599 -entity_send_target_write(struct bufferevent *buf, void *d)
600 -{
601 -struct http_entity *entity = (http_entity *)d;
602 -static char fbuf[ZLIB_BLOCK];
603 -
604 - WDEBUG((WLOG_DEBUG, "entity_send_target_write: eof=%d, state=%d",
605 - entity->he_flags.eof, entity->_he_state));
606 -
607 - if (entity->he_flags.eof) {
608 - if (entity->_he_frombuf)
609 - bufferevent_disable(entity->_he_frombuf, EV_READ);
610 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
611 - entity->_he_func(entity, entity->_he_cbdata, 0);
612 - return;
613 - }
614 -
615 - /*
616 - * Write to target completed.
617 - */
618 - if (entity->_he_state == ENTITY_STATE_SEND_HDR) {
619 - /*
620 - * Sending headers completed. Decide what to do next.
621 - */
622 - switch (entity->he_source_type) {
623 - case ENT_SOURCE_NONE:
624 - /* no body for this request */
625 - WDEBUG((WLOG_DEBUG, "entity_send_target_write: no body, return immediately"));
626 - entity->_he_func(entity, entity->_he_cbdata, 0);
627 - return;
628 -
629 - case ENT_SOURCE_BUFFER:
630 - /* write buffer, callback when done */
631 - WDEBUG((WLOG_DEBUG, "entity_send_target_write: source is buffer, %d bytes",
632 - entity->he_source.buffer.len));
633 - entity->_he_state = ENTITY_STATE_SEND_BUF;
634 - bufferevent_write(entity->_he_tobuf,
635 - (void *)entity->he_source.buffer.addr,
636 - entity->he_source.buffer.len);
637 - return;
638 -
639 - case ENT_SOURCE_FILE:
640 - /* write file */
641 - //entity->_he_tobuf = entity->_he_frombuf = NULL;
642 -
643 - /*
644 - * Compressed data can't be written using sendfile
645 - */
646 - entity->_he_state = ENTITY_STATE_SEND_BODY;
647 -
648 - if (entity->he_encoding) {
649 - bufferevent_enable(entity->_he_tobuf, EV_WRITE);
650 - /* The write handler does this for us */
651 - return;
652 - }
653 -
654 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
655 -#if 0
656 - if (wnet_sendfile(entity->_he_target->fde_fd, entity->he_source.fd.fd,
657 - entity->he_source.fd.size - entity->he_source.fd.off,
658 - entity->he_source.fd.off, entity_send_file_done, entity, 0) == -1) {
659 - entity->_he_func(entity, entity->_he_cbdata, -1);
660 - }
661 -#endif
662 - return;
663 - }
664 - entity->_he_state = ENTITY_STATE_SEND_BODY;
665 - }
666 -
667 - if (entity->_he_state == ENTITY_STATE_SEND_BUF) {
668 - /*
669 - * Writing buffer completed.
670 - */
671 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
672 - if (entity->_he_frombuf)
673 - bufferevent_disable(entity->_he_frombuf, EV_READ);
674 - entity->_he_func(entity, entity->_he_cbdata, 0);
675 - return;
676 - }
677 -
678 - if (entity->he_source_type == ENT_SOURCE_FILE) {
679 - /*
680 - * We only get here if we're writing deflate data.
681 - */
682 - ssize_t i;
683 -
684 - WDEBUG((WLOG_DEBUG, "write file, eof=%d, size=%d, off=%d",
685 - entity->he_flags.eof, entity->he_source.fd.size,
686 - entity->he_source.fd.off));
687 -
688 - if (entity->he_flags.eof) {
689 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
690 - entity->_he_func(entity, entity->_he_cbdata, 0);
691 - return;
692 - }
693 -
694 - if ((i = read(entity->he_source.fd.fd, fbuf, sizeof fbuf)) == -1) {
695 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
696 - entity->_he_func(entity, entity->_he_cbdata, -1);
697 - return;
698 - }
699 - if (write_data(entity, fbuf, i) == -1) {
700 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
701 - entity->_he_func(entity, entity->_he_cbdata, -1);
702 - return;
703 - }
704 - entity->he_source.fd.off += i;
705 - if (entity->he_source.fd.off == (off_t) entity->he_source.fd.size) {
706 - entity->he_flags.eof = 1;
707 - write_zlib_eof(entity);
708 - return;
709 - }
710 -
711 - return;
712 - }
713 -
714 - WDEBUG((WLOG_DEBUG, "entity_send_target_write: FDE, drained=%d",
715 - entity->he_flags.drained));
716 -
717 - /*
718 - * Otherwise, we're sending from an FDE, and the last write completed.
719 - */
720 - bufferevent_enable(entity->_he_frombuf, EV_READ);
721 - bufferevent_disable(entity->_he_tobuf, EV_WRITE);
722 - if (!entity->he_flags.drained) {
723 - entity->he_flags.drained = 1;
724 -} entity_read_callback(entity->_he_frombuf, entity);
725 -// }
726 -}
727 -
728 -static void
729 -entity_send_target_error(struct bufferevent *buf, short err, void *d)
730 -{
731 -struct http_entity *entity = (http_entity *)d;
732 -
733 - /*
734 - * Writing to target produced an error.
735 - */
736 - entity->_he_func(entity, entity->_he_cbdata, -1);
737 -}
738 -
739 -/*ARGSUSED*/
740 -static void
741 -entity_send_file_done(fde *fde, void *data, int res)
742 -{
743 -struct http_entity *entity = (http_entity *)data;
744 -
745 - WDEBUG((WLOG_DEBUG, "entity_send_file_done: called for %d [%s], res=%d",
746 - fde->fde_fd, fde->fde_desc, res));
747 - entity->_he_func(entity, entity->_he_cbdata, res);
748 - return;
749 -}
750 -
751 -static int
752 -validhost(const char *host)
753 -{
754 - for (; *host; ++host) {
755 - if (!(char_table[(unsigned char)*host] & CHAR_HOST))
756 - return 0;
757 - }
758 - return 1;
759 -}
760 -
761 -static int
762 -via_includes_me(const char *s)
763 -{
764 - char *orig = wstrdup(s);
765 - char *via = orig, *comma, *space;
766 -
767 - do {
768 - comma = strchr(via, ',');
769 - if (comma)
770 - *comma++ = '\0';
771 - via = strchr(via, ' ');
772 - if (!via)
773 - break;
774 - while (*via == ' ')
775 - ++via;
776 - space = strchr(via, ' ');
777 - if (!space) {
778 - wfree(orig);
779 - return 0;
780 - }
781 - *space = '\0';
782 - if (!strcmp(via, my_hostname)) {
783 - wfree(orig);
784 - return 1;
785 - }
786 - via = comma;
787 - } while (comma);
788 - wfree(orig);
789 - return 0;
790 -}
791 -
792 -static int
793 -parse_headers(http_entity *entity)
794 -{
795 -char *line;
796 -char *rdbuf;
797 -char *buf = (char *)EVBUFFER_DATA(entity->_he_frombuf->input);
798 -char *end = buf + entity->_he_hdroff;
799 -char *nexthdr;
800 -static char rn[] = { '\r', '\n' };
801 -size_t i, nread;
802 -char *lbuf, *lend;
803 -bool sent_host = false;
804 - entity->_he_hdrbuf = new char[end - buf];
805 - lbuf = entity->_he_hdrbuf;
806 - lend = lbuf + (end - buf);
807 - WDEBUG((WLOG_DEBUG, "parse_headers: %d in buffer before read of %d",
808 - (int)EVBUFFER_LENGTH(entity->_he_frombuf->input), end - buf));
809 - if ((i = bufferevent_read(entity->_he_frombuf, lbuf, end - buf)) != (end - buf)) {
810 - WDEBUG((WLOG_DEBUG, "expected %d bytes, read %d!", end - buf, i));
811 - abort();
812 - }
813 - WDEBUG((WLOG_DEBUG, "parse_headers: %d left in buffer",
814 - (int)EVBUFFER_LENGTH(entity->_he_frombuf->input)));
815 - while ((nexthdr = find_rn(lbuf, lend)) != NULL) {
816 - char *name = NULL, *value = NULL;
817 - size_t nlen, vlen;
818 - int error = 1;
819 - *nexthdr = '\0';
820 - line = lbuf;
821 - lbuf = nexthdr + 2;
822 - if (!*line) {
823 - if (!entity->he_reqstr) {
824 - return ENT_ERR_INVREQ;
825 - }
826 -
827 - if (!sent_host && entity->he_rdata.request.host)
828 - evbuffer_add_printf(entity->he_extraheaders, "Host: %s\r\n",
829 - entity->he_rdata.request.host);
830 -
831 - entity->_he_state = ENTITY_STATE_DONE;
832 - return 0;
833 - }
834 -
835 - switch(entity->_he_state) {
836 - case ENTITY_STATE_START:
837 - entity->he_reqstr = wstrdup(line);
838 - if (parse_reqtype(entity) == -1) {
839 - return ENT_ERR_INVREQ;
840 - }
841 - entity->_he_state = ENTITY_STATE_HDR;
842 - break;
843 - case ENTITY_STATE_HDR:
844 - if (isspace(*line)) {
845 - char *s = line;
846 - if (!entity->he_headers.hl_hdrs.size()) {
847 - error = ENT_ERR_INVHDR;
848 - goto error;
849 - }
850 - while (isspace(*s))
851 - s++;
852 - entity->he_headers.append_last(s);
853 - continue;
854 - }
855 -
856 - name = line;
857 - value = strchr(name, ':');
858 - if (value == NULL) {
859 - error = ENT_ERR_INVREQ;
860 - goto error;
861 - }
862 - nlen = value - name;
863 - *value++ = '\0';
864 - vlen = nexthdr - value - 1;
865 - while (isspace(*value))
866 - ++value;
867 -
868 - WDEBUG((WLOG_DEBUG, "header: from [%s], [%s] = [%s]",
869 - line, name, value));
870 -
871 - if (entity->he_headers.hl_hdrs.size() > MAX_HEADERS) {
872 - error = ENT_ERR_2MANY;
873 - goto error;
874 - }
875 - if (!strcasecmp(name, "Host")) {
876 - if (!validhost(value)) {
877 - error = ENT_ERR_INVHOST;
878 - goto error;
879 - }
880 - entity->he_headers.add(name, nlen, value, vlen);
881 - entity->he_rdata.request.host = value;
882 - sent_host = true;
883 - } else if (!strcasecmp(name, "Content-Length")) {
884 - entity->he_headers.add(name, nlen, value, vlen);
885 - entity->he_rdata.request.contlen = atoi(value);
886 - } else if (!strcasecmp(name, "Via")) {
887 - if (via_includes_me(value)) {
888 - error = ENT_ERR_LOOP;
889 - goto error;
890 - }
891 - entity->he_headers.add(name, nlen, value, vlen);
892 - } else if (!strcasecmp(name, "transfer-encoding")) {
893 - /* XXX */
894 - if (!strcasecmp(value, "chunked")) {
895 - entity->he_te |= TE_CHUNKED;
896 - }
897 - /* Don't forward transfer-encoding... */
898 - } else if (!strcasecmp(name, "Accept-Encoding")) {
899 - if (!entity->he_flags.response &&
900 - qvalue_parse(entity->he_rdata.request.accept_encoding, value) == -1) {
901 - error = ENT_ERR_INVAE;
902 - WDEBUG((WLOG_DEBUG, "a-e parse failed"));
903 - goto error;
904 - }
905 - } else if (!strcasecmp(name, "User-Agent") && strstr(value, "MSIE")) {
906 - /*
907 - * Some MSIE versions cannot handle chunked replies properly.
908 - * Force a fallback to HTTP/1.0.
909 - * http://support.microsoft.com/kb/263754
910 - */
911 - entity->he_rdata.request.httpmin = 0;
912 - } else if (config.ncaches) {
913 - if (!strcasecmp(name, "Pragma")) {
914 - entity->he_h_pragma = wstrdup(value);
915 - entity->he_headers.add(name, nlen, value, vlen);
916 - } else if (!strcasecmp(name, "Cache-Control")) {
917 - entity->he_h_cache_control = wstrdup(value);
918 - entity->he_headers.add(name, nlen, value, vlen);
919 - } else if (!strcasecmp(name, "If-Modified-Since")) {
920 - entity->he_h_if_modified_since = wstrdup(value);
921 - entity->he_headers.add(name, nlen, value, vlen);
922 - } else if (!strcasecmp(name, "Transfer-Encoding")) {
923 - entity->he_h_transfer_encoding = wstrdup(value);
924 - entity->he_headers.add(name, nlen, value, vlen);
925 - } else if (!strcasecmp(name, "Last-Modified")) {
926 - entity->he_h_last_modified = wstrdup(value);
927 - entity->he_headers.add(name, nlen, value, vlen);
928 - } else
929 - entity->he_headers.add(name, nlen, value, vlen);
930 - } else
931 - entity->he_headers.add(name, nlen, value, vlen);
932 - break;
933 - error:
934 - return -error;
935 - }
936 - }
937 - return 0;
938 -}
939 -
940 -static int
941 -parse_reqtype(http_entity *entity)
942 -{
943 - char *p, *s, *t;
944 - char *request = entity->he_reqstr;;
945 - int i;
946 -
947 - WDEBUG((WLOG_DEBUG, "parse_reqtype: called, response=%d", (int)entity->he_flags.response));
948 -
949 - /*
950 - * These probably shouldn't be handled in the same function.
951 - */
952 - if (entity->he_flags.response) {
953 - /*
954 - * HTTP/1.0
955 - */
956 - if ((p = strchr(request, ' ')) == NULL)
957 - return -1;
958 - *p++ = '\0';
959 -
960 - /* 200 */
961 - if ((s = strchr(p, ' ')) == NULL)
962 - return -1;
963 - *s++ = '\0';
964 - entity->he_rdata.response.status = atoi(p);
965 -
966 - /* OK */
967 - entity->he_rdata.response.status_str = s;
968 -
969 - WDEBUG((WLOG_DEBUG, "parse_reqtype: \"%s\" \"%d\" \"%s\"",
970 - request, entity->he_rdata.response.status,
971 - entity->he_rdata.response.status_str));
972 - return 0;
973 - }
974 -
975 - /* GET */
976 - if ((p = strchr(request, ' ')) == NULL)
977 - return -1;
978 -
979 - *p++ = '\0';
980 -
981 - for (i = 0; supported_reqtypes[i].name; i++)
982 - if (!strcmp(request, supported_reqtypes[i].name))
983 - break;
984 -
985 - entity->he_rdata.request.reqtype = supported_reqtypes[i].type;
986 - if (entity->he_rdata.request.reqtype == REQTYPE_INVALID)
987 - return -1;
988 -
989 - /* /path/to/file */
990 - if ((s = strchr(p, ' ')) == NULL)
991 - return -1;
992 -
993 - *s++ = '\0';
994 - if (*p != '/') {
995 - /*
996 - * This normally means the request URI was of the form
997 - * "http://host.tld/file". Clients don't send this, but
998 - * Squid does when it thinks we're a proxy.
999 - *
1000 - * Extract the host and set it now. If there's another host
1001 - * later, it'll overwrite it, but if the client sends two
1002 - * different hosts it's probably broken anyway...
1003 - *
1004 - * We could handle non-http URIs here, but there's not much
1005 - * points, the backend will reject it anyway.
1006 - */
1007 - if (strncmp(p, "http://", 7))
1008 - return -1;
1009 - p += 7;
1010 - t = strchr(p, '/');
1011 - if (t == NULL)
1012 - return -1;
1013 - memmove(p - 1, p, t - p);
1014 - entity->he_rdata.request.host = p - 1;
1015 - t[-1] = '\0';
1016 - entity->he_rdata.request.path = t;
1017 - } else {
1018 - entity->he_rdata.request.path = p;
1019 - }
1020 -
1021 - /* HTTP/1.0 */
1022 - if (sscanf(s, "HTTP/%d.%d", &entity->he_rdata.request.httpmaj,
1023 - &entity->he_rdata.request.httpmin) != 2)
1024 - return -1;
1025 -
1026 - return 0;
1027 -}
1028 -
1029 -int
1030 -qvalue_parse(set<qvalue> &list, const char *header)
1031 -{
1032 -char **values;
1033 -char **value;
1034 -
1035 - values = wstrvec(header, ",", 0);
1036 - for (value = values; *value; ++value) {
1037 - char **bits;
1038 - qvalue entry;
1039 - bits = wstrvec(*value, ";", 0);
1040 - entry.name = wstrdup(bits[0]);
1041 - if (bits[1])
1042 - entry.val = atof(bits[1]);
1043 - else
1044 - entry.val = 1.0;
1045 - list.insert(entry);
1046 - wstrvecfree(bits);
1047 - }
1048 -
1049 - wstrvecfree(values);
1050 - return 0;
1051 -}
1052 -
1053 -bool
1054 -qvalue_remove_best(set<qvalue> &list, qvalue &val)
1055 -{
1056 -set<qvalue>::iterator it;
1057 - if ((it = list.begin()) == list.end())
1058 - return false;
1059 - val = *it;
1060 - list.erase(it);
1061 - return true;
1062 -}
1063 -
1064 -enum encoding
1065 -accept_encoding(const char *enc)
1066 -{
1067 -static struct {
1068 - const char *name;
1069 - enum encoding value;
1070 -} encs[] = {
1071 - { "deflate", E_DEFLATE },
1072 - { "x-deflate", E_X_DEFLATE },
1073 - { "identity", E_NONE },
1074 - { "gzip", E_GZIP },
1075 - { "x-gzip", E_X_GZIP },
1076 - { NULL, E_NONE }
1077 -}, *s;
1078 - for (s = encs; s->name; s++)
1079 - if (!strcasecmp(s->name, enc))
1080 - return s->value;
1081 - return E_NONE;
1082 -}