📄 mod_charset_lite.c
字号:
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * simple hokey charset recoding configuration module * * See mod_ebcdic and mod_charset for more thought-out examples. This * one is just so Jeff can learn how a module works and experiment with * basic character set recoding configuration. * * !!!This is an extremely cheap ripoff of mod_charset.c from Russian Apache!!! */#include "httpd.h"#include "http_config.h"#define CORE_PRIVATE#include "http_core.h"#include "http_log.h"#include "http_main.h"#include "http_protocol.h"#include "http_request.h"#include "util_charset.h"#include "apr_buckets.h"#include "util_filter.h"#include "apr_strings.h"#include "apr_lib.h"#include "apr_xlate.h"#define APR_WANT_STRFUNC#include "apr_want.h"#define OUTPUT_XLATE_BUF_SIZE (16*1024) /* size of translation buffer used on output */#define INPUT_XLATE_BUF_SIZE (8*1024) /* size of translation buffer used on input */#define XLATE_MIN_BUFF_LEFT 128 /* flush once there is no more than this much * space left in the translation buffer */#define FATTEST_CHAR 8 /* we don't handle chars wider than this that straddle * two buckets *//* extended error status codes; this is used in addition to an apr_status_t to * track errors in the translation filter */typedef enum { EES_INIT = 0, /* no error info yet; value must be 0 for easy init */ EES_LIMIT, /* built-in restriction encountered */ EES_INCOMPLETE_CHAR, /* incomplete multi-byte char at end of content */ EES_BUCKET_READ, EES_DOWNSTREAM, /* something bad happened in a filter below xlate */ EES_BAD_INPUT /* input data invalid */} ees_t;/* registered name of the output translation filter */#define XLATEOUT_FILTER_NAME "XLATEOUT"/* registered name of input translation filter */#define XLATEIN_FILTER_NAME "XLATEIN" typedef struct charset_dir_t { /** debug level; -1 means uninitialized, 0 means no debug */ int debug; const char *charset_source; /* source encoding */ const char *charset_default; /* how to ship on wire */ /** module does ap_add_*_filter()? */ enum {IA_INIT, IA_IMPADD, IA_NOIMPADD} implicit_add; } charset_dir_t;/* charset_filter_ctx_t is created for each filter instance; because the same * filter code is used for translating in both directions, we need this context * data to tell the filter which translation handle to use; it also can hold a * character which was split between buckets */typedef struct charset_filter_ctx_t { apr_xlate_t *xlate; charset_dir_t *dc; ees_t ees; /* extended error status */ apr_size_t saved; char buf[FATTEST_CHAR]; /* we want to be able to build a complete char here */ int ran; /* has filter instance run before? */ int noop; /* should we pass brigades through unchanged? */ char *tmp; /* buffer for input filtering */ apr_bucket_brigade *bb; /* input buckets we couldn't finish translating */} charset_filter_ctx_t;/* charset_req_t is available via r->request_config if any translation is * being performed */typedef struct charset_req_t { charset_dir_t *dc; charset_filter_ctx_t *output_ctx, *input_ctx;} charset_req_t;/* debug level definitions */#define DBGLVL_GORY 9 /* gory details */#define DBGLVL_FLOW 4 /* enough messages to see what happens on * each request */#define DBGLVL_PMC 2 /* messages about possible misconfiguration */module AP_MODULE_DECLARE_DATA charset_lite_module;static void *create_charset_dir_conf(apr_pool_t *p,char *dummy){ charset_dir_t *dc = (charset_dir_t *)apr_pcalloc(p,sizeof(charset_dir_t)); dc->debug = -1; return dc;}static void *merge_charset_dir_conf(apr_pool_t *p, void *basev, void *overridesv){ charset_dir_t *a = (charset_dir_t *)apr_pcalloc (p, sizeof(charset_dir_t)); charset_dir_t *base = (charset_dir_t *)basev, *over = (charset_dir_t *)overridesv; /* If it is defined in the current container, use it. Otherwise, use the one * from the enclosing container. */ a->debug = over->debug != -1 ? over->debug : base->debug; a->charset_default = over->charset_default ? over->charset_default : base->charset_default; a->charset_source = over->charset_source ? over->charset_source : base->charset_source; a->implicit_add = over->implicit_add != IA_INIT ? over->implicit_add : base->implicit_add; return a;}/* CharsetSourceEnc charset */static const char *add_charset_source(cmd_parms *cmd, void *in_dc, const char *name){ charset_dir_t *dc = in_dc; dc->charset_source = name; return NULL;}/* CharsetDefault charset */static const char *add_charset_default(cmd_parms *cmd, void *in_dc, const char *name){ charset_dir_t *dc = in_dc; dc->charset_default = name; return NULL;}/* CharsetOptions optionflag... */static const char *add_charset_options(cmd_parms *cmd, void *in_dc, const char *flag){ charset_dir_t *dc = in_dc; if (!strcasecmp(flag, "ImplicitAdd")) { dc->implicit_add = IA_IMPADD; } else if (!strcasecmp(flag, "NoImplicitAdd")) { dc->implicit_add = IA_NOIMPADD; } else if (!strncasecmp(flag, "DebugLevel=", 11)) { dc->debug = atoi(flag + 11); } else { return apr_pstrcat(cmd->temp_pool, "Invalid CharsetOptions option: ", flag, NULL); } return NULL;}/* find_code_page() is a fixup hook that decides if translation should be * enabled; if so, it sets up request data for use by the filter registration * hook so that it knows what to do */static int find_code_page(request_rec *r){ charset_dir_t *dc = ap_get_module_config(r->per_dir_config, &charset_lite_module); charset_req_t *reqinfo; charset_filter_ctx_t *input_ctx, *output_ctx; apr_status_t rv; const char *mime_type; if (dc->debug >= DBGLVL_FLOW) { ap_log_rerror(APLOG_MARK,APLOG_DEBUG, 0, r, "uri: %s file: %s method: %d " "imt: %s flags: %s%s%s %s->%s", r->uri, r->filename, r->method_number, r->content_type ? r->content_type : "(unknown)", r->main ? "S" : "", /* S if subrequest */ r->prev ? "R" : "", /* R if redirect */ r->proxyreq ? "P" : "", /* P if proxy */ dc->charset_source, dc->charset_default); } /* If we don't have a full directory configuration, bail out. */ if (!dc->charset_source || !dc->charset_default) { if (dc->debug >= DBGLVL_PMC) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "incomplete configuration: src %s, dst %s", dc->charset_source ? dc->charset_source : "unspecified", dc->charset_default ? dc->charset_default : "unspecified"); } return DECLINED; } /* catch proxy requests */ if (r->proxyreq) return DECLINED; /* mod_rewrite indicators */ if (!strncmp(r->filename, "redirect:", 9)) return DECLINED; if (!strncmp(r->filename, "gone:", 5)) return DECLINED; if (!strncmp(r->filename, "passthrough:", 12)) return DECLINED; if (!strncmp(r->filename, "forbidden:", 10)) return DECLINED; mime_type = r->content_type ? r->content_type : ap_default_type(r); /* If mime type isn't text or message, bail out. *//* XXX When we handle translation of the request body, watch out here as * 1.3 allowed additional mime types: multipart and * application/x-www-form-urlencoded */ if (strncasecmp(mime_type, "text/", 5) &&#if APR_CHARSET_EBCDIC || AP_WANT_DIR_TRANSLATION /* On an EBCDIC machine, be willing to translate mod_autoindex- * generated output. Otherwise, it doesn't look too cool. * * XXX This isn't a perfect fix because this doesn't trigger us * to convert from the charset of the source code to ASCII. The * general solution seems to be to allow a generator to set an * indicator in the r specifying that the body is coded in the * implementation character set (i.e., the charset of the source * code). This would get several different types of documents * translated properly: mod_autoindex output, mod_status output, * mod_info output, hard-coded error documents, etc. */ strcmp(mime_type, DIR_MAGIC_TYPE) &&#endif strncasecmp(mime_type, "message/", 8)) { if (dc->debug >= DBGLVL_GORY) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "mime type is %s; no translation selected", mime_type); } return DECLINED; } if (dc->debug >= DBGLVL_GORY) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "charset_source: %s charset_default: %s", dc && dc->charset_source ? dc->charset_source : "(none)", dc && dc->charset_default ? dc->charset_default : "(none)"); } /* Get storage for the request data and the output filter context. * We rarely need the input filter context, so allocate that separately. */ reqinfo = (charset_req_t *)apr_pcalloc(r->pool, sizeof(charset_req_t) + sizeof(charset_filter_ctx_t)); output_ctx = (charset_filter_ctx_t *)(reqinfo + 1); reqinfo->dc = dc; output_ctx->dc = dc; ap_set_module_config(r->request_config, &charset_lite_module, reqinfo); reqinfo->output_ctx = output_ctx; rv = apr_xlate_open(&output_ctx->xlate, dc->charset_default, dc->charset_source, r->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "can't open translation %s->%s", dc->charset_source, dc->charset_default); return HTTP_INTERNAL_SERVER_ERROR; } switch (r->method_number) { case M_PUT: case M_POST: /* Set up input translation. Note: A request body can be included * with the OPTIONS method, but for now we don't set up translation * of it. */ input_ctx = apr_pcalloc(r->pool, sizeof(charset_filter_ctx_t)); input_ctx->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); input_ctx->tmp = apr_palloc(r->pool, INPUT_XLATE_BUF_SIZE); input_ctx->dc = dc; reqinfo->input_ctx = input_ctx; rv = apr_xlate_open(&input_ctx->xlate, dc->charset_source, dc->charset_default, r->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "can't open translation %s->%s", dc->charset_default, dc->charset_source); return HTTP_INTERNAL_SERVER_ERROR; } } return DECLINED;}static int configured_in_list(request_rec *r, const char *filter_name, struct ap_filter_t *filter_list){ struct ap_filter_t *filter = filter_list; while (filter) { if (!strcasecmp(filter_name, filter->frec->name)) { return 1; } filter = filter->next; } return 0;}static int configured_on_input(request_rec *r, const char *filter_name){ return configured_in_list(r, filter_name, r->input_filters);}static int configured_on_output(request_rec *r, const char *filter_name){ return configured_in_list(r, filter_name, r->output_filters);}/* xlate_insert_filter() is a filter hook which decides whether or not * to insert a translation filter for the current request. */static void xlate_insert_filter(request_rec *r){ /* Hey... don't be so quick to use reqinfo->dc here; reqinfo may be NULL */ charset_req_t *reqinfo = ap_get_module_config(r->request_config, &charset_lite_module); charset_dir_t *dc = ap_get_module_config(r->per_dir_config, &charset_lite_module); if (reqinfo) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -