📄 mod_charset_lite.c
字号:
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 *//* send_downstream() is passed the translated data; it puts it in a single- * bucket brigade and passes the brigade to the next filter */static apr_status_t send_downstream(ap_filter_t *f, const char *tmp, apr_size_t len){ request_rec *r = f->r; conn_rec *c = r->connection; apr_bucket_brigade *bb; apr_bucket *b; charset_filter_ctx_t *ctx = f->ctx; apr_status_t rv; bb = apr_brigade_create(r->pool, c->bucket_alloc); b = apr_bucket_transient_create(tmp, len, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(f->next, bb); if (rv != APR_SUCCESS) { ctx->ees = EES_DOWNSTREAM; } return rv;}static apr_status_t send_eos(ap_filter_t *f){ request_rec *r = f->r; conn_rec *c = r->connection; apr_bucket_brigade *bb; apr_bucket *b; charset_filter_ctx_t *ctx = f->ctx; apr_status_t rv; bb = apr_brigade_create(r->pool, c->bucket_alloc); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(f->next, bb); if (rv != APR_SUCCESS) { ctx->ees = EES_DOWNSTREAM; } return rv;}static apr_status_t set_aside_partial_char(charset_filter_ctx_t *ctx, const char *partial, apr_size_t partial_len){ apr_status_t rv; if (sizeof(ctx->buf) > partial_len) { ctx->saved = partial_len; memcpy(ctx->buf, partial, partial_len); rv = APR_SUCCESS; } else { rv = APR_INCOMPLETE; ctx->ees = EES_LIMIT; /* we don't handle chars this wide which straddle * buckets */ } return rv;}static apr_status_t finish_partial_char(charset_filter_ctx_t *ctx, /* input buffer: */ const char **cur_str, apr_size_t *cur_len, /* output buffer: */ char **out_str, apr_size_t *out_len){ apr_status_t rv; apr_size_t tmp_input_len; /* Keep adding bytes from the input string to the saved string until we * 1) finish the input char * 2) get an error * or 3) run out of bytes to add */ do { ctx->buf[ctx->saved] = **cur_str; ++ctx->saved; ++*cur_str; --*cur_len; tmp_input_len = ctx->saved; rv = apr_xlate_conv_buffer(ctx->xlate, ctx->buf, &tmp_input_len, *out_str, out_len); } while (rv == APR_INCOMPLETE && *cur_len); if (rv == APR_SUCCESS) { ctx->saved = 0; } else { ctx->ees = EES_LIMIT; /* code isn't smart enough to handle chars * straddling more than two buckets */ } return rv;}static void log_xlate_error(ap_filter_t *f, apr_status_t rv){ charset_filter_ctx_t *ctx = f->ctx; const char *msg; char msgbuf[100]; int cur; switch(ctx->ees) { case EES_LIMIT: rv = 0; msg = "xlate filter - a built-in restriction was encountered"; break; case EES_BAD_INPUT: rv = 0; msg = "xlate filter - an input character was invalid"; break; case EES_BUCKET_READ: rv = 0; msg = "xlate filter - bucket read routine failed"; break; case EES_INCOMPLETE_CHAR: rv = 0; strcpy(msgbuf, "xlate filter - incomplete char at end of input - "); cur = 0; while ((apr_size_t)cur < ctx->saved) { apr_snprintf(msgbuf + strlen(msgbuf), sizeof(msgbuf) - strlen(msgbuf), "%02X", (unsigned)ctx->buf[cur]); ++cur; } msg = msgbuf; break; case EES_DOWNSTREAM: msg = "xlate filter - an error occurred in a lower filter"; break; default: msg = "xlate filter - returning error"; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "%s", msg);}/* chk_filter_chain() is called once per filter instance; it tries to * determine if the current filter instance should be disabled because * its translation is incompatible with the translation of an existing * instance of the translate filter * * Example bad scenario: * * configured filter chain for the request: * INCLUDES XLATEOUT(8859-1->UTS-16) * configured filter chain for the subrequest: * XLATEOUT(8859-1->UTS-16) * * When the subrequest is processed, the filter chain will be * XLATEOUT(8859-1->UTS-16) XLATEOUT(8859-1->UTS-16) * This makes no sense, so the instance of XLATEOUT added for the * subrequest will be noop-ed. * * Example good scenario: * * configured filter chain for the request: * INCLUDES XLATEOUT(8859-1->UTS-16) * configured filter chain for the subrequest: * XLATEOUT(IBM-1047->8859-1) * * When the subrequest is processed, the filter chain will be * XLATEOUT(IBM-1047->8859-1) XLATEOUT(8859-1->UTS-16) * This makes sense, so the instance of XLATEOUT added for the * subrequest will be left alone and it will translate from * IBM-1047->8859-1. */static void chk_filter_chain(ap_filter_t *f){ ap_filter_t *curf; charset_filter_ctx_t *curctx, *last_xlate_ctx = NULL, *ctx = f->ctx; int debug = ctx->dc->debug; int output = !strcasecmp(f->frec->name, XLATEOUT_FILTER_NAME); if (ctx->noop) { return; } /* walk the filter chain; see if it makes sense for our filter to * do any translation */ curf = output ? f->r->output_filters : f->r->input_filters; while (curf) { if (!strcasecmp(curf->frec->name, f->frec->name) && curf->ctx) { curctx = (charset_filter_ctx_t *)curf->ctx; if (!last_xlate_ctx) { last_xlate_ctx = curctx; } else { if (strcmp(last_xlate_ctx->dc->charset_default, curctx->dc->charset_source)) { /* incompatible translation * if our filter instance is incompatible with an instance * already in place, noop our instance * Notes: * . We are only willing to noop our own instance. * . It is possible to noop another instance which has not * yet run, but this is not currently implemented. * Hopefully it will not be needed. * . It is not possible to noop an instance which has * already run. */ if (last_xlate_ctx == f->ctx) { last_xlate_ctx->noop = 1; if (debug >= DBGLVL_PMC) { const char *symbol = output ? "->" : "<-"; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "%s %s - disabling " "translation %s%s%s; existing " "translation %s%s%s", f->r->uri ? "uri" : "file", f->r->uri ? f->r->uri : f->r->filename, last_xlate_ctx->dc->charset_source, symbol, last_xlate_ctx->dc->charset_default, curctx->dc->charset_source, symbol, curctx->dc->charset_default); } } else { const char *symbol = output ? "->" : "<-"; ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "chk_filter_chain() - can't disable " "translation %s%s%s; existing " "translation %s%s%s", last_xlate_ctx->dc->charset_source, symbol, last_xlate_ctx->dc->charset_default, curctx->dc->charset_source, symbol, curctx->dc->charset_default); } break; } } } curf = curf->next; }}/* xlate_brigade() is used to filter request and response bodies * * we'll stop when one of the following occurs: * . we run out of buckets * . we run out of space in the output buffer * . we hit an error * * inputs: * bb: brigade to process * buffer: storage to hold the translated characters * buffer_size: size of buffer * (and a few more uninteresting parms) * * outputs: * return value: APR_SUCCESS or some error code * bb: we've removed any buckets representing the * translated characters; the eos bucket, if * present, will be left in the brigade * buffer: filled in with translated characters * buffer_size: updated with the bytes remaining * hit_eos: did we hit an EOS bucket? */static apr_status_t xlate_brigade(charset_filter_ctx_t *ctx, apr_bucket_brigade *bb, char *buffer, apr_size_t *buffer_avail, int *hit_eos){ apr_bucket *b = NULL; /* set to NULL only to quiet some gcc */ apr_bucket *consumed_bucket; const char *bucket; apr_size_t bytes_in_bucket; /* total bytes read from current bucket */ apr_size_t bucket_avail; /* bytes left in current bucket */ apr_status_t rv = APR_SUCCESS; *hit_eos = 0; bucket_avail = 0; consumed_bucket = NULL; while (1) { if (!bucket_avail) { /* no bytes left to process in the current bucket... */ if (consumed_bucket) { apr_bucket_delete(consumed_bucket); consumed_bucket = NULL; } b = APR_BRIGADE_FIRST(bb); if (b == APR_BRIGADE_SENTINEL(bb) || APR_BUCKET_IS_EOS(b)) { break; } rv = apr_bucket_read(b, &bucket, &bytes_in_bucket, APR_BLOCK_READ); if (rv != APR_SUCCESS) { ctx->ees = EES_BUCKET_READ; break; } bucket_avail = bytes_in_bucket; consumed_bucket = b; /* for axing when we're done reading it */ } if (bucket_avail) { /* We've got data, so translate it. */ if (ctx->saved) { /* Rats... we need to finish a partial character from the previous * bucket. * * Strangely, finish_partial_char() increments the input buffer * pointer but does not increment the output buffer pointer. */ apr_size_t old_buffer_avail = *buffer_avail; rv = finish_partial_char(ctx, &bucket, &bucket_avail,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -