@@ -0,0 +1,553 @@
+/********************************************************************
+ Copyright (c) 2005-6, WebThing Ltd
+ Author: Nick Kew <nick@webthing.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*********************************************************************/
+
+
+#define LINE_EDIT_VERSION "1.0.0"
+
+#include <ctype.h>
+
+#include <httpd.h>
+#include <http_config.h>
+#include <util_filter.h>
+
+#include <apr_strmatch.h>
+#include <apr_strings.h>
+
+#ifdef AP_REG_ICASE
+#define APACHE21
+#else
+#define APACHE20
+#endif
+
+#ifdef APACHE20
+#define ap_regex_t regex_t
+#define ap_regmatch_t regmatch_t
+#define AP_REG_EXTENDED REG_EXTENDED
+#define AP_REG_ICASE REG_ICASE
+#define AP_REG_NOSUB REG_NOSUB
+#define AP_REG_NEWLINE REG_NEWLINE
+
+/* we don't have protocol handling in 2.0 */
+#define ap_register_output_filter_protocol(a,b,c,d,e) \
+ ap_register_output_filter(a,b,c,d)
+#endif
+
+#define M_REGEX 0x01
+#define M_NOCASE 0x08
+#define M_NEWLINE 0x10
+#define M_ENV 0x20
+
+typedef struct {
+ union {
+ const apr_strmatch_pattern* s;
+ const ap_regex_t* r ;
+ } from ;
+ const char* to ;
+ unsigned int flags ;
+ unsigned int length ;
+} rewriterule ;
+
+typedef struct {
+ enum {
+ LINEEND_UNSET,
+ LINEEND_ANY,
+ LINEEND_UNIX,
+ LINEEND_MAC,
+ LINEEND_DOS,
+ LINEEND_CUSTOM,
+ LINEEND_NONE
+ } lineend ;
+ apr_array_header_t* rewriterules ;
+ int lechar;
+} line_edit_cfg ;
+
+module AP_MODULE_DECLARE_DATA line_edit_module ;
+
+static const char* const line_edit_filter_name = "line-editor" ;
+
+typedef struct {
+ apr_bucket_brigade* bbsave ;
+ apr_pool_t* lpool ;
+ apr_array_header_t* rewriterules ; /* make a copy if per-request
+ interpolation is wanted */
+} line_edit_ctx ;
+
+static const char* interpolate_env(request_rec *r, const char *str) {
+ /* Interpolate an env str in a configuration string
+ * Syntax ${var} --> value_of(var)
+ * Method: replace one var, and recurse on remainder of string
+ * Nothing clever here, and crap like nested vars may do silly things
+ * but we'll at least avoid sending the unwary into a loop
+ */
+ const char *start;
+ const char *end;
+ const char *var;
+ const char *val;
+ const char *firstpart;
+
+ start = ap_strstr(str, "${");
+ if (start == NULL) {
+ return str;
+ }
+ end = ap_strchr(start+2, '}');
+ if (end == NULL) {
+ return str;
+ }
+ /* OK, this is syntax we want to interpolate. Is there such a var ? */
+ var = apr_pstrndup(r->pool, start+2, end-(start+2));
+ val = apr_table_get(r->subprocess_env, var);
+ firstpart = apr_pstrndup(r->pool, str, (start-str));
+
+ if (val == NULL) {
+ return apr_pstrcat(r->pool, firstpart, interpolate_env(r, end+1), NULL);
+ } else {
+ return apr_pstrcat(r->pool, firstpart, val,
+ interpolate_env(r, end+1), NULL);
+ }
+}
+static apr_status_t line_edit_filter(ap_filter_t* f, apr_bucket_brigade* bb) {
+ int i, j;
+ unsigned int match ;
+ unsigned int nmatch = 10 ;
+ ap_regmatch_t pmatch[10] ;
+ const char* bufp;
+ const char* subs ;
+ apr_size_t bytes ;
+ apr_size_t fbytes ;
+ apr_size_t offs ;
+ const char* buf ;
+ const char* le = NULL ;
+ const char* le_n ;
+ const char* le_r ;
+ char* fbuf ;
+ apr_bucket* b = APR_BRIGADE_FIRST(bb) ;
+ apr_bucket* b1 ;
+ int found = 0 ;
+ apr_status_t rv ;
+
+ apr_bucket_brigade* bbline ;
+ line_edit_cfg* cfg
+ = ap_get_module_config(f->r->per_dir_config, &line_edit_module) ;
+ rewriterule* rules = (rewriterule*) cfg->rewriterules->elts ;
+ rewriterule* newrule;
+
+ line_edit_ctx* ctx = f->ctx ;
+ if (ctx == NULL) {
+
+ /* check env to see if we're wanted, to give basic control with 2.0 */
+ buf = apr_table_get(f->r->subprocess_env, "LineEdit");
+ if (buf && f->r->content_type) {
+ char* lcbuf = apr_pstrdup(f->r->pool, buf) ;
+ char* lctype = apr_pstrdup(f->r->pool, f->r->content_type) ;
+ char* c ;
+
+ for (c = lcbuf; *c; ++c)
+ if (isupper(*c))
+ *c = tolower(*c) ;
+
+ for (c = lctype; *c; ++c)
+ if (isupper(*c))
+ *c = tolower(*c) ;
+ else if (*c == ';') {
+ *c = 0 ;
+ break ;
+ }
+
+ if (!strstr(lcbuf, lctype)) {
+ /* don't filter this content type */
+ ap_filter_t* fnext = f->next ;
+ ap_remove_output_filter(f) ;
+ return ap_pass_brigade(fnext, bb) ;
+ }
+ }
+
+ ctx = f->ctx = apr_palloc(f->r->pool, sizeof(line_edit_ctx)) ;
+ ctx->bbsave = apr_brigade_create(f->r->pool, f->c->bucket_alloc) ;
+
+ /* If we have any regex matches, we'll need to copy everything, so we
+ * have null-terminated strings to parse. That's a lot of memory if
+ * we're streaming anything big. So we'll use (and reuse) a local
+ * subpool. Fall back to the request pool if anything bad happens.
+ */
+ ctx->lpool = f->r->pool ;
+ for (i = 0; i < cfg->rewriterules->nelts; ++i) {
+ if ( rules[i].flags & M_REGEX ) {
+ if (apr_pool_create(&ctx->lpool, f->r->pool) != APR_SUCCESS) {
+ ctx->lpool = f->r->pool ;
+ }
+ break ;
+ }
+ }
+ /* If we have env interpolation, we'll need a private copy of
+ * our rewrite rules with this requests env. Otherwise we can
|