⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_charset_lite.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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;    /** treat all mimetypes as text? */    enum {FX_INIT, FX_FORCE, FX_NOFORCE} force_xlate;} 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;    int is_sb;              /* single-byte translation? */    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 */    apr_bucket_brigade *tmpbb; /* used for passing downstream */} 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;    a->force_xlate=        over->force_xlate != FX_INIT ? over->force_xlate : base->force_xlate;    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;    }    if (!strcasecmp(flag, "TranslateAllMimeTypes")) {        dc->force_xlate = FX_FORCE;    }    else if (!strcasecmp(flag, "NoTranslateAllMimeTypes")) {        dc->force_xlate = FX_NOFORCE;    }    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 checks if the module is * configured and the input or output potentially need to be translated. * If so, context is initialized for the filters. */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;    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->filename : "(none)",                      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 (r->filename        && (!strncmp(r->filename, "redirect:", 9)            || !strncmp(r->filename, "gone:", 5)            || !strncmp(r->filename, "passthrough:", 12)            || !strncmp(r->filename, "forbidden:", 10))) {        return DECLINED;    }    /* no translation when server and network charsets are set to the same value */    if (!strcasecmp(dc->charset_source, dc->charset_default)) {        return DECLINED;    }    /* 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;    output_ctx->tmpbb = apr_brigade_create(r->pool,                                            r->connection->bucket_alloc);    ap_set_module_config(r->request_config, &charset_lite_module, reqinfo);    reqinfo->output_ctx = output_ctx;    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;        }        if (apr_xlate_sb_get(input_ctx->xlate, &input_ctx->is_sb) != APR_SUCCESS) {            input_ctx->is_sb = 0;        }    }    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) {        if (reqinfo->output_ctx && !configured_on_output(r, XLATEOUT_FILTER_NAME)) {            ap_add_output_filter(XLATEOUT_FILTER_NAME, reqinfo->output_ctx, r,                                 r->connection);        }        else if (dc->debug >= DBGLVL_FLOW) {            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,                          "xlate output filter not added implicitly because %s",                          !reqinfo->output_ctx ?                          "no output configuration available" :                          "another module added the filter");        }        if (reqinfo->input_ctx && !configured_on_input(r, XLATEIN_FILTER_NAME)) {            ap_add_input_filter(XLATEIN_FILTER_NAME, reqinfo->input_ctx, r,                                r->connection);        }        else if (dc->debug >= DBGLVL_FLOW) {            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,                          "xlate input filter not added implicitly because %s",                          !reqinfo->input_ctx ?                          "no input configuration available" :                          "another module added the filter");        }    }}/* stuff that sucks that I know of: * * bucket handling: *  why create an eos bucket when we see it come down the stream?  just send the one *  passed as input...  news flash: this will be fixed when xlate_out_filter() starts *  using the more generic xlate_brigade() * * translation mechanics: *   we don't handle characters that straddle more than two buckets; an error *   will be generated */static apr_status_t send_bucket_downstream(ap_filter_t *f, apr_bucket *b){    charset_filter_ctx_t *ctx = f->ctx;    apr_status_t rv;    APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, b);    rv = ap_pass_brigade(f->next, ctx->tmpbb);    if (rv != APR_SUCCESS) {        ctx->ees = EES_DOWNSTREAM;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -