apr_status_t ap_init_ebcdic(apr_pool_t *pool) { apr_status_t rv; char buf[80]; rv = apr_xlate_open(&ap_hdrs_to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, pool); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_xlate_open() failed"); return rv; } rv = apr_xlate_open(&ap_hdrs_from_ascii, APR_DEFAULT_CHARSET, "ISO8859-1", pool); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_xlate_open() failed"); return rv; } rv = apr_xlate_open(&ap_locale_to_ascii, "ISO8859-1", APR_LOCALE_CHARSET, pool); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_xlate_open() failed"); return rv; } rv = apr_xlate_open(&ap_locale_from_ascii, APR_LOCALE_CHARSET, "ISO8859-1", pool); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_xlate_open() failed"); return rv; } rv = apr_MD5InitEBCDIC(ap_hdrs_to_ascii); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_MD5InitEBCDIC() failed"); return rv; } rv = apr_base64init_ebcdic(ap_hdrs_to_ascii, ap_hdrs_from_ascii); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_base64init_ebcdic() failed"); return rv; } rv = apr_SHA1InitEBCDIC(ap_hdrs_to_ascii); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_SHA1InitEBCDIC() failed"); return rv; } return APR_SUCCESS; }
static const char *add_basic_auth_conversion(const char *encoding, authnz_crowd_dir_config *config, apr_pool_t *pconf, apr_pool_t *ptemp) { apr_xlate_t *conversion; if (apr_xlate_open(&conversion, "UTF-8", encoding, pconf) != APR_SUCCESS) { const char *error = log_palloc(ptemp, apr_psprintf(ptemp, "Encoding not supported: '%s'", encoding)); if (error == NULL) { error = "Out of memory"; } return error; } APR_ARRAY_PUSH(config->basic_auth_xlates, apr_xlate_t *) = conversion; return NULL; }
/** * Creates a new instance. * @param frompage name of source encoding. */ APRCharsetDecoder(const LogString& frompage) : pool(), mutex(pool) { #if LOG4CXX_LOGCHAR_IS_WCHAR const char* topage = "WCHAR_T"; #endif #if LOG4CXX_LOGCHAR_IS_UTF8 const char* topage = "UTF-8"; #endif #if LOG4CXX_LOGCHAR_IS_UNICHAR const char* topage = "UTF-16"; #endif std::string fpage(Transcoder::encodeCharsetName(frompage)); apr_status_t stat = apr_xlate_open(&convset, topage, fpage.c_str(), pool.getAPRPool()); if (stat != APR_SUCCESS) { throw IllegalArgumentException(frompage); } }
static apr_status_t htdbm_init(apr_pool_t **pool, htdbm_t **hdbm) { #if APR_CHARSET_EBCDIC apr_status_t rv; #endif apr_pool_create( pool, NULL); apr_pool_abort_set(abort_on_oom, *pool); apr_file_open_stderr(&errfile, *pool); apr_signal(SIGINT, (void (*)(int)) htdbm_interrupted); (*hdbm) = (htdbm_t *)apr_pcalloc(*pool, sizeof(htdbm_t)); (*hdbm)->ctx.pool = *pool; #if APR_CHARSET_EBCDIC rv = apr_xlate_open(&((*hdbm)->to_ascii), "ISO-8859-1", APR_DEFAULT_CHARSET, (*hdbm)->ctx.pool); if (rv) { fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", rv); return APR_EGENERAL; } rv = apr_SHA1InitEBCDIC((*hdbm)->to_ascii); if (rv) { fprintf(stderr, "apr_SHA1InitEBCDIC()->%d\n", rv); return APR_EGENERAL; } rv = apr_MD5InitEBCDIC((*hdbm)->to_ascii); if (rv) { fprintf(stderr, "apr_MD5InitEBCDIC()->%d\n", rv); return APR_EGENERAL; } #endif /*APR_CHARSET_EBCDIC*/ /* Set MD5 as default */ (*hdbm)->ctx.alg = ALG_APMD5; (*hdbm)->type = "default"; return APR_SUCCESS; }
/* xlate_out_filter() handles (almost) arbitrary conversions from one charset * to another... * translation is determined in the fixup hook (find_code_page), which is * where the filter's context data is set up... the context data gives us * the translation handle */ static apr_status_t xlate_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) { charset_req_t *reqinfo = ap_get_module_config(f->r->request_config, &charset_lite_module); charset_dir_t *dc = ap_get_module_config(f->r->per_dir_config, &charset_lite_module); charset_filter_ctx_t *ctx = f->ctx; apr_bucket *dptr, *consumed_bucket; const char *cur_str; apr_size_t cur_len, cur_avail; char tmp[OUTPUT_XLATE_BUF_SIZE]; apr_size_t space_avail; int done; apr_status_t rv = APR_SUCCESS; if (!ctx) { /* this is SetOutputFilter path; grab the preallocated context, * if any; note that if we decided not to do anything in an earlier * handler, we won't even have a reqinfo */ if (reqinfo) { ctx = f->ctx = reqinfo->output_ctx; reqinfo->output_ctx = NULL; /* prevent SNAFU if user coded us twice * in the filter chain; we can't have two * instances using the same context */ } if (!ctx) { /* no idea how to translate; don't do anything */ ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(charset_filter_ctx_t)); ctx->dc = dc; ctx->noop = 1; } } /* Check the mime type to see if translation should be performed. */ if (!ctx->noop && ctx->xlate == NULL) { const char *mime_type = f->r->content_type; if (mime_type && (strncasecmp(mime_type, "text/", 5) == 0 || #if APR_CHARSET_EBCDIC /* 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) == 0 || #endif strncasecmp(mime_type, "message/", 8) == 0 || dc->force_xlate == FX_FORCE)) { rv = apr_xlate_open(&ctx->xlate, dc->charset_default, dc->charset_source, f->r->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01453) "can't open translation %s->%s", dc->charset_source, dc->charset_default); ctx->noop = 1; } else { if (apr_xlate_sb_get(ctx->xlate, &ctx->is_sb) != APR_SUCCESS) { ctx->is_sb = 0; } } } else { ctx->noop = 1; if (mime_type) { ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, f->r, "mime type is %s; no translation selected", mime_type); } } } ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, f->r, "xlate_out_filter() - " "charset_source: %s charset_default: %s", dc && dc->charset_source ? dc->charset_source : "(none)", dc && dc->charset_default ? dc->charset_default : "(none)"); if (!ctx->ran) { /* filter never ran before */ chk_filter_chain(f); ctx->ran = 1; if (!ctx->noop && !ctx->is_sb) { /* We're not converting between two single-byte charsets, so unset * Content-Length since it is unlikely to remain the same. */ apr_table_unset(f->r->headers_out, "Content-Length"); } } if (ctx->noop) { return ap_pass_brigade(f->next, bb); } dptr = APR_BRIGADE_FIRST(bb); done = 0; cur_len = 0; space_avail = sizeof(tmp); consumed_bucket = NULL; while (!done) { if (!cur_len) { /* no bytes left to process in the current bucket... */ if (consumed_bucket) { apr_bucket_delete(consumed_bucket); consumed_bucket = NULL; } if (dptr == APR_BRIGADE_SENTINEL(bb)) { break; } if (APR_BUCKET_IS_EOS(dptr)) { cur_len = -1; /* XXX yuck, but that tells us to send * eos down; when we minimize our bb construction * we'll fix this crap */ if (ctx->saved) { /* Oops... we have a partial char from the previous bucket * that won't be completed because there's no more data. */ rv = APR_INCOMPLETE; ctx->ees = EES_INCOMPLETE_CHAR; } break; } if (APR_BUCKET_IS_METADATA(dptr)) { apr_bucket *metadata_bucket; metadata_bucket = dptr; dptr = APR_BUCKET_NEXT(dptr); APR_BUCKET_REMOVE(metadata_bucket); rv = send_bucket_downstream(f, metadata_bucket); if (rv != APR_SUCCESS) { done = 1; } continue; } rv = apr_bucket_read(dptr, &cur_str, &cur_len, APR_BLOCK_READ); if (rv != APR_SUCCESS) { ctx->ees = EES_BUCKET_READ; break; } consumed_bucket = dptr; /* for axing when we're done reading it */ dptr = APR_BUCKET_NEXT(dptr); /* get ready for when we access the * next bucket */ } /* Try to fill up our tmp buffer with translated data. */ cur_avail = cur_len; if (cur_len) { /* maybe we just hit the end of a pipe (len = 0) ? */ if (ctx->saved) { /* Rats... we need to finish a partial character from the previous * bucket. */ char *tmp_tmp; tmp_tmp = tmp + sizeof(tmp) - space_avail; rv = finish_partial_char(ctx, &cur_str, &cur_len, &tmp_tmp, &space_avail); } else { rv = apr_xlate_conv_buffer(ctx->xlate, cur_str, &cur_avail, tmp + sizeof(tmp) - space_avail, &space_avail); /* Update input ptr and len after consuming some bytes */ cur_str += cur_len - cur_avail; cur_len = cur_avail; if (rv == APR_INCOMPLETE) { /* partial character at end of input */ /* We need to save the final byte(s) for next time; we can't * convert it until we look at the next bucket. */ rv = set_aside_partial_char(ctx, cur_str, cur_len); cur_len = 0; } } } if (rv != APR_SUCCESS) { /* bad input byte or partial char too big to store */ done = 1; } if (space_avail < XLATE_MIN_BUFF_LEFT) { /* It is time to flush, as there is not enough space left in the * current output buffer to bother with converting more data. */ rv = send_downstream(f, tmp, sizeof(tmp) - space_avail); if (rv != APR_SUCCESS) { done = 1; } /* tmp is now empty */ space_avail = sizeof(tmp); } } if (rv == APR_SUCCESS) { if (space_avail < sizeof(tmp)) { /* gotta write out what we converted */ rv = send_downstream(f, tmp, sizeof(tmp) - space_avail); } } if (rv == APR_SUCCESS) { if (cur_len == -1) { rv = send_eos(f); } } else { log_xlate_error(f, rv); } return rv; }
/* 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; ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 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) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01448) "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, APLOGNO(01449) "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; }
/* * Let's do it. We end up doing a lot of file opening and closing, * but what do we care? This application isn't run constantly. */ int main(int argc, const char * const argv[]) { apr_file_t *fpw = NULL; char record[MAX_STRING_LEN]; char line[MAX_STRING_LEN]; char *password = NULL; char *pwfilename = NULL; char *user = NULL; char tn[] = "htpasswd.tmp.XXXXXX"; char *dirname; char *scratch, cp[MAX_STRING_LEN]; int found = 0; int i; int alg = ALG_APMD5; int mask = 0; apr_pool_t *pool; int existing_file = 0; #if APR_CHARSET_EBCDIC apr_status_t rv; apr_xlate_t *to_ascii; #endif apr_app_initialize(&argc, &argv, NULL); atexit(terminate); apr_pool_create(&pool, NULL); apr_file_open_stderr(&errfile, pool); #if APR_CHARSET_EBCDIC rv = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, pool); if (rv) { apr_file_printf(errfile, "apr_xlate_open(to ASCII)->%d" NL, rv); exit(1); } rv = apr_SHA1InitEBCDIC(to_ascii); if (rv) { apr_file_printf(errfile, "apr_SHA1InitEBCDIC()->%d" NL, rv); exit(1); } rv = apr_MD5InitEBCDIC(to_ascii); if (rv) { apr_file_printf(errfile, "apr_MD5InitEBCDIC()->%d" NL, rv); exit(1); } #endif /*APR_CHARSET_EBCDIC*/ check_args(pool, argc, argv, &alg, &mask, &user, &pwfilename, &password); #if defined(WIN32) || defined(NETWARE) if (alg == ALG_CRYPT) { alg = ALG_APMD5; apr_file_printf(errfile, "Automatically using MD5 format." NL); } #endif #if (!(defined(WIN32) || defined(TPF) || defined(NETWARE))) if (alg == ALG_PLAIN) { apr_file_printf(errfile,"Warning: storing passwords as plain text " "might just not work on this platform." NL); } #endif /* * Only do the file checks if we're supposed to frob it. */ if (!(mask & APHTP_NOFILE)) { existing_file = exists(pwfilename, pool); if (existing_file) { /* * Check that this existing file is readable and writable. */ if (!accessible(pool, pwfilename, APR_READ | APR_APPEND)) { apr_file_printf(errfile, "%s: cannot open file %s for " "read/write access" NL, argv[0], pwfilename); exit(ERR_FILEPERM); } } else { /* * Error out if -c was omitted for this non-existant file. */ if (!(mask & APHTP_NEWFILE)) { apr_file_printf(errfile, "%s: cannot modify file %s; use '-c' to create it" NL, argv[0], pwfilename); exit(ERR_FILEPERM); } /* * As it doesn't exist yet, verify that we can create it. */ if (!accessible(pool, pwfilename, APR_CREATE | APR_WRITE)) { apr_file_printf(errfile, "%s: cannot create file %s" NL, argv[0], pwfilename); exit(ERR_FILEPERM); } } } /* * All the file access checks (if any) have been made. Time to go to work; * try to create the record for the username in question. If that * fails, there's no need to waste any time on file manipulations. * Any error message text is returned in the record buffer, since * the mkrecord() routine doesn't have access to argv[]. */ if (!(mask & APHTP_DELUSER)) { i = mkrecord(user, record, sizeof(record) - 1, password, alg); if (i != 0) { apr_file_printf(errfile, "%s: %s" NL, argv[0], record); exit(i); } if (mask & APHTP_NOFILE) { printf("%s" NL, record); exit(0); } } /* * We can access the files the right way, and we have a record * to add or update. Let's do it.. */ if (apr_temp_dir_get((const char**)&dirname, pool) != APR_SUCCESS) { apr_file_printf(errfile, "%s: could not determine temp dir" NL, argv[0]); exit(ERR_FILEPERM); } dirname = apr_psprintf(pool, "%s/%s", dirname, tn); if (apr_file_mktemp(&ftemp, dirname, 0, pool) != APR_SUCCESS) { apr_file_printf(errfile, "%s: unable to create temporary file %s" NL, argv[0], dirname); exit(ERR_FILEPERM); } /* * If we're not creating a new file, copy records from the existing * one to the temporary file until we find the specified user. */ if (existing_file && !(mask & APHTP_NEWFILE)) { if (apr_file_open(&fpw, pwfilename, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool) != APR_SUCCESS) { apr_file_printf(errfile, "%s: unable to read file %s" NL, argv[0], pwfilename); exit(ERR_FILEPERM); } while (apr_file_gets(line, sizeof(line), fpw) == APR_SUCCESS) { char *colon; strcpy(cp, line); scratch = cp; while (apr_isspace(*scratch)) { ++scratch; } if (!*scratch || (*scratch == '#')) { putline(ftemp, line); continue; } /* * See if this is our user. */ colon = strchr(scratch, ':'); if (colon != NULL) { *colon = '\0'; } else { /* * If we've not got a colon on the line, this could well * not be a valid htpasswd file. * We should bail at this point. */ apr_file_printf(errfile, "%s: The file %s does not appear " "to be a valid htpasswd file." NL, argv[0], pwfilename); apr_file_close(fpw); exit(ERR_INVALID); } if (strcmp(user, scratch) != 0) { putline(ftemp, line); continue; } else { if (!(mask & APHTP_DELUSER)) { /* We found the user we were looking for. * Add him to the file. */ apr_file_printf(errfile, "Updating "); putline(ftemp, record); found++; } else { /* We found the user we were looking for. * Delete them from the file. */ apr_file_printf(errfile, "Deleting "); found++; } } } apr_file_close(fpw); } if (!found && !(mask & APHTP_DELUSER)) { apr_file_printf(errfile, "Adding "); putline(ftemp, record); } else if (!found && (mask & APHTP_DELUSER)) { apr_file_printf(errfile, "User %s not found" NL, user); exit(0); } apr_file_printf(errfile, "password for user %s" NL, user); /* The temporary file has all the data, just copy it to the new location. */ if (apr_file_copy(dirname, pwfilename, APR_FILE_SOURCE_PERMS, pool) != APR_SUCCESS) { apr_file_printf(errfile, "%s: unable to update file %s" NL, argv[0], pwfilename); exit(ERR_FILEPERM); } apr_file_close(ftemp); return 0; }
int main(int argc, const char * const argv[]) { apr_file_t *f; apr_status_t rv; char tn[] = "htdigest.tmp.XXXXXX"; char *dirname; char user[MAX_STRING_LEN]; char realm[MAX_STRING_LEN]; char line[MAX_STRING_LEN]; char l[MAX_STRING_LEN]; char w[MAX_STRING_LEN]; char x[MAX_STRING_LEN]; int found; apr_app_initialize(&argc, &argv, NULL); atexit(terminate); apr_pool_create(&cntxt, NULL); apr_file_open_stderr(&errfile, cntxt); #if APR_CHARSET_EBCDIC rv = apr_xlate_open(&to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, cntxt); if (rv) { apr_file_printf(errfile, "apr_xlate_open(): %s (%d)\n", apr_strerror(rv, line, sizeof(line)), rv); exit(1); } #endif apr_signal(SIGINT, (void (*)(int)) interrupted); if (argc == 5) { if (strcmp(argv[1], "-c")) usage(); rv = apr_file_open(&f, argv[2], APR_WRITE | APR_CREATE, APR_OS_DEFAULT, cntxt); if (rv != APR_SUCCESS) { char errmsg[120]; apr_file_printf(errfile, "Could not open passwd file %s for writing: %s\n", argv[2], apr_strerror(rv, errmsg, sizeof errmsg)); exit(1); } apr_file_printf(errfile, "Adding password for %s in realm %s.\n", argv[4], argv[3]); add_password(argv[4], argv[3], f); apr_file_close(f); exit(0); } else if (argc != 4) usage(); if (apr_temp_dir_get((const char**)&dirname, cntxt) != APR_SUCCESS) { apr_file_printf(errfile, "%s: could not determine temp dir\n", argv[0]); exit(1); } dirname = apr_psprintf(cntxt, "%s/%s", dirname, tn); if (apr_file_mktemp(&tfp, dirname, 0, cntxt) != APR_SUCCESS) { apr_file_printf(errfile, "Could not open temp file %s.\n", dirname); exit(1); } if (apr_file_open(&f, argv[1], APR_READ, APR_OS_DEFAULT, cntxt) != APR_SUCCESS) { apr_file_printf(errfile, "Could not open passwd file %s for reading.\n", argv[1]); apr_file_printf(errfile, "Use -c option to create new one.\n"); cleanup_tempfile_and_exit(1); } apr_cpystrn(user, argv[3], sizeof(user)); apr_cpystrn(realm, argv[2], sizeof(realm)); found = 0; while (!(get_line(line, MAX_STRING_LEN, f))) { if (found || (line[0] == '#') || (!line[0])) { putline(tfp, line); continue; } strcpy(l, line); getword(w, l, ':'); getword(x, l, ':'); if (strcmp(user, w) || strcmp(realm, x)) { putline(tfp, line); continue; } else { apr_file_printf(errfile, "Changing password for user %s in realm %s\n", user, realm); add_password(user, realm, tfp); found = 1; } } if (!found) { apr_file_printf(errfile, "Adding user %s in realm %s\n", user, realm); add_password(user, realm, tfp); } apr_file_close(f); /* The temporary file has all the data, just copy it to the new location. */ if (apr_file_copy(dirname, argv[1], APR_FILE_SOURCE_PERMS, cntxt) != APR_SUCCESS) { apr_file_printf(errfile, "%s: unable to update file %s\n", argv[0], argv[1]); } apr_file_close(tfp); return 0; }
/* 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; /* no translation when server and network charsets are set to the same value */ if (!strcasecmp(dc->charset_source, dc->charset_default)) 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); } /* We must not bail out here (i.e., the MIME test must be in the filter * itself, not in the fixup, because only then is the final MIME type known. * Examples for late changes to the MIME type include CGI handling (MIME * type is set in the Content-Type header produced by the CGI script), or * PHP (until PHP runs, the MIME type is set to application/x-httpd-php) */ } 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; /* We must not open the xlation table here yet, because the final MIME * type is not known until we are actually called in the output filter. * With POST or PUT request, the case is different, because their MIME * type is set in the request headers, and their data are prerequisites * for actually calling, e.g., the CGI handler later on. */ output_ctx->xlate = NULL; 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; }