mod_filter.c.filterhdr 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define APR_WANT_STRFUNC
  17. #include "apr_want.h"
  18. #include "apr_lib.h"
  19. #include "apr_strings.h"
  20. #include "apr_hash.h"
  21. #include "httpd.h"
  22. #include "http_config.h"
  23. #include "http_request.h"
  24. #include "http_log.h"
  25. #include "util_filter.h"
  26. module AP_MODULE_DECLARE_DATA filter_module;
  27. /**
  28. * @brief is a filter provider, as defined and implemented by mod_filter.
  29. *
  30. * The struct is a linked list, with dispatch criteria
  31. * defined for each filter. The provider implementation itself is a
  32. * (2.0-compatible) ap_filter_rec_t* frec.
  33. */
  34. struct ap_filter_provider_t {
  35. /** How to match this provider to filter dispatch criterion */
  36. enum {
  37. STRING_MATCH,
  38. STRING_CONTAINS,
  39. REGEX_MATCH,
  40. INT_EQ,
  41. INT_LT,
  42. INT_LE,
  43. INT_GT,
  44. INT_GE,
  45. DEFINED
  46. } match_type;
  47. /** negation on match_type */
  48. int not;
  49. /** The dispatch match itself - union member depends on match_type */
  50. union {
  51. const char *string;
  52. ap_regex_t *regex;
  53. int number;
  54. } match;
  55. /** The filter that implements this provider */
  56. ap_filter_rec_t *frec;
  57. /** The next provider in the list */
  58. ap_filter_provider_t *next;
  59. /** Dispatch criteria for filter providers */
  60. enum {
  61. HANDLER,
  62. REQUEST_HEADERS,
  63. RESPONSE_HEADERS,
  64. SUBPROCESS_ENV,
  65. CONTENT_TYPE
  66. } dispatch;
  67. /** Match value for filter providers */
  68. const char* value;
  69. };
  70. /** we need provider_ctx to save ctx values set by providers in filter_init */
  71. typedef struct provider_ctx provider_ctx;
  72. struct provider_ctx {
  73. ap_filter_provider_t *provider;
  74. void *ctx;
  75. provider_ctx *next;
  76. };
  77. typedef struct {
  78. ap_out_filter_func func;
  79. void *fctx;
  80. provider_ctx *init_ctx;
  81. } harness_ctx;
  82. typedef struct mod_filter_chain {
  83. const char *fname;
  84. struct mod_filter_chain *next;
  85. } mod_filter_chain;
  86. typedef struct {
  87. apr_hash_t *live_filters;
  88. mod_filter_chain *chain;
  89. } mod_filter_cfg;
  90. typedef struct {
  91. const char* range ;
  92. } mod_filter_ctx ;
  93. static void filter_trace(conn_rec *c, int debug, const char *fname,
  94. apr_bucket_brigade *bb)
  95. {
  96. apr_bucket *b;
  97. switch (debug) {
  98. case 0: /* normal, operational use */
  99. return;
  100. case 1: /* mod_diagnostics level */
  101. ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s", fname);
  102. for (b = APR_BRIGADE_FIRST(bb);
  103. b != APR_BRIGADE_SENTINEL(bb);
  104. b = APR_BUCKET_NEXT(b)) {
  105. ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
  106. "%s: type: %s, length: %" APR_SIZE_T_FMT,
  107. fname, b->type->name ? b->type->name : "(unknown)",
  108. b->length);
  109. }
  110. break;
  111. }
  112. }
  113. static int filter_init(ap_filter_t *f)
  114. {
  115. ap_filter_provider_t *p;
  116. provider_ctx *pctx;
  117. int err;
  118. ap_filter_rec_t *filter = f->frec;
  119. harness_ctx *fctx = apr_pcalloc(f->r->pool, sizeof(harness_ctx));
  120. for (p = filter->providers; p; p = p->next) {
  121. if (p->frec->filter_init_func == filter_init) {
  122. ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c,
  123. "Chaining of FilterProviders not supported");
  124. return HTTP_INTERNAL_SERVER_ERROR;
  125. }
  126. else if (p->frec->filter_init_func) {
  127. f->ctx = NULL;
  128. if ((err = p->frec->filter_init_func(f)) != OK) {
  129. ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c,
  130. "filter_init for %s failed", p->frec->name);
  131. return err; /* if anyone errors out here, so do we */
  132. }
  133. if (f->ctx != NULL) {
  134. /* the filter init function set a ctx - we need to record it */
  135. pctx = apr_pcalloc(f->r->pool, sizeof(provider_ctx));
  136. pctx->provider = p;
  137. pctx->ctx = f->ctx;
  138. pctx->next = fctx->init_ctx;
  139. fctx->init_ctx = pctx;
  140. }
  141. }
  142. }
  143. f->ctx = fctx;
  144. return OK;
  145. }
  146. static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
  147. {
  148. ap_filter_provider_t *provider;
  149. const char *str = NULL;
  150. char *str1;
  151. int match;
  152. unsigned int proto_flags;
  153. request_rec *r = f->r;
  154. harness_ctx *ctx = f->ctx;
  155. provider_ctx *pctx;
  156. mod_filter_ctx *rctx = ap_get_module_config(r->request_config,
  157. &filter_module);
  158. /* Check registered providers in order */
  159. for (provider = filter->providers; provider; provider = provider->next) {
  160. match = 1;
  161. switch (provider->dispatch) {
  162. case REQUEST_HEADERS:
  163. str = apr_table_get(r->headers_in, provider->value);
  164. break;
  165. case RESPONSE_HEADERS:
  166. str = apr_table_get(r->headers_out, provider->value);
  167. break;
  168. case SUBPROCESS_ENV:
  169. str = apr_table_get(r->subprocess_env, provider->value);
  170. break;
  171. case CONTENT_TYPE:
  172. str = r->content_type;
  173. break;
  174. case HANDLER:
  175. str = r->handler;
  176. break;
  177. }
  178. /* treat nulls so we don't have to check every strcmp individually
  179. * Not sure if there's anything better to do with them
  180. */
  181. if (!str) {
  182. match = 0;
  183. }
  184. /* we can't check for NULL in provider as that kills integer 0
  185. * so we have to test each string/regexp case in the switch
  186. */
  187. else {
  188. switch (provider->match_type) {
  189. case STRING_MATCH:
  190. if (strcasecmp(str, provider->match.string)) {
  191. match = 0;
  192. }
  193. break;
  194. case STRING_CONTAINS:
  195. str1 = apr_pstrdup(r->pool, str);
  196. ap_str_tolower(str1);
  197. if (!strstr(str1, provider->match.string)) {
  198. match = 0;
  199. }
  200. break;
  201. case REGEX_MATCH:
  202. if (ap_regexec(provider->match.regex, str, 0, NULL, 0)
  203. == AP_REG_NOMATCH) {
  204. match = 0;
  205. }
  206. break;
  207. case INT_EQ:
  208. if (atoi(str) != provider->match.number) {
  209. match = 0;
  210. }
  211. break;
  212. /* Integer comparisons should be [var] OP [match]
  213. * We need to set match = 0 if the condition fails
  214. */
  215. case INT_LT:
  216. if (atoi(str) >= provider->match.number) {
  217. match = 0;
  218. }
  219. break;
  220. case INT_LE:
  221. if (atoi(str) > provider->match.number) {
  222. match = 0;
  223. }
  224. break;
  225. case INT_GT:
  226. if (atoi(str) <= provider->match.number) {
  227. match = 0;
  228. }
  229. break;
  230. case INT_GE:
  231. if (atoi(str) < provider->match.number) {
  232. match = 0;
  233. }
  234. break;
  235. case DEFINED: /* we already handled this:-) */
  236. break;
  237. }
  238. }
  239. if (match != provider->not) {
  240. /* condition matches this provider */
  241. #ifndef NO_PROTOCOL
  242. /* check protocol
  243. *
  244. * FIXME:
  245. * This is a quick hack and almost certainly buggy.
  246. * The idea is that by putting this in mod_filter, we relieve
  247. * filter implementations of the burden of fixing up HTTP headers
  248. * for cases that are routinely affected by filters.
  249. *
  250. * Default is ALWAYS to do nothing, so as not to tread on the
  251. * toes of filters which want to do it themselves.
  252. *
  253. */
  254. proto_flags = provider->frec->proto_flags;
  255. /* some specific things can't happen in a proxy */
  256. if (r->proxyreq) {
  257. if (proto_flags & AP_FILTER_PROTO_NO_PROXY) {
  258. /* can't use this provider; try next */
  259. continue;
  260. }
  261. if (proto_flags & AP_FILTER_PROTO_TRANSFORM) {
  262. str = apr_table_get(r->headers_out, "Cache-Control");
  263. if (str) {
  264. str1 = apr_pstrdup(r->pool, str);
  265. ap_str_tolower(str1);
  266. if (strstr(str1, "no-transform")) {
  267. /* can't use this provider; try next */
  268. continue;
  269. }
  270. }
  271. apr_table_addn(r->headers_out, "Warning",
  272. apr_psprintf(r->pool,
  273. "214 %s Transformation applied",
  274. r->hostname));
  275. }
  276. }
  277. /* things that are invalidated if the filter transforms content */
  278. if (proto_flags & AP_FILTER_PROTO_CHANGE) {
  279. apr_table_unset(r->headers_out, "Content-MD5");
  280. apr_table_unset(r->headers_out, "ETag");
  281. if (proto_flags & AP_FILTER_PROTO_CHANGE_LENGTH) {
  282. apr_table_unset(r->headers_out, "Content-Length");
  283. }
  284. }
  285. /* no-cache is for a filter that has different effect per-hit */
  286. if (proto_flags & AP_FILTER_PROTO_NO_CACHE) {
  287. apr_table_unset(r->headers_out, "Last-Modified");
  288. apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
  289. }
  290. if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) {
  291. apr_table_unset(r->headers_out, "Accept-Ranges");
  292. }
  293. else if (rctx && rctx->range) {
  294. /* restore range header we saved earlier */
  295. apr_table_setn(r->headers_in, "Range", rctx->range);
  296. rctx->range = NULL;
  297. }
  298. #endif
  299. for (pctx = ctx->init_ctx; pctx; pctx = pctx->next) {
  300. if (pctx->provider == provider) {
  301. ctx->fctx = pctx->ctx ;
  302. }
  303. }
  304. ctx->func = provider->frec->filter_func.out_func;
  305. return 1;
  306. }
  307. }
  308. /* No provider matched */
  309. return 0;
  310. }
  311. static apr_status_t filter_harness(ap_filter_t *f, apr_bucket_brigade *bb)
  312. {
  313. apr_status_t ret;
  314. const char *cachecontrol;
  315. char *str;
  316. harness_ctx *ctx = f->ctx;
  317. ap_filter_rec_t *filter = f->frec;
  318. if (f->r->status != 200) {
  319. ap_remove_output_filter(f);
  320. return ap_pass_brigade(f->next, bb);
  321. }
  322. filter_trace(f->c, filter->debug, f->frec->name, bb);
  323. /* look up a handler function if we haven't already set it */
  324. if (!ctx->func) {
  325. #ifndef NO_PROTOCOL
  326. if (f->r->proxyreq) {
  327. if (filter->proto_flags & AP_FILTER_PROTO_NO_PROXY) {
  328. ap_remove_output_filter(f);
  329. return ap_pass_brigade(f->next, bb);
  330. }
  331. if (filter->proto_flags & AP_FILTER_PROTO_TRANSFORM) {
  332. cachecontrol = apr_table_get(f->r->headers_out,
  333. "Cache-Control");
  334. if (cachecontrol) {
  335. str = apr_pstrdup(f->r->pool, cachecontrol);
  336. ap_str_tolower(str);
  337. if (strstr(str, "no-transform")) {
  338. ap_remove_output_filter(f);
  339. return ap_pass_brigade(f->next, bb);
  340. }
  341. }
  342. }
  343. }
  344. #endif
  345. if (!filter_lookup(f, filter)) {
  346. ap_remove_output_filter(f);
  347. return ap_pass_brigade(f->next, bb);
  348. }
  349. }
  350. /* call the content filter with its own context, then restore our
  351. * context
  352. */
  353. f->ctx = ctx->fctx;
  354. ret = ctx->func(f, bb);
  355. ctx->fctx = f->ctx;
  356. f->ctx = ctx;
  357. return ret;
  358. }
  359. #ifndef NO_PROTOCOL
  360. static const char *filter_protocol(cmd_parms *cmd, void *CFG, const char *fname,
  361. const char *pname, const char *proto)
  362. {
  363. static const char *sep = ";, \t";
  364. char *arg;
  365. char *tok = 0;
  366. unsigned int flags = 0;
  367. mod_filter_cfg *cfg = CFG;
  368. ap_filter_provider_t *provider = NULL;
  369. ap_filter_rec_t *filter = apr_hash_get(cfg->live_filters, fname,
  370. APR_HASH_KEY_STRING);
  371. if (!filter) {
  372. return "FilterProtocol: No such filter";
  373. }
  374. /* Fixup the args: it's really pname that's optional */
  375. if (proto == NULL) {
  376. proto = pname;
  377. pname = NULL;
  378. }
  379. else {
  380. /* Find provider */
  381. for (provider = filter->providers; provider; provider = provider->next){
  382. if (!strcasecmp(provider->frec->name, pname)) {
  383. break;
  384. }
  385. }
  386. if (!provider) {
  387. return "FilterProtocol: No such provider for this filter";
  388. }
  389. }
  390. /* Now set flags from our args */
  391. for (arg = apr_strtok(apr_pstrdup(cmd->pool, proto), sep, &tok);
  392. arg; arg = apr_strtok(NULL, sep, &tok)) {
  393. if (!strcasecmp(arg, "change=yes")) {
  394. flags |= AP_FILTER_PROTO_CHANGE | AP_FILTER_PROTO_CHANGE_LENGTH;
  395. }
  396. else if (!strcasecmp(arg, "change=1:1")) {
  397. flags |= AP_FILTER_PROTO_CHANGE;
  398. }
  399. else if (!strcasecmp(arg, "byteranges=no")) {
  400. flags |= AP_FILTER_PROTO_NO_BYTERANGE;
  401. }
  402. else if (!strcasecmp(arg, "proxy=no")) {
  403. flags |= AP_FILTER_PROTO_NO_PROXY;
  404. }
  405. else if (!strcasecmp(arg, "proxy=transform")) {
  406. flags |= AP_FILTER_PROTO_TRANSFORM;
  407. }
  408. else if (!strcasecmp(arg, "cache=no")) {
  409. flags |= AP_FILTER_PROTO_NO_CACHE;
  410. }
  411. }
  412. if (pname) {
  413. provider->frec->proto_flags = flags;
  414. }
  415. else {
  416. filter->proto_flags = flags;
  417. }
  418. return NULL;
  419. }
  420. #endif
  421. static const char *filter_declare(cmd_parms *cmd, void *CFG, const char *fname,
  422. const char *place)
  423. {
  424. mod_filter_cfg *cfg = (mod_filter_cfg *)CFG;
  425. ap_filter_rec_t *filter;
  426. filter = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t));
  427. apr_hash_set(cfg->live_filters, fname, APR_HASH_KEY_STRING, filter);
  428. filter->name = fname;
  429. filter->filter_init_func = filter_init;
  430. filter->filter_func.out_func = filter_harness;
  431. filter->ftype = AP_FTYPE_RESOURCE;
  432. filter->next = NULL;
  433. if (place) {
  434. if (!strcasecmp(place, "CONTENT_SET")) {
  435. filter->ftype = AP_FTYPE_CONTENT_SET;
  436. }
  437. else if (!strcasecmp(place, "PROTOCOL")) {
  438. filter->ftype = AP_FTYPE_PROTOCOL;
  439. }
  440. else if (!strcasecmp(place, "CONNECTION")) {
  441. filter->ftype = AP_FTYPE_CONNECTION;
  442. }
  443. else if (!strcasecmp(place, "NETWORK")) {
  444. filter->ftype = AP_FTYPE_NETWORK;
  445. }
  446. }
  447. return NULL;
  448. }
  449. static const char *filter_provider(cmd_parms *cmd, void *CFG, const char *args)
  450. {
  451. mod_filter_cfg *cfg = CFG;
  452. int flags;
  453. ap_filter_provider_t *provider;
  454. const char *rxend;
  455. const char *c;
  456. char *str;
  457. const char *eq;
  458. ap_filter_rec_t* frec;
  459. ap_filter_rec_t* provider_frec;
  460. /* insist on exactly four arguments */
  461. const char *fname = ap_getword_conf(cmd->pool, &args) ;
  462. const char *pname = ap_getword_conf(cmd->pool, &args) ;
  463. const char *condition = ap_getword_conf(cmd->pool, &args) ;
  464. const char *match = ap_getword_conf(cmd->pool, &args) ;
  465. eq = ap_getword_conf(cmd->pool, &args) ;
  466. if ( !*fname || !*pname || !*match || !*condition || *eq ) {
  467. return "usage: FilterProvider filter provider condition match" ;
  468. }
  469. /* fname has been declared with DeclareFilter, so we can look it up */
  470. frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
  471. /* or if provider is mod_filter itself, we can also look it up */
  472. if (!frec) {
  473. c = filter_declare(cmd, CFG, fname, NULL);
  474. if ( c ) {
  475. return c;
  476. }
  477. frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
  478. }
  479. if (!frec) {
  480. return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname);
  481. }
  482. /* if provider has been registered, we can look it up */
  483. provider_frec = ap_get_output_filter_handle(pname);
  484. if (!provider_frec) {
  485. return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname);
  486. }
  487. provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t));
  488. if (*match == '!') {
  489. provider->not = 1;
  490. ++match;
  491. }
  492. else {
  493. provider->not = 0;
  494. }
  495. switch (*match++) {
  496. case '<':
  497. if (*match == '=') {
  498. provider->match_type = INT_LE;
  499. ++match;
  500. }
  501. else {
  502. provider->match_type = INT_LT;
  503. }
  504. provider->match.number = atoi(match);
  505. break;
  506. case '>':
  507. if (*match == '=') {
  508. provider->match_type = INT_GE;
  509. ++match;
  510. }
  511. else {
  512. provider->match_type = INT_GT;
  513. }
  514. provider->match.number = atoi(match);
  515. break;
  516. case '=':
  517. provider->match_type = INT_EQ;
  518. provider->match.number = atoi(match);
  519. break;
  520. case '/':
  521. provider->match_type = REGEX_MATCH;
  522. rxend = ap_strchr_c(match, '/');
  523. if (!rxend) {
  524. return "Bad regexp syntax";
  525. }
  526. flags = AP_REG_NOSUB; /* we're not mod_rewrite:-) */
  527. for (c = rxend+1; *c; ++c) {
  528. switch (*c) {
  529. case 'i': flags |= AP_REG_ICASE; break;
  530. }
  531. }
  532. provider->match.regex = ap_pregcomp(cmd->pool,
  533. apr_pstrndup(cmd->pool,
  534. match,
  535. rxend-match),
  536. flags);
  537. if (provider->match.regex == NULL) {
  538. return "Bad regexp";
  539. }
  540. break;
  541. case '*':
  542. provider->match_type = DEFINED;
  543. provider->match.number = -1;
  544. break;
  545. case '$':
  546. provider->match_type = STRING_CONTAINS;
  547. str = apr_pstrdup(cmd->pool, match);
  548. ap_str_tolower(str);
  549. provider->match.string = str;
  550. break;
  551. default:
  552. provider->match_type = STRING_MATCH;
  553. provider->match.string = apr_pstrdup(cmd->pool, match-1);
  554. break;
  555. }
  556. provider->frec = provider_frec;
  557. provider->next = frec->providers;
  558. frec->providers = provider;
  559. /* determine what a filter will dispatch this provider on */
  560. eq = ap_strchr_c(condition, '=');
  561. if (eq) {
  562. str = apr_pstrdup(cmd->pool, eq+1);
  563. if (!strncasecmp(condition, "env=", 4)) {
  564. provider->dispatch = SUBPROCESS_ENV;
  565. }
  566. else if (!strncasecmp(condition, "req=", 4)) {
  567. provider->dispatch = REQUEST_HEADERS;
  568. }
  569. else if (!strncasecmp(condition, "resp=", 5)) {
  570. provider->dispatch = RESPONSE_HEADERS;
  571. }
  572. else {
  573. return "FilterProvider: unrecognized dispatch table";
  574. }
  575. }
  576. else {
  577. if (!strcasecmp(condition, "handler")) {
  578. provider->dispatch = HANDLER;
  579. }
  580. else {
  581. provider->dispatch = RESPONSE_HEADERS;
  582. }
  583. str = apr_pstrdup(cmd->pool, condition);
  584. ap_str_tolower(str);
  585. }
  586. if ( (provider->dispatch == RESPONSE_HEADERS)
  587. && !strcasecmp(str, "content-type")) {
  588. provider->dispatch = CONTENT_TYPE;
  589. }
  590. provider->value = str;
  591. return NULL;
  592. }
  593. static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg)
  594. {
  595. mod_filter_chain *p;
  596. mod_filter_chain *q;
  597. mod_filter_cfg *cfg = CFG;
  598. switch (arg[0]) {
  599. case '+': /* add to end of chain */
  600. p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
  601. p->fname = arg+1;
  602. if (cfg->chain) {
  603. for (q = cfg->chain; q->next; q = q->next);
  604. q->next = p;
  605. }
  606. else {
  607. cfg->chain = p;
  608. }
  609. break;
  610. case '@': /* add to start of chain */
  611. p = apr_palloc(cmd->pool, sizeof(mod_filter_chain));
  612. p->fname = arg+1;
  613. p->next = cfg->chain;
  614. cfg->chain = p;
  615. break;
  616. case '-': /* remove from chain */
  617. if (cfg->chain) {
  618. if (strcasecmp(cfg->chain->fname, arg+1)) {
  619. for (p = cfg->chain; p->next; p = p->next) {
  620. if (!strcasecmp(p->next->fname, arg+1)) {
  621. p->next = p->next->next;
  622. }
  623. }
  624. }
  625. else {
  626. cfg->chain = cfg->chain->next;
  627. }
  628. }
  629. break;
  630. case '!': /* Empty the chain */
  631. /** IG: Add a NULL provider to the beginning so that
  632. * we can ensure that we'll empty everything before
  633. * this when doing config merges later */
  634. p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
  635. p->fname = NULL;
  636. cfg->chain = p;
  637. break;
  638. case '=': /* initialise chain with this arg */
  639. /** IG: Prepend a NULL provider to the beginning as above */
  640. p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
  641. p->fname = NULL;
  642. p->next = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
  643. p->next->fname = arg+1;
  644. cfg->chain = p;
  645. break;
  646. default: /* add to end */
  647. p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
  648. p->fname = arg;
  649. if (cfg->chain) {
  650. for (q = cfg->chain; q->next; q = q->next);
  651. q->next = p;
  652. }
  653. else {
  654. cfg->chain = p;
  655. }
  656. break;
  657. }
  658. return NULL;
  659. }
  660. static const char *filter_debug(cmd_parms *cmd, void *CFG, const char *fname,
  661. const char *level)
  662. {
  663. mod_filter_cfg *cfg = CFG;
  664. ap_filter_rec_t *frec = apr_hash_get(cfg->live_filters, fname,
  665. APR_HASH_KEY_STRING);
  666. if (!frec) {
  667. return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname);
  668. }
  669. frec->debug = atoi(level);
  670. return NULL;
  671. }
  672. static void filter_insert(request_rec *r)
  673. {
  674. mod_filter_chain *p;
  675. ap_filter_rec_t *filter;
  676. mod_filter_cfg *cfg = ap_get_module_config(r->per_dir_config,
  677. &filter_module);
  678. #ifndef NO_PROTOCOL
  679. int ranges = 1;
  680. mod_filter_ctx *ctx = apr_pcalloc(r->pool, sizeof(mod_filter_ctx));
  681. ap_set_module_config(r->request_config, &filter_module, ctx);
  682. #endif
  683. /** IG: Now that we've merged to the final config, go one last time
  684. * through the chain, and prune out the NULL filters */
  685. for (p = cfg->chain; p; p = p->next) {
  686. if (p->fname == NULL)
  687. cfg->chain = p->next;
  688. }
  689. for (p = cfg->chain; p; p = p->next) {
  690. filter = apr_hash_get(cfg->live_filters, p->fname, APR_HASH_KEY_STRING);
  691. if (filter == NULL) {
  692. ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
  693. "Unknown filter %s not added", p->fname);
  694. continue;
  695. }
  696. ap_add_output_filter_handle(filter, NULL, r, r->connection);
  697. #ifndef NO_PROTOCOL
  698. if (ranges && (filter->proto_flags
  699. & (AP_FILTER_PROTO_NO_BYTERANGE
  700. | AP_FILTER_PROTO_CHANGE_LENGTH))) {
  701. ctx->range = apr_table_get(r->headers_in, "Range");
  702. apr_table_unset(r->headers_in, "Range");
  703. ranges = 0;
  704. }
  705. #endif
  706. }
  707. return;
  708. }
  709. static void filter_hooks(apr_pool_t *pool)
  710. {
  711. ap_hook_insert_filter(filter_insert, NULL, NULL, APR_HOOK_MIDDLE);
  712. }
  713. static void *filter_config(apr_pool_t *pool, char *x)
  714. {
  715. mod_filter_cfg *cfg = apr_palloc(pool, sizeof(mod_filter_cfg));
  716. cfg->live_filters = apr_hash_make(pool);
  717. cfg->chain = NULL;
  718. return cfg;
  719. }
  720. static void *filter_merge(apr_pool_t *pool, void *BASE, void *ADD)
  721. {
  722. mod_filter_cfg *base = BASE;
  723. mod_filter_cfg *add = ADD;
  724. mod_filter_chain *savelink = 0;
  725. mod_filter_chain *newlink;
  726. mod_filter_chain *p;
  727. mod_filter_cfg *conf = apr_palloc(pool, sizeof(mod_filter_cfg));
  728. conf->live_filters = apr_hash_overlay(pool, add->live_filters,
  729. base->live_filters);
  730. if (base->chain && add->chain) {
  731. for (p = base->chain; p; p = p->next) {
  732. newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain));
  733. if (newlink->fname == NULL) {
  734. conf->chain = savelink = newlink;
  735. }
  736. else if (savelink) {
  737. savelink->next = newlink;
  738. savelink = newlink;
  739. }
  740. else {
  741. conf->chain = savelink = newlink;
  742. }
  743. }
  744. for (p = add->chain; p; p = p->next) {
  745. newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain));
  746. /** Filter out merged chain resets */
  747. if (newlink->fname == NULL) {
  748. conf->chain = savelink = newlink;
  749. }
  750. else if (savelink) {
  751. savelink->next = newlink;
  752. savelink = newlink;
  753. }
  754. else {
  755. conf->chain = savelink = newlink;
  756. }
  757. }
  758. }
  759. else if (add->chain) {
  760. conf->chain = add->chain;
  761. }
  762. else {
  763. conf->chain = base->chain;
  764. }
  765. return conf;
  766. }
  767. static const command_rec filter_cmds[] = {
  768. AP_INIT_TAKE12("FilterDeclare", filter_declare, NULL, OR_OPTIONS,
  769. "filter-name [, filter-type]"),
  770. /** we don't have a TAKE4, so we have to use RAW_ARGS */
  771. AP_INIT_RAW_ARGS("FilterProvider", filter_provider, NULL, OR_OPTIONS,
  772. "filter-name, provider-name, dispatch--criterion, dispatch-match"),
  773. AP_INIT_ITERATE("FilterChain", filter_chain, NULL, OR_OPTIONS,
  774. "list of filter names with optional [+-=!@]"),
  775. AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, RSRC_CONF | ACCESS_CONF,
  776. "Debug level"),
  777. #ifndef NO_PROTOCOL
  778. AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_OPTIONS,
  779. "filter-name [provider-name] protocol-args"),
  780. #endif
  781. { NULL }
  782. };
  783. module AP_MODULE_DECLARE_DATA filter_module = {
  784. STANDARD20_MODULE_STUFF,
  785. filter_config,
  786. filter_merge,
  787. NULL,
  788. NULL,
  789. filter_cmds,
  790. filter_hooks
  791. };