1 diff -u apache_1.3.26/src/modules/proxy/mod_proxy.c apache_1.3.26-patched/src/modules/proxy/mod_proxy.c
2 --- apache_1.3.26/src/modules/proxy/mod_proxy.c Mon Jun 17 20:59:59 2002
3 +++ apache_1.3.26-patched/src/modules/proxy/mod_proxy.c Sun Jun 23 19:25:57 2002
5 static int proxy_fixup(request_rec *r)
12 if (r->proxyreq == NOT_PROXY || strncmp(r->filename, "proxy:", 6) != 0)
15 url = &r->filename[6];
17 /* canonicalise each specific scheme */
19 + if (ap_hook_use("ap::mod_proxy::canon",
20 + AP_HOOK_SIG3(int,ptr,ptr),
21 + AP_HOOK_DECLINE(DECLINED),
22 + &rc, r, url) && rc != DECLINED)
26 if (strncasecmp(url, "http:", 5) == 0)
27 return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);
28 else if (strncasecmp(url, "ftp:", 4) == 0)
30 static void proxy_init(server_rec *r, pool *p)
32 ap_proxy_garbage_init(r, p);
34 + ap_hook_use("ap::mod_proxy::init",
35 + AP_HOOK_SIG3(void,ptr,ptr), AP_HOOK_ALL, r, p);
41 +static void proxy_addmod(module *m)
43 + /* export: ap_proxy_http_canon() as `ap::mod_proxy::http::canon' */
44 + ap_hook_configure("ap::mod_proxy::http::canon",
45 + AP_HOOK_SIG5(int,ptr,ptr,ptr,int), AP_HOOK_TOPMOST);
46 + ap_hook_register("ap::mod_proxy::http::canon",
47 + ap_proxy_http_canon, AP_HOOK_NOCTX);
49 + /* export: ap_proxy_http_handler() as `ap::mod_proxy::http::handler' */
50 + ap_hook_configure("ap::mod_proxy::http::handler",
51 + AP_HOOK_SIG6(int,ptr,ptr,ptr,ptr,int), AP_HOOK_TOPMOST);
52 + ap_hook_register("ap::mod_proxy::http::handler",
53 + ap_proxy_http_handler, AP_HOOK_NOCTX);
55 + /* export: ap_proxyerror() as `ap::mod_proxy::error' */
56 + ap_hook_configure("ap::mod_proxy::error",
57 + AP_HOOK_SIG3(int,ptr,ptr), AP_HOOK_TOPMOST);
58 + ap_hook_register("ap::mod_proxy::error",
59 + ap_proxyerror, AP_HOOK_NOCTX);
63 +static void proxy_remmod(module *m)
65 + /* remove the hook references */
66 + ap_hook_unregister("ap::mod_proxy::http::canon", ap_proxy_http_canon);
67 + ap_hook_unregister("ap::mod_proxy::http::handler", ap_proxy_http_handler);
68 + ap_hook_unregister("ap::mod_proxy::error", ap_proxyerror);
73 /* Send a redirection if the request contains a hostname which is not */
74 /* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
76 * CONNECT is a special method that bypasses the normal proxy
80 + if (!ap_hook_use("ap::mod_proxy::handler",
81 + AP_HOOK_SIG7(int,ptr,ptr,ptr,ptr,int,ptr),
82 + AP_HOOK_DECLINE(DECLINED),
84 + ents[i].hostname, ents[i].port,
85 + ents[i].protocol) || rc == DECLINED) {
87 if (r->method_number == M_CONNECT)
88 rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,
98 /* an error or success */
99 if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)
103 /* handle the scheme */
105 + if (ap_hook_use("ap::mod_proxy::handler",
106 + AP_HOOK_SIG7(int,ptr,ptr,ptr,ptr,int,ptr),
107 + AP_HOOK_DECLINE(DECLINED),
109 + NULL, 0, scheme) && rc != DECLINED)
112 if (r->method_number == M_CONNECT) {
113 return ap_proxy_connect_handler(r, cr, url, NULL, 0);
116 ps->cache.dirlength_set = 0;
117 ps->cache.cache_completion = (float)DEFAULT_CACHE_COMPLETION;
118 ps->cache.cache_completion_set = 0;
119 + /* header manipulation */
120 + ps->freshen_date = ap_make_array(p, 10, sizeof(hdr_actions_entry));
121 + ps->resp_exp_vector = ap_make_array(p, 10, sizeof(resp_exp_vector_entry));
122 + ps->req_headers = ap_make_array(p, 10, sizeof(hdr_actions_entry));
123 + ps->resp_headers = ap_make_array(p, 10, sizeof(hdr_actions_entry));
128 ps->cache.dirlevels = (overrides->cache.dirlevels_set == 0) ? base->cache.dirlevels : overrides->cache.dirlevels;
129 ps->cache.dirlength = (overrides->cache.dirlength_set == 0) ? base->cache.dirlength : overrides->cache.dirlength;
130 ps->cache.cache_completion = (overrides->cache.cache_completion_set == 0) ? base->cache.cache_completion : overrides->cache.cache_completion;
131 + /* put freshen_date and resp_exp_vector from the overriding config
132 + in front of the base config arrays, the semantics being that
133 + virtual server configs should be checked first */
134 + ps->freshen_date = ap_append_arrays(p,overrides->freshen_date,base->freshen_date);
135 + ps->resp_exp_vector = ap_append_arrays(p,overrides->resp_exp_vector,base->resp_exp_vector);
136 + /* add req_ and resp_headers from the overriding config after
137 + those from the base config arrays, the semantics being that the
138 + directives are applied in declaration order, with those
139 + specific to a virtual server coming after and therefore
140 + overriding those from the root config */
141 + ps->req_headers = ap_append_arrays(p,base->req_headers,overrides->req_headers);
142 + ps->resp_headers = ap_append_arrays(p,base->resp_headers,overrides->resp_headers);
146 @@ -920,6 +1002,120 @@
151 + set_freshen_date(cmd_parms *parms, void *mconfig, char *one, char *two)
153 + proxy_server_conf *psf =
154 + ap_get_module_config(parms->server->module_config, &proxy_module);
155 + hdr_actions_entry *f =
156 + (hdr_actions_entry *)ap_push_array(psf->freshen_date);
158 + if (strcasecmp(one, "Off") == 0)
159 + f->action = hdr_off;
160 + else if (strcasecmp(one, "On") == 0)
161 + f->action = hdr_on;
163 + return "CacheFreshenDate must be either On or Off";
164 + /* set pattern (null is okay, will be dealt with at match time) */
166 + f->pattern = ap_pregcomp(parms->pool,two,REG_EXTENDED|REG_NOSUB);
167 + if (f->pattern == NULL)
169 + (parms->pool,"Regular expression could not be compiled: %s", two);
177 + set_resp_exp_vector(cmd_parms *parms, void *mconfig, char *one, char *two)
179 + proxy_server_conf *psf =
180 + ap_get_module_config(parms->server->module_config, &proxy_module);
181 + resp_exp_vector_entry *rev =
182 + (resp_exp_vector_entry *)ap_push_array(psf->resp_exp_vector);
184 + /* set seconds number */
186 + return "ProxyResponseExpiresVector must be a number of seconds (0 for \"immediately), or -1 to explicitly disable\"";
188 + /* set pattern (again, null is okay) */
190 + rev->pattern = ap_pregcomp(parms->pool,two,REG_EXTENDED|REG_NOSUB);
191 + if (rev->pattern == NULL)
193 + (parms->pool,"Regular expression could not be compiled: %s", two);
195 + rev->pattern = NULL;
201 + set_header_directive(cmd_parms *parms, void *mconfig, const char *args)
203 + char *one = ap_getword_conf(parms->pool,&args);
204 + char *two = ap_getword_conf(parms->pool,&args);
205 + char *three = ap_getword_conf(parms->pool,&args);
206 + char *four = ap_getword_conf(parms->pool,&args);
207 + proxy_server_conf *psf =
208 + ap_get_module_config(parms->server->module_config, &proxy_module);
209 + hdr_actions_entry *h;
210 + /* push onto the correct array */
211 + if (strcmp("ProxyRequestHeader",(char*)parms->info) == 0)
212 + h = (hdr_actions_entry *)ap_push_array(psf->req_headers);
214 + h = (hdr_actions_entry *)ap_push_array(psf->resp_headers);
216 + if (strcasecmp(one,"set") == 0)
217 + h->action = hdr_set;
218 + else if (strcasecmp(one,"unset") == 0)
219 + h->action = hdr_unset;
220 + else if (strcasecmp(one,"add") == 0)
221 + h->action = hdr_add;
222 + else if (strcasecmp(one,"append") == 0)
223 + h->action = hdr_append;
226 + (parms->pool, "Argument to %s must be one of set | unset | add | append",
227 + (char*)parms->info);
228 + /* set which header */
229 + h->header = ap_pstrdup(parms->pool,two);
230 + /* unset only takes 2/3 arguments -- so set its pattern and return */
231 + if (h->action == hdr_unset) {
232 + if (strcmp(three,"")!=0) {
233 + h->pattern = ap_pregcomp(parms->pool,three,REG_EXTENDED|REG_NOSUB);
234 + if (h->pattern == NULL)
236 + (parms->pool,"Regular expression could not be compiled: %s", three);
240 + if (!strcmp(four,"")==0)
242 + (parms->pool,"%s 'unset' only takes two or three arguments",
243 + (char*)parms->info);
246 + /* set value string */
247 + if (strcmp(three,"")==0)
249 + (parms->pool,"%s requires at least three arguments", (char*)parms->info);
250 + h->value = ap_pstrdup(parms->pool,three);
252 + if (strcmp(four,"")!=0) {
253 + h->pattern = ap_pregcomp(parms->pool,four,REG_EXTENDED|REG_NOSUB);
254 + if (h->pattern == NULL)
256 + (parms->pool,"Regular expression could not be compiled: %s", four);
264 static const handler_rec proxy_handlers[] =
266 {"proxy-server", proxy_handler},
267 @@ -970,6 +1166,16 @@
268 "Force a http cache completion after this percentage is loaded"},
269 {"ProxyVia", set_via_opt, NULL, RSRC_CONF, TAKE1,
270 "Configure Via: proxy header header to one of: on | off | block | full"},
271 + {"CacheFreshenDate", set_freshen_date, NULL, RSRC_CONF, TAKE12,
272 + "Whether to update the Date header when returning cached proxy responses"},
273 + {"ProxyResponseExpiresVector", set_resp_exp_vector, NULL, RSRC_CONF, TAKE12,
274 + "A constant to add to current time for expires headers on proxy response"},
275 + {"ProxyRequestHeader", set_header_directive, (void*)"ProxyRequestHeader",
276 + RSRC_CONF,RAW_ARGS,
277 + "A directive for headers to be sent with proxy requests"},
278 + {"ProxyResponseHeader", set_header_directive, (void*)"ProxyResponseHeader",
279 + RSRC_CONF,RAW_ARGS,
280 + "A directive for headers that are returned with responses"},
284 @@ -994,4 +1200,10 @@
285 NULL, /* child_init */
286 NULL, /* child_exit */
287 proxy_detect /* post read-request */
289 + ,proxy_addmod, /* EAPI: add_module */
290 + proxy_remmod, /* EAPI: remove_module */
291 + NULL, /* EAPI: rewrite_command */
292 + NULL /* EAPI: new_connection */
295 diff -u apache_1.3.26/src/modules/proxy/mod_proxy.h apache_1.3.26-patched/src/modules/proxy/mod_proxy.h
296 --- apache_1.3.26/src/modules/proxy/mod_proxy.h Sun Apr 21 07:35:07 2002
297 +++ apache_1.3.26-patched/src/modules/proxy/mod_proxy.h Sun Jun 23 18:36:11 2002
302 +/* for configurable headers */
304 + hdr_on, hdr_off, hdr_set, hdr_unset, hdr_add, hdr_append
308 + hdr_actions action;
312 +} hdr_actions_entry;
317 +} resp_exp_vector_entry;
319 #define DEFAULT_CACHE_SPACE 5
320 #define DEFAULT_CACHE_MAXEXPIRE SEC_ONE_DAY
321 #define DEFAULT_CACHE_EXPIRE SEC_ONE_HR
323 char recv_buffer_size_set;
324 size_t io_buffer_size;
325 char io_buffer_size_set;
326 + array_header *freshen_date;
327 + array_header *resp_exp_vector;
328 + array_header *req_headers;
329 + array_header *resp_headers;
334 table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
335 long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int nowrite, int chunked, size_t recv_buffer_size);
336 void ap_proxy_write_headers(cache_req *c, const char *respline, table *t);
337 +void ap_proxy_freshen_date(request_rec *r, proxy_server_conf *psf, table* t);
338 +void ap_proxy_vectored_exp(request_rec *r, proxy_server_conf *psf, table* t);
339 +void ap_proxy_header_fixup(request_rec *r, proxy_server_conf *psf, table* t,
340 + array_header *directives);
341 int ap_proxy_liststr(const char *list, const char *key, char **val);
342 void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
343 int ap_proxy_hex2sec(const char *x);
344 diff -u apache_1.3.26/src/modules/proxy/proxy_cache.c apache_1.3.26-patched/src/modules/proxy/proxy_cache.c
345 --- apache_1.3.26/src/modules/proxy/proxy_cache.c Mon Jun 3 08:28:27 2002
346 +++ apache_1.3.26-patched/src/modules/proxy/proxy_cache.c Sun Jun 23 19:59:20 2002
348 int ap_proxy_cache_conditional(request_rec *r, cache_req *c, BUFF *cachefp)
350 const char *etag, *wetag = NULL;
351 + proxy_server_conf *psf = (proxy_server_conf *)
352 + ap_get_module_config(r->server->module_config,&proxy_module);
355 if ((etag = ap_table_get(c->hdrs, "Etag"))) {
357 /* content type is already set in the headers */
358 r->content_type = ap_table_get(r->headers_out, "Content-Type");
360 + /* handle the cases where we need to modify the date and expires
361 + outgoing headers */
362 + ap_proxy_freshen_date(r,psf,r->headers_out);
363 + ap_proxy_vectored_exp(r,psf,r->headers_out);
365 ap_send_http_header(r);
367 /* are we rewriting the cache file? */
368 diff -u apache_1.3.26/src/modules/proxy/proxy_http.c apache_1.3.26-patched/src/modules/proxy/proxy_http.c
369 --- apache_1.3.26/src/modules/proxy/proxy_http.c Mon Jun 17 20:59:59 2002
370 +++ apache_1.3.26-patched/src/modules/proxy/proxy_http.c Sun Jun 23 20:14:14 2002
372 const char *datestr, *urlstr;
373 int result, major, minor;
374 const char *content_length;
379 void *sconf = r->server->module_config;
380 proxy_server_conf *conf =
382 return HTTP_BAD_REQUEST;
384 destport = DEFAULT_HTTP_PORT;
386 + ap_hook_use("ap::mod_proxy::http::handler::set_destport",
387 + AP_HOOK_SIG2(int,ptr),
391 strp = strchr(urlptr, '/');
393 desthost = ap_pstrdup(p, urlptr);
394 @@ -228,12 +237,18 @@
395 err = ap_proxy_host2addr(proxyhost, &server_hp);
397 return DECLINED; /* try another */
399 + peer = ap_psprintf(p, "%s:%u", proxyhost, proxyport);
403 server.sin_port = htons((unsigned short)destport);
404 err = ap_proxy_host2addr(desthost, &server_hp);
406 return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err);
408 + peer = ap_psprintf(p, "%s:%u", desthost, destport);
413 @@ -308,14 +323,45 @@
414 f = ap_bcreate(p, B_RDWR | B_SOCKET);
415 ap_bpushfd(f, sock, sock);
419 + char *errmsg = NULL;
420 + ap_hook_use("ap::mod_proxy::http::handler::new_connection",
421 + AP_HOOK_SIG4(ptr,ptr,ptr,ptr),
422 + AP_HOOK_DECLINE(NULL),
423 + &errmsg, r, f, peer);
424 + if (errmsg != NULL)
425 + return ap_proxyerror(r, HTTP_BAD_GATEWAY, errmsg);
429 ap_hard_timeout("proxy send", r);
430 ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.1" CRLF,
435 + ap_hook_use("ap::mod_proxy::http::handler::write_host_header",
436 + AP_HOOK_SIG6(int,ptr,ptr,ptr,int,ptr),
437 + AP_HOOK_DECLINE(DECLINED),
438 + &rc, r, f, desthost, destport, destportstr);
439 + if (rc == DECLINED) {
440 + if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
441 + ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
443 + ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
447 /* Send Host: now, adding it to req_hdrs wouldn't be much better */
448 if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
449 ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
451 ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
454 + /* run fixup for the request header directives */
455 + ap_proxy_header_fixup(r,conf,req_hdrs,conf->req_headers);
457 if (conf->viaopt == via_block) {
458 /* Block all outgoing Via: headers */
459 diff -u apache_1.3.26/src/modules/proxy/proxy_util.c apache_1.3.26-patched/src/modules/proxy/proxy_util.c
460 --- apache_1.3.26/src/modules/proxy/proxy_util.c Mon Jun 17 20:59:59 2002
461 +++ apache_1.3.26-patched/src/modules/proxy/proxy_util.c Sun Jun 23 20:03:54 2002
464 void ap_proxy_write_headers(cache_req *c, const char *respline, table *t)
466 - /* write status line */
467 + proxy_server_conf *psf = (proxy_server_conf *)
468 + ap_get_module_config(c->req->server->module_config,&proxy_module);
470 + /* write status line */
471 if (respline && c->fp != NULL &&
472 ap_bvputs(c->fp, respline, CRLF, NULL) == -1) {
473 ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
478 + /* Set extra response headers. We can set whatever we want here
479 + * (including Expires and family) because we've already written
480 + * the hex header line for the cache file. But the rest of the
481 + * cache file, including the HTTP headers, will include whatever
482 + * we adjust here. This is good, in general, but it does mean we
483 + * have to adjust any running-vector Expires headers in the
484 + * ap_proxy_send_headers, so even cached files get nice clean
485 + * headers with times set correctly in the future. */
486 + ap_proxy_vectored_exp(c->req,psf,t);
487 + ap_proxy_header_fixup(c->req,psf,t,psf->resp_headers);
489 /* write response headers to the cache file */
490 ap_table_do(ap_proxy_send_hdr_line, c, t, NULL);
496 +void ap_proxy_freshen_date(request_rec *r, proxy_server_conf *psf, table* t)
499 + hdr_actions_entry *list = (hdr_actions_entry*)psf->freshen_date->elts;
500 + for(i=0; i < psf->freshen_date->nelts; i++) {
501 + if(((list+i)->pattern == NULL) ||
502 + (regexec((list+i)->pattern,r->uri,0,NULL,0) != REG_NOMATCH)) {
503 + if ((list+i)->action == hdr_on) {
504 + ap_table_set(t, "Date",
505 + ap_ht_time(r->pool, time(NULL), "%a %d %b %Y %T %Z", 1));
512 +/* see whether there are ProxyVectoredExpire directives to apply to
513 + this request. (Don't do anything unless there is already an Expires
515 +void ap_proxy_vectored_exp(request_rec *r, proxy_server_conf *psf, table* t)
518 + resp_exp_vector_entry *list;
519 + /* don't do anything to a doc that doesn't *already* have an Expires */
520 + if (! ap_table_get(t,"Expires")) return;
521 + /* okay, loop through directives */
522 + list = (resp_exp_vector_entry*)psf->resp_exp_vector->elts;
523 + for(i=0; i < psf->resp_exp_vector->nelts; i++) {
524 + if(((list+i)->pattern == NULL) ||
525 + (regexec((list+i)->pattern,r->uri,0,NULL,0) != REG_NOMATCH)) {
526 + if ((list+i)->vector == -1) {
527 + } else if ((list+i)->vector == 0) {
528 + ap_table_setn(t, "Expires", "0");
529 + ap_table_setn(t, "Cache-Control", "max-age=0");
531 + ap_table_set(t, "Expires",
532 + ap_ht_time(r->pool, time(NULL)+(list+i)->vector,
533 + "%a %d %b %Y %T %Z", 1));
534 + ap_table_set(t, "Cache-Control",
535 + ap_psprintf(r->pool,"max-age=%d",(list+i)->vector));
542 +void ap_proxy_header_fixup(request_rec *r, proxy_server_conf *psf,
543 + table *t, array_header *directives)
546 + hdr_actions_entry *list = (hdr_actions_entry *)directives->elts;
547 + for (i=0; i < directives->nelts; i++) {
548 + if(((list+i)->pattern == NULL) ||
549 + (regexec((list+i)->pattern,r->uri,0,NULL,0) != REG_NOMATCH)) {
550 + switch ((list+i)->action) {
552 + ap_table_setn(t,(list+i)->header,(list+i)->value);
555 + ap_table_unset(t,(list+i)->header);
558 + ap_table_addn(t,(list+i)->header,(list+i)->value);
561 + ap_table_mergen(t,(list+i)->header,(list+i)->value);
569 * list is a comma-separated list of case-insensitive tokens, with