You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@httpd.apache.org by GitBox <gi...@apache.org> on 2021/06/07 08:28:09 UTC

[GitHub] [httpd] jfclere opened a new pull request #193: back port the mapping=servlet to 2.4.x

jfclere opened a new pull request #193:
URL: https://github.com/apache/httpd/pull/193


   I have tried to limit the changes to mod_proxy, the PR passes the framework tests, did I miss something?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@httpd.apache.org
For additional commands, e-mail: notifications-help@httpd.apache.org


[GitHub] [httpd] jfclere commented on pull request #193: back port the mapping=servlet to 2.4.x

Posted by GitBox <gi...@apache.org>.
jfclere commented on pull request #193:
URL: https://github.com/apache/httpd/pull/193#issuecomment-856467068


   On 07/06/2021 19:47, ylavic wrote:
   > This seems to be missing some changes in ap_process_request_internal(), 
   > the commits to be backported would be:
   > 
   >   * r1879074 ***@***.***
   >     ***@***.***>)
   >   * r1879075 ***@***.***
   >     ***@***.***>)
   >   * r1879076 ***@***.***
   >     ***@***.***>)
   >   * r1879077 ***@***.***
   >     ***@***.***>)
   >   * r1879078 ***@***.***
   >     ***@***.***>)
   >   * r1879079 ***@***.***
   >     ***@***.***>)
   >   * r1879080 ***@***.***
   >     ***@***.***>)
   >   * r1879094 ***@***.***
   >     ***@***.***>)
   >   * r1879095 ***@***.***
   >     ***@***.***>)
   >   * r1879110 ***@***.***
   >     ***@***.***>)
   >   * r1879111 ***@***.***
   >     ***@***.***>)
   >   * r1879112 ***@***.***
   >     ***@***.***>)
   >   * r1879114 ***@***.***
   >     ***@***.***>)
   >   * r1879116 ***@***.***
   >     ***@***.***>)
   >   * r1879117 ***@***.***
   >     ***@***.***>)
   >   * r1879137 ***@***.***
   >     ***@***.***>)
   >   * r1879144 ***@***.***
   >     ***@***.***>)
   >   * r1879145 ***@***.***
   >     ***@***.***>)
   >   * r1879147 ***@***.***
   >     ***@***.***>)
   >   * r1879149 ***@***.***
   >     ***@***.***>)
   >   * r1879235 ***@***.***
   >     ***@***.***>)
   >   * r1879360 ***@***.***
   >     ***@***.***>)
   > 
   > The above includes all the changes, not only mod_proxy's, but if we go 
   > for this backport I think that they all matter.
   
   OK I will do another try not limited to mod_proxy. Thnaks for the review.
   
   > 
   > The full patch would be:
   > 
   > |Index: docs/manual/developer/modguide.xml 
   > =================================================================== --- 
   > docs/manual/developer/modguide.xml (revision 1890572) +++ 
   > docs/manual/developer/modguide.xml (working copy) @@ -237,6 +237,7 @@ 
   > can create. Some other ways of hooking are: 
   > <li><code>ap_hook_child_init</code>: Place a hook that executes when a 
   > child process is spawned (commonly used for initializing modules after 
   > the server has forked)</li> <li><code>ap_hook_pre_config</code>: Place a 
   > hook that executes before any configuration data has been read (very 
   > early hook)</li> <li><code>ap_hook_post_config</code>: Place a hook that 
   > executes after configuration has been parsed, but before the server has 
   > forked</li> +<li><code>ap_hook_pre_translate_name</code>: Place a hook 
   > that executes when a URI needs to be translated into a filename on the 
   > server, before decoding</li> <li><code>ap_hook_translate_name</code>: 
   > Place a hook that executes when a URI needs to be translated into a 
   > filename on the server (think <code>mod_rewrite</code>)</li> 
   > <li><code>ap_hook_quick_handler</code>: Similar to 
   > <code>ap_hook_handler</code>, except it is run before any other request 
   > hooks (translation, auth, fixups etc)</li> 
   > <li><code>ap_hook_log_transaction</code>: Place a hook that executes 
   > when the server is about to add a log entry of the current request</li> 
   > Index: docs/manual/mod/mod_log_debug.xml 
   > =================================================================== --- 
   > docs/manual/mod/mod_log_debug.xml (revision 1890572) +++ 
   > docs/manual/mod/mod_log_debug.xml (working copy) @@ -103,6 +103,7 @@ 
   > <table border="1" style="zebra"> <columnspec><column 
   > width="1"/></columnspec> <tr><th>Name</th></tr> + 
   > <tr><td><code>pre_translate_name</code></td></tr> 
   > <tr><td><code>translate_name</code></td></tr> 
   > <tr><td><code>type_checker</code></td></tr> 
   > <tr><td><code>quick_handler</code></td></tr> Index: 
   > docs/manual/mod/mod_lua.xml 
   > =================================================================== --- 
   > docs/manual/mod/mod_lua.xml (revision 1890572) +++ 
   > docs/manual/mod/mod_lua.xml (working copy) @@ -216,6 +216,13 @@ 
   > performing access control, or setting mime types:< been mapped to a host 
   > or virtual host</td> </tr> <tr> + <td>Pre-Translate name</td> + 
   > <td><directive module="mod_lua">LuaHookPreTranslateName</directive></td> 
   > + <td>This phase translates the requested URI into a filename on the + 
   > system, before decoding occurs. Modules such as 
   > <module>mod_proxy</module> + can operate in this phase.</td> + </tr> + 
   > <tr> <td>Translate name</td> <td><directive 
   > module="mod_lua">LuaHookTranslateName</directive></td> <td>This phase 
   > translates the requested URI into a filename on the @@ -438,8 +445,8 @@ 
   > end <td><code>filename</code></td> <td>string</td> <td>yes</td> - 
   > <td>The file name that the request maps to, f.x. 
   > /www/example.com/foo.txt. This can be - changed in the translate-name or 
   > map-to-storage phases of a request to allow the + <td>The file name that 
   > the request maps to, f.x. /www/example.com/foo.txt. This can be + 
   > changed in the pre-translate-name, translate-name or map-to-storage 
   > phases of a request to allow the default handler (or script handlers) to 
   > serve a different file than what was requested.</td> </tr> <tr> @@ 
   > -538,7 +545,7 @@ end <td>string</td> <td>yes</td> <td>Denotes whether 
   > this is a proxy request or not. This value is generally set in - the 
   > post_read_request/translate_name phase of a request.</td> + the 
   > post_read_request/pre_translate_name/translate_name phase of a 
   > request.</td> </tr> <tr> <td><code>range</code></td> @@ -1495,6 +1502,23 
   > @@ end </directivesynopsis> <directivesynopsis> 
   > +<name>LuaHookPreTranslate</name> +<description>Provide a hook for the 
   > pre_translate phase of a request +processing</description> 
   > +<syntax>LuaHookPreTranslate /path/to/lua/script.lua 
   > hook_function_name</syntax> +<contextlist><context>server 
   > config</context><context>virtual host</context> 
   > +<context>directory</context><context>.htaccess</context> 
   > +</contextlist> +<override>All</override> +<usage> +<p> + Just like 
   > LuaHookTranslateName, but executed at the pre_translate phase, + where 
   > the URI-path is not percent decoded. +</p> +</usage> 
   > +</directivesynopsis> + +<directivesynopsis> <name>LuaHookFixups</name> 
   > <description>Provide a hook for the fixups phase of a request 
   > processing</description> Index: include/ap_mmn.h 
   > =================================================================== --- 
   > include/ap_mmn.h (revision 1890572) +++ include/ap_mmn.h (working copy) 
   > @@ -562,6 +562,10 @@ * 20120211.106 (2.4.49-dev) Add 
   > ap_create_request(). * 20120211.107 (2.4.49-dev) Add 
   > ap_parse_request_line() and * ap_check_request_header() + * 20120211.108 
   > (2.4.49-dev) Add ap_normalize_path() + * 20120211.109 (2.4.49-dev) Add 
   > pre_translate_name hook + * 20120211.110 (2.4.49-dev) Add 
   > map_encoded_one and map_encoded_all bits to + * proxy_server_conf */ 
   > #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -569,7 +573,7 
   > @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 
   > 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 107 /* 0...n */ 
   > +#define MODULE_MAGIC_NUMBER_MINOR 110 /* 0...n */ /** * Determine if 
   > the server's current MODULE_MAGIC_NUMBER is at least a Index: 
   > include/http_request.h 
   > =================================================================== --- 
   > include/http_request.h (revision 1890572) +++ include/http_request.h 
   > (working copy) @@ -364,6 +364,18 @@ 
   > AP_DECLARE_HOOK(int,create_request,(request_rec *r /** * This hook allow 
   > modules an opportunity to translate the URI into an + * actual filename, 
   > before URL decoding happens. + * @param r The current request + * 
   > @return DECLINED to let other modules handle the pre-translation, + * OK 
   > if it was handled and no other module should process it, + * DONE if no 
   > further transformation should happen on the URI, + * HTTP_... in case of 
   > error. + * @ingroup hooks + */ 
   > +AP_DECLARE_HOOK(int,pre_translate_name,(request_rec *r)) + +/** + * 
   > This hook allow modules an opportunity to translate the URI into an * 
   > actual filename. If no modules do anything special, the server's default 
   > * rules will be followed. * @param r The current request Index: 
   > include/httpd.h 
   > =================================================================== --- 
   > include/httpd.h (revision 1890572) +++ include/httpd.h (working copy) @@ 
   > -1762,7 +1762,22 @@ AP_DECLARE(void) ap_no2slash(char *name); */ 
   > AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path); +#define 
   > AP_NORMALIZE_ALLOW_RELATIVE (1u << 0) +#define 
   > AP_NORMALIZE_NOT_ABOVE_ROOT (1u << 1) +#define 
   > AP_NORMALIZE_DECODE_UNRESERVED (1u << 2) +#define 
   > AP_NORMALIZE_MERGE_SLASHES (1u << 3) +#define 
   > AP_NORMALIZE_DROP_PARAMETERS (1u << 4) + /** + * Remove all ////, /./ 
   > and /xx/../ substrings from a path, and more + * depending on passed in 
   > flags. + * @param path The path to normalize + * @param flags bitmask of 
   > AP_NORMALIZE_* flags + * @return non-zero on success + */ 
   > +AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags); + 
   > +/** * Remove all ./ and xx/../ substrings from a file name. Also remove 
   > * any leading ../ or /../ substrings. * @param name the file name to 
   > parse Index: modules/dav/main/util.c 
   > =================================================================== --- 
   > modules/dav/main/util.c (revision 1890572) +++ modules/dav/main/util.c 
   > (working copy) @@ -664,7 +664,13 @@ static dav_error * 
   > dav_process_if_header(request_r /* note that parsed_uri.path is 
   > allocated; we can trash it */ /* clean up the URI a bit */ - 
   > ap_getparents(parsed_uri.path); + if 
   > (!ap_normalize_path(parsed_uri.path, + AP_NORMALIZE_NOT_ABOVE_ROOT | + 
   > AP_NORMALIZE_DECODE_UNRESERVED)) { + return dav_new_error(r->pool, 
   > HTTP_BAD_REQUEST, + DAV_ERR_IF_TAGGED, rv, + "Invalid URI path tagged 
   > If-header."); + } /* the resources we will compare to have unencoded 
   > paths */ if (ap_unescape_url(parsed_uri.path) != OK) { Index: 
   > modules/examples/mod_example_hooks.c 
   > =================================================================== --- 
   > modules/examples/mod_example_hooks.c (revision 1890572) +++ 
   > modules/examples/mod_example_hooks.c (working copy) @@ -1175,6 +1175,22 
   > @@ static int x_post_read_request(request_rec *r) /* * This routine 
   > gives our module an opportunity to translate the URI into an + * actual 
   > filename, before URL decoding happens. + * + * This is a RUN_FIRST hook. 
   > + */ +static int x_pre_translate_name(request_rec *r) +{ + /* + * We 
   > don't actually *do* anything here, except note the fact that we were + * 
   > called. + */ + trace_request(r, "x_pre_translate_name()"); + return 
   > DECLINED; +} + +/* + * This routine gives our module an opportunity to 
   > translate the URI into an * actual filename. If we don't do anything 
   > special, the server's default * rules (Alias directives and the like) 
   > will continue to be followed. * @@ -1467,6 +1483,7 @@ static void 
   > x_register_hooks(apr_pool_t *p) 
   > ap_hook_log_transaction(x_log_transaction, NULL, NULL, APR_HOOK_MIDDLE); 
   > ap_hook_http_scheme(x_http_scheme, NULL, NULL, APR_HOOK_MIDDLE); 
   > ap_hook_default_port(x_default_port, NULL, NULL, APR_HOOK_MIDDLE); + 
   > ap_hook_pre_translate_name(x_pre_translate_name, NULL, NULL, 
   > APR_HOOK_MIDDLE); ap_hook_translate_name(x_translate_name, NULL, NULL, 
   > APR_HOOK_MIDDLE); ap_hook_map_to_storage(x_map_to_storage, NULL,NULL, 
   > APR_HOOK_MIDDLE); ap_hook_header_parser(x_header_parser, NULL, NULL, 
   > APR_HOOK_MIDDLE); Index: modules/generators/mod_autoindex.c 
   > =================================================================== --- 
   > modules/generators/mod_autoindex.c (revision 1890572) +++ 
   > modules/generators/mod_autoindex.c (working copy) @@ -1266,8 +1266,9 @@ 
   > static struct ent *make_parent_entry(apr_int32_t a if (!(p->name = 
   > ap_make_full_path(r->pool, r->uri, "../"))) { return (NULL); } - 
   > ap_getparents(p->name); - if (!*p->name) { + if 
   > (!ap_normalize_path(p->name, AP_NORMALIZE_ALLOW_RELATIVE | + 
   > AP_NORMALIZE_NOT_ABOVE_ROOT) + || p->name[0] == '\0') { return (NULL); } 
   > Index: modules/generators/mod_info.c 
   > =================================================================== --- 
   > modules/generators/mod_info.c (revision 1890572) +++ 
   > modules/generators/mod_info.c (working copy) @@ -322,6 +322,7 @@ static 
   > const hook_lookup_t request_hooks[] = { {"HTTP Scheme", 
   > ap_hook_get_http_scheme}, {"Default Port", ap_hook_get_default_port}, 
   > {"Quick Handler", ap_hook_get_quick_handler}, + {"Pre-Translate Name", 
   > ap_hook_get_pre_translate_name}, {"Translate Name", 
   > ap_hook_get_translate_name}, {"Map to Storage", 
   > ap_hook_get_map_to_storage}, {"Check Access", 
   > ap_hook_get_access_checker_ex}, Index: modules/loggers/mod_log_debug.c 
   > =================================================================== --- 
   > modules/loggers/mod_log_debug.c (revision 1890572) +++ 
   > modules/loggers/mod_log_debug.c (working copy) @@ -49,6 +49,7 @@ static 
   > const char * const hooks[] = { "check_authn", /* 9 */ "check_authz", /* 
   > 10 */ "insert_filter", /* 11 */ + "pre_translate_name", /* 12 */ NULL }; 
   > @@ -109,6 +110,12 @@ static int log_debug_handler(request_rec *r) return 
   > DECLINED; } +static int log_debug_pre_translate_name(request_rec *r) +{ 
   > + do_debug_log(r, hooks[12]); + return DECLINED; +} + static int 
   > log_debug_translate_name(request_rec *r) { do_debug_log(r, hooks[3]); @@ 
   > -263,6 +270,7 @@ static void register_hooks(apr_pool_t *p) 
   > ap_hook_log_transaction(log_debug_log_transaction, NULL, NULL, 
   > APR_HOOK_FIRST); ap_hook_quick_handler(log_debug_quick_handler, NULL, 
   > NULL, APR_HOOK_FIRST); ap_hook_handler(log_debug_handler, NULL, NULL, 
   > APR_HOOK_FIRST); + 
   > ap_hook_pre_translate_name(log_debug_pre_translate_name, NULL, NULL, 
   > APR_HOOK_FIRST); ap_hook_translate_name(log_debug_translate_name, NULL, 
   > NULL, APR_HOOK_FIRST); ap_hook_map_to_storage(log_debug_map_to_storage, 
   > NULL, NULL, APR_HOOK_FIRST); ap_hook_fixups(log_debug_fixups, NULL, 
   > NULL, APR_HOOK_FIRST); Index: modules/lua/mod_lua.c 
   > =================================================================== --- 
   > modules/lua/mod_lua.c (revision 1890572) +++ modules/lua/mod_lua.c 
   > (working copy) @@ -1202,6 +1202,11 @@ static int 
   > lua_check_user_id_harness_last(request_ } */ +static int 
   > lua_pre_trans_name_harness(request_rec *r) +{ + return 
   > lua_request_rec_hook_harness(r, "pre_translate_name", APR_HOOK_MIDDLE); 
   > +} + static int lua_translate_name_harness_first(request_rec *r) { 
   > return lua_request_rec_hook_harness(r, "translate_name", 
   > AP_LUA_HOOK_FIRST); @@ -1274,6 +1279,21 @@ static int 
   > lua_quick_harness(request_rec *r, int l return 
   > lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE); } +static 
   > const char *register_pre_trans_name_hook(cmd_parms *cmd, void *_cfg, + 
   > const char *file, + const char *function) +{ + return 
   > register_named_file_function_hook("pre_translate_name", cmd, _cfg, file, 
   > + function, APR_HOOK_MIDDLE); +} + +static const char 
   > *register_pre_trans_name_block(cmd_parms *cmd, void *_cfg, + const char 
   > *line) +{ + return 
   > register_named_block_function_hook("pre_translate_name", cmd, _cfg, + 
   > line); +} + static const char *register_translate_name_hook(cmd_parms 
   > *cmd, void *_cfg, const char *file, const char *function, @@ -1842,6 
   > +1862,14 @@ static const command_rec lua_commands[] = { 
   > AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, 
   > RSRC_CONF|EXEC_ON_READ, "Provide an authorization provider"), + 
   > AP_INIT_TAKE2("LuaHookPreTranslateName", register_pre_trans_name_hook, 
   > NULL, + OR_ALL, + "Provide a hook for the pre_translate name phase of 
   > request processing"), + + AP_INIT_RAW_ARGS("<LuaHookPreTranslateName", 
   > register_pre_trans_name_block, NULL, + EXEC_ON_READ | OR_ALL, + "Provide 
   > a hook for the pre_translate name phase of request processing"), + 
   > AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, 
   > NULL, OR_ALL, "Provide a hook for the translate name phase of request 
   > processing"), @@ -2092,6 +2120,9 @@ static void 
   > lua_register_hooks(apr_pool_t *p) APR_HOOK_MIDDLE); /* http_request.h 
   > hooks */ + ap_hook_pre_translate_name(lua_pre_trans_name_harness, NULL, 
   > NULL, + APR_HOOK_MIDDLE); + 
   > ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL, 
   > AP_LUA_HOOK_FIRST); ap_hook_translate_name(lua_translate_name_harness, 
   > NULL, NULL, Index: modules/proxy/mod_proxy.c 
   > =================================================================== --- 
   > modules/proxy/mod_proxy.c (revision 1890572) +++ 
   > modules/proxy/mod_proxy.c (working copy) @@ -17,6 +17,7 @@ #include 
   > "mod_proxy.h" #include "mod_core.h" #include "apr_optional.h" +#include 
   > "apr_strings.h" #include "scoreboard.h" #include "mod_status.h" #include 
   > "proxy_util.h" @@ -560,6 +561,201 @@ static int alias_match(const char 
   > *uri, const char return urip - uri; } +/* + * Inspired by mod_jk's 
   > jk_servlet_normalize(). + */ +static int alias_match_servlet(apr_pool_t 
   > *p, + const char **urip, + const char *alias) +{ + char *map; + const 
   > char *uri = *urip; + apr_array_header_t *stack; + int map_pos, uri_pos, 
   > alias_pos, first_pos; + int alias_depth = 0, depth; + + /* Both uri and 
   > alias should start with '/' */ + if (uri[0] != '/' || alias[0] != '/') { 
   > + return 0; + } + + stack = apr_array_make(p, 5, sizeof(int)); + map = 
   > apr_palloc(p, strlen(uri) + 1); + map[0] = '/'; + map[1] = '\0'; + + 
   > map_pos = uri_pos = alias_pos = first_pos = 1; + while (uri[uri_pos] != 
   > '\0') { + /* Remove path parameters ;foo=bar/ from any path segment */ + 
   > if (uri[uri_pos] == ';') { + do { + uri_pos++; + } while (uri[uri_pos] 
   > != '/' && uri[uri_pos] != '\0'); + continue; + } + + if (map[map_pos - 
   > 1] == '/') { + /* Collapse ///// sequences to / */ + if (uri[uri_pos] == 
   > '/') { + do { + uri_pos++; + } while (uri[uri_pos] == '/'); + continue; 
   > + } + + if (uri[uri_pos] == '.') { + /* Remove /./ segments */ + if 
   > (uri[uri_pos + 1] == '/' + || uri[uri_pos + 1] == ';' + || uri[uri_pos + 
   > 1] == '\0') { + uri_pos++; + if (uri[uri_pos] == '/') { + uri_pos++; + } 
   > + continue; + } + + /* Remove /xx/../ segments */ + if (uri[uri_pos + 1] 
   > == '.' + && (uri[uri_pos + 2] == '/' + || uri[uri_pos + 2] == ';' + || 
   > uri[uri_pos + 2] == '\0')) { + /* Wind map segment back the previous one 
   > */ + if (map_pos == 1) { + /* Above root */ + return 0; + } + do { + 
   > map_pos--; + } while (map[map_pos - 1] != '/'); + map[map_pos] = '\0'; + 
   > + /* Wind alias segment back, unless in deeper segment */ + if 
   > (alias_depth == stack->nelts) { + if (alias[alias_pos] == '\0') { + 
   > alias_pos--; + } + while (alias_pos > 0 && alias[alias_pos] == '/') { + 
   > alias_pos--; + } + while (alias_pos > 0 && alias[alias_pos - 1] != '/') 
   > { + alias_pos--; + } + AP_DEBUG_ASSERT(alias_pos > 0); + alias_depth--; 
   > + } + apr_array_pop(stack); + + /* Move uri forward to the next segment 
   > */ + uri_pos += 2; + if (uri[uri_pos] == '/') { + uri_pos++; + } + 
   > first_pos = 0; + continue; + } + } + if (first_pos) { + while 
   > (uri[first_pos] == '/') { + first_pos++; + } + } + + /* New segment */ + 
   > APR_ARRAY_PUSH(stack, int) = first_pos ? first_pos : uri_pos; + if 
   > (alias[alias_pos] != '\0') { + if (alias[alias_pos - 1] != '/') { + /* 
   > Remain in pair with uri segments */ + do { + alias_pos++; + } while 
   > (alias[alias_pos - 1] != '/' && alias[alias_pos]); + } + while 
   > (alias[alias_pos] == '/') { + alias_pos++; + } + if (alias[alias_pos] != 
   > '\0') { + alias_depth++; + } + } + } + + if (alias[alias_pos] != '\0') { 
   > + int *match = &APR_ARRAY_IDX(stack, alias_depth - 1, int); + if 
   > (*match) { + if (alias[alias_pos] != uri[uri_pos]) { + /* Current 
   > segment does not match */ + *match = 0; + } + else if (alias[alias_pos + 
   > 1] == '\0' + && alias[alias_pos] != '/') { + if (uri[uri_pos + 1] == 
   > ';') { + /* We'll preserve the parameters of the last + * segment if it 
   > does not end with '/', so mark + * the match as negative for below 
   > handling. + */ + *match = -(uri_pos + 1); + } + else if (uri[uri_pos + 
   > 1] != '/' + && uri[uri_pos + 1] != '\0') { + /* Last segment does not 
   > match all the way */ + *match = 0; + } + } + } + /* Don't go past the 
   > segment if the uri isn't there yet */ + if (alias[alias_pos] != '/' || 
   > uri[uri_pos] == '/') { + alias_pos++; + } + } + + if (uri[uri_pos] == 
   > '/') { + first_pos = uri_pos + 1; + } + map[map_pos++] = uri[uri_pos++]; 
   > + map[map_pos] = '\0'; + } + + /* Can't reach the end of uri before the 
   > end of the alias, + * for example if uri is "/" and alias is "/examples" 
   > + */ + if (alias[alias_pos] != '\0') { + return 0; + } + + /* Check 
   > whether each alias segment matched */ + for (depth = 0; depth < 
   > alias_depth; ++depth) { + if (!APR_ARRAY_IDX(stack, depth, int)) { + 
   > return 0; + } + } + + /* If alias_depth == stack->nelts we have a full 
   > match, i.e. + * uri == alias so we can return uri_pos as is (the end of 
   > uri) + */ + if (alias_depth < stack->nelts) { + /* Return the segment 
   > following the alias */ + uri_pos = APR_ARRAY_IDX(stack, alias_depth, 
   > int); + if (alias_depth) { + /* But if the last segment of the alias 
   > does not end with '/' + * and the corresponding segment of the uri has 
   > parameters, + * we want to forward those parameters (see above for the + 
   > * negative pos trick/mark). + */ + int pos = APR_ARRAY_IDX(stack, 
   > alias_depth - 1, int); + if (pos < 0) { + uri_pos = -pos; + } + } + } + 
   > /* If the alias lacks a trailing slash, take it from the uri (if any) */ 
   > + if (alias[alias_pos - 1] != '/' && uri[uri_pos - 1] == '/') { + 
   > uri_pos--; + } + + *urip = map; + return uri_pos; +} + /* Detect if an 
   > absoluteURI should be proxied or not. Note that we * have to do this 
   > during this phase because later phases are * "short-circuiting"... i.e. 
   > translate_names will end when the first @@ -670,6 +866,7 @@ 
   > PROXY_DECLARE(int) ap_proxy_trans_match(request_re int mismatch = 0; 
   > unsigned int nocanon = ent->flags & PROXYPASS_NOCANON; const char 
   > *use_uri = nocanon ? r->unparsed_uri : r->uri; + const char *servlet_uri 
   > = NULL; if (dconf && (dconf->interpolate_env == 1) && (ent->flags & 
   > PROXYPASS_INTERPOLATE)) { fake = proxy_interpolate(r, ent->fake); @@ 
   > -730,7 +927,14 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re } } 
   > else { - len = alias_match(r->uri, fake); + if ((ent->flags & 
   > PROXYPASS_MAP_SERVLET) == PROXYPASS_MAP_SERVLET) { + servlet_uri = 
   > r->uri; + len = alias_match_servlet(r->pool, &servlet_uri, fake); + 
   > nocanon = 0; /* ignored since servlet's normalization applies */ + } + 
   > else { + len = alias_match(r->uri, fake); + } if (len != 0) { if 
   > ((real[0] == '!') && (real[1] == '\0')) { @@ -761,7 +965,7 @@ 
   > PROXY_DECLARE(int) ap_proxy_trans_match(request_re */ int rc = 
   > proxy_run_check_trans(r, found + 6); if (rc != OK && rc != DECLINED) { - 
   > return DONE; + return HTTP_CONTINUE; } r->filename = found; @@ -775,19 
   > +979,33 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re 
   > apr_table_setn(r->notes, "proxy-noquery", "1"); } + if (servlet_uri) { + 
   > ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(10248) + "Servlet 
   > path '%s' (%s) matches proxy handler '%s'", + r->uri, servlet_uri, 
   > found); + /* Apply servlet normalization to r->uri so that <Location> or 
   > any + * directory context match does not have to handle path parameters. 
   > + * We change r->uri in-place so that r->parsed_uri.path is updated + * 
   > too. Since normalized servlet_uri is necessarily shorter than + * the 
   > original r->uri, strcpy() is fine. + */ + AP_DEBUG_ASSERT(strlen(r->uri) 
   >  >= strlen(servlet_uri)); + strcpy(r->uri, servlet_uri); + return DONE; 
   > + } + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03464) "URI 
   > path '%s' matches proxy handler '%s'", r->uri, found); - return OK; } - 
   > return DONE; + return HTTP_CONTINUE; } -static int 
   > proxy_trans(request_rec *r) +static int proxy_trans(request_rec *r, int 
   > pre_trans) { - int i; + int i, enc; struct proxy_alias *ent; 
   > proxy_dir_conf *dconf; proxy_server_conf *conf; @@ -794,11 +1012,32 @@ 
   > PROXY_DECLARE(int) ap_proxy_trans_match(request_re if (r->proxyreq) { /* 
   > someone has already set up the proxy, it was possibly ourselves - * in 
   > proxy_detect + * in proxy_detect (DONE will prevent further decoding of 
   > r->uri, + * only if proxyreq is set before pre_trans already). */ - 
   > return OK; + return pre_trans ? DONE : OK; } + /* In early pre_trans 
   > hook, r->uri was not manipulated yet so we are + * compliant with 
   > RFC1945 at this point. Otherwise, it probably isn't + * an issue because 
   > this is a hybrid proxy/origin server. + */ + + dconf = 
   > ap_get_module_config(r->per_dir_config, &proxy_module); + conf = 
   > (proxy_server_conf *) ap_get_module_config(r->server->module_config, + 
   > &proxy_module); + + /* Always and only do PROXY_MAP_ENCODED mapping in 
   > pre_trans, when + * r->uri is still encoded, or we might consider for 
   > instance that + * a decoded sub-delim is now a delimiter (e.g. "%3B" => 
   > ';' for + * path parameters), which it's not. + */ + if ((pre_trans && 
   > !conf->map_encoded_one) + || (!pre_trans && conf->map_encoded_all)) { + 
   > /* Fast path, nothing at this stage */ + return DECLINED; + } + if 
   > ((r->unparsed_uri[0] == '*' && r->unparsed_uri[1] == '\0') || !r->uri || 
   > r->uri[0] != '/') { return DECLINED; @@ -808,37 +1047,42 @@ 
   > PROXY_DECLARE(int) ap_proxy_trans_match(request_re return DECLINED; } - 
   > /* XXX: since r->uri has been manipulated already we're not really - * 
   > compliant with RFC1945 at this point. But this probably isn't - * an 
   > issue because this is a hybrid proxy/origin server. - */ - - dconf = 
   > ap_get_module_config(r->per_dir_config, &proxy_module); - /* short way - 
   > this location is reverse proxied? */ if (dconf->alias) { - int rv = 
   > ap_proxy_trans_match(r, dconf->alias, dconf); - if (DONE != rv) { - 
   > return rv; + enc = (dconf->alias->flags & PROXYPASS_MAP_ENCODED) != 0; + 
   > if (!(pre_trans ^ enc)) { + int rv = ap_proxy_trans_match(r, 
   > dconf->alias, dconf); + if (rv != HTTP_CONTINUE) { + return rv; + } } } 
   > - conf = (proxy_server_conf *) 
   > ap_get_module_config(r->server->module_config, - &proxy_module); - /* 
   > long way - walk the list of aliases, find a match */ - if 
   > (conf->aliases->nelts) { - ent = (struct proxy_alias *) 
   > conf->aliases->elts; - for (i = 0; i < conf->aliases->nelts; i++) { - 
   > int rv = ap_proxy_trans_match(r, &ent[i], dconf); - if (DONE != rv) { + 
   > for (i = 0; i < conf->aliases->nelts; i++) { + ent = &((struct 
   > proxy_alias *)conf->aliases->elts)[i]; + enc = (ent->flags & 
   > PROXYPASS_MAP_ENCODED) != 0; + if (!(pre_trans ^ enc)) { + int rv = 
   > ap_proxy_trans_match(r, ent, dconf); + if (rv != HTTP_CONTINUE) { return 
   > rv; } } } + return DECLINED; } +static int 
   > proxy_pre_translate_name(request_rec *r) +{ + return proxy_trans(r, 1); 
   > +} + +static int proxy_translate_name(request_rec *r) +{ + return 
   > proxy_trans(r, 0); +} + static int proxy_walk(request_rec *r) { 
   > proxy_server_conf *sconf = 
   > ap_get_module_config(r->server->module_config, @@ -1359,6 +1603,8 @@ 
   > static void * create_proxy_config(apr_pool_t *p, s ps->forward = NULL; 
   > ps->reverse = NULL; ps->domain = NULL; + ps->map_encoded_one = 0; + 
   > ps->map_encoded_all = 1; ps->id = apr_psprintf(p, "p%x", 1); /* simply 
   > for storage size */ ps->viaopt = via_off; /* initially backward 
   > compatible with 1.3.1 */ ps->viaopt_set = 0; /* 0 means default */ @@ 
   > -1516,6 +1762,9 @@ static void * merge_proxy_config(apr_pool_t *p, vo 
   > ps->forward = overrides->forward ? overrides->forward : base->forward; 
   > ps->reverse = overrides->reverse ? overrides->reverse : base->reverse; + 
   > ps->map_encoded_one = overrides->map_encoded_one || 
   > base->map_encoded_one; + ps->map_encoded_all = 
   > overrides->map_encoded_all && base->map_encoded_all; + ps->domain = 
   > (overrides->domain == NULL) ? base->domain : overrides->domain; ps->id = 
   > (overrides->id == NULL) ? base->id : overrides->id; ps->viaopt = 
   > (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt; @@ 
   > -1640,7 +1889,7 @@ static void *merge_proxy_dir_config(apr_pool_t *p, : 
   > add->forward_100_continue; new->forward_100_continue_set = 
   > add->forward_100_continue_set || base->forward_100_continue_set; - + 
   > return new; } @@ -1814,11 +2063,31 @@ static const char * "in the form 
   > 'key=value'."; } } - else + else { *val++ = '\0'; - 
   > apr_table_setn(params, word, val); + } + if (!strcasecmp(word, 
   > "mapping")) { + if (!strcasecmp(val, "encoded")) { + flags |= 
   > PROXYPASS_MAP_ENCODED; + } + else if (!strcasecmp(val, "servlet")) { + 
   > flags |= PROXYPASS_MAP_SERVLET; + } + else { + return "unknown mapping"; 
   > + } + } + else { + apr_table_setn(params, word, val); + } } - }; + } + 
   > if (flags & PROXYPASS_MAP_ENCODED) { + conf->map_encoded_one = 1; + } + 
   > else { + conf->map_encoded_all = 0; + } if (r == NULL) { return 
   > "ProxyPass|ProxyPassMatch needs a path when not defined in a location"; 
   > @@ -3142,7 +3411,10 @@ static void register_hooks(apr_pool_t *p) /* 
   > handler */ ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST); 
   > /* filename-to-URI translation */ - ap_hook_translate_name(proxy_trans, 
   > aszSucc, NULL, APR_HOOK_FIRST); + 
   > ap_hook_pre_translate_name(proxy_pre_translate_name, NULL, NULL, + 
   > APR_HOOK_MIDDLE); + ap_hook_translate_name(proxy_translate_name, 
   > aszSucc, NULL, + APR_HOOK_FIRST); /* walk <Proxy > entries and suppress 
   > default TRACE behavior */ ap_hook_map_to_storage(proxy_map_location, 
   > NULL,NULL, APR_HOOK_FIRST); /* fixups */ Index: 
   > modules/proxy/mod_proxy.h 
   > =================================================================== --- 
   > modules/proxy/mod_proxy.h (revision 1890572) +++ 
   > modules/proxy/mod_proxy.h (working copy) @@ -124,6 +124,8 @@ struct 
   > proxy_remote { #define PROXYPASS_NOCANON 0x01 #define 
   > PROXYPASS_INTERPOLATE 0x02 #define PROXYPASS_NOQUERY 0x04 +#define 
   > PROXYPASS_MAP_ENCODED 0x08 +#define PROXYPASS_MAP_SERVLET 0x18 /* + 
   > MAP_ENCODED */ struct proxy_alias { const char *real; const char *fake; 
   > @@ -200,6 +202,8 @@ typedef struct { unsigned int inherit_set:1; 
   > unsigned int ppinherit:1; unsigned int ppinherit_set:1; + unsigned int 
   > map_encoded_one:1; + unsigned int map_encoded_all:1; } 
   > proxy_server_conf; typedef struct { @@ -1171,7 +1175,11 @@ 
   > PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer * @param r request * 
   > @param ent proxy_alias record * @param dconf per-dir config or NULL - * 
   > @return DECLINED, DONE or OK if matched + * @return OK if the alias 
   > matched, + * DONE if the alias matched and r->uri was normalized so + * 
   > no further transformation should happen on it, + * DECLINED if proxying 
   > is disabled for this alias, + * HTTP_CONTINUE if the alias did not match 
   > */ PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r, struct 
   > proxy_alias *ent, Index: server/request.c 
   > =================================================================== --- 
   > server/request.c (revision 1890572) +++ server/request.c (working copy) 
   > @@ -59,6 +59,7 @@ #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX 
   > APR_HOOK_STRUCT( + APR_HOOK_LINK(pre_translate_name) 
   > APR_HOOK_LINK(translate_name) APR_HOOK_LINK(map_to_storage) 
   > APR_HOOK_LINK(check_user_id) @@ -74,6 +75,8 @@ APR_HOOK_STRUCT( 
   > APR_HOOK_LINK(force_authn) ) 
   > +AP_IMPLEMENT_HOOK_RUN_FIRST(int,pre_translate_name, + (request_rec *r), 
   > (r), DECLINED) AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name, 
   > (request_rec *r), (r), DECLINED) 
   > AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage, @@ -157,6 +160,26 @@ 
   > AP_DECLARE(int) ap_some_authn_required(request_rec return rv; } +static 
   > int walk_location_and_if(request_rec *r) +{ + int access_status; + + if 
   > ((access_status = ap_location_walk(r))) { + return access_status; + } + 
   > if ((access_status = ap_if_walk(r))) { + return access_status; + } + + { 
   > + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + 
   > if (d->log) + r->log = d->log; + } + + return OK; +} + /* This is the 
   > master logic for processing requests. Do NOT duplicate * this logic 
   > elsewhere, or the security model will be broken by future * API changes. 
   > Each phase must be individually optimized to pick up @@ -164,17 +187,65 
   > @@ AP_DECLARE(int) ap_some_authn_required(request_rec */ AP_DECLARE(int) 
   > ap_process_request_internal(request_rec *r) { + int access_status = 
   > DECLINED; int file_req = (r->main && r->filename); - int access_status; 
   > - core_dir_config *d; core_server_config *sconf = 
   > ap_get_core_module_config(r->server->module_config); + unsigned int 
   > normalize_flags; - /* Ignore embedded %2F's in path for proxy requests 
   > */ - if (!r->proxyreq && r->parsed_uri.path) { - d = 
   > ap_get_core_module_config(r->per_dir_config); + normalize_flags = 
   > AP_NORMALIZE_NOT_ABOVE_ROOT; + if (sconf->merge_slashes != 
   > AP_CORE_CONFIG_OFF) { + normalize_flags |= AP_NORMALIZE_MERGE_SLASHES; + 
   > } + if (file_req) { + /* File subrequests can have a relative path. */ + 
   > normalize_flags |= AP_NORMALIZE_ALLOW_RELATIVE; + } + + if 
   > (r->parsed_uri.path) { + /* Normalize: remove /./ and shrink /../ 
   > segments, plus + * decode unreserved chars (first time only to avoid + * 
   > double decoding after ap_unescape_url() below). + */ + if 
   > (!ap_normalize_path(r->parsed_uri.path, + normalize_flags | + 
   > AP_NORMALIZE_DECODE_UNRESERVED)) { + ap_log_rerror(APLOG_MARK, 
   > APLOG_ERR, 0, r, APLOGNO(10244) + "invalid URI path (%s)", 
   > r->unparsed_uri); + return HTTP_BAD_REQUEST; + } + } + + /* All file 
   > subrequests are a huge pain... they cannot bubble through the + * next 
   > several steps. Only file subrequests are allowed an empty uri, + * 
   > otherwise let (pre_)translate_name kill the request. + */ + if 
   > (!file_req) { + ap_conf_vector_t *per_dir_config = r->per_dir_config; + 
   > + if ((access_status = walk_location_and_if(r))) { + return 
   > access_status; + } + + /* Let pre_translate_name hooks work with 
   > non-decoded URIs, and + * eventually prevent further URI transformations 
   > (return DONE). + */ + access_status = ap_run_pre_translate_name(r); + if 
   > (ap_is_HTTP_ERROR(access_status)) { + return access_status; + } + + /* 
   > Throw away pre_trans only merging */ + r->per_dir_config = 
   > per_dir_config; + } + + /* Ignore URL unescaping for translated URIs 
   > already */ + if (access_status != DONE && r->parsed_uri.path) { + 
   > core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + if 
   > (d->allow_encoded_slashes) { - access_status = 
   > ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes); + 
   > access_status = ap_unescape_url_keep2f(r->parsed_uri.path, + 
   > d->decode_encoded_slashes); } else { access_status = 
   > ap_unescape_url(r->parsed_uri.path); @@ -183,40 +254,27 @@ 
   > AP_DECLARE(int) ap_process_request_internal(reques if (access_status == 
   > HTTP_NOT_FOUND) { if (! d->allow_encoded_slashes) { 
   > ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026) - "found %%2f 
   > (encoded '/') in URI " - "(decoded='%s'), returning 404", - 
   > r->parsed_uri.path); + "found %%2f (encoded '/') in URI path (%s), " + 
   > "returning 404", r->unparsed_uri); } } return access_status; } - } - 
   > ap_getparents(r->uri); /* OK --- shrinking transformations... */ - if 
   > (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { - ap_no2slash(r->uri); - 
   > if (r->parsed_uri.path) { - ap_no2slash(r->parsed_uri.path); + if 
   > (d->allow_encoded_slashes && d->decode_encoded_slashes) { + /* Decoding 
   > slashes might have created new // or /./ or /../ + * segments (e.g. 
   > "/.%2F/"), so re-normalize. + */ + ap_normalize_path(r->parsed_uri.path, 
   > normalize_flags); } - } + } - /* All file subrequests are a huge pain... 
   > they cannot bubble through the - * next several steps. Only file 
   > subrequests are allowed an empty uri, - * otherwise let translate_name 
   > kill the request. - */ + /* Same, translate_name is not suited for file 
   > subrequests */ if (!file_req) { - if ((access_status = 
   > ap_location_walk(r))) { + if ((access_status = walk_location_and_if(r))) 
   > { return access_status; } - if ((access_status = ap_if_walk(r))) { - 
   > return access_status; - } - d = 
   > ap_get_core_module_config(r->per_dir_config); - if (d->log) { - r->log = 
   > d->log; - } - if ((access_status = ap_run_translate_name(r))) { return 
   > decl_die(access_status, "translate", r); } @@ -233,18 +291,10 @@ 
   > AP_DECLARE(int) ap_process_request_internal(reques /* Rerun the location 
   > walk, which overrides any map_to_storage config. */ - if ((access_status 
   > = ap_location_walk(r))) { + if ((access_status = 
   > walk_location_and_if(r))) { return access_status; } - if ((access_status 
   > = ap_if_walk(r))) { - return access_status; - } - d = 
   > ap_get_core_module_config(r->per_dir_config); - if (d->log) { - r->log = 
   > d->log; - } - if ((access_status = ap_run_post_perdir_config(r))) { 
   > return access_status; } @@ -1370,7 +1420,7 @@ AP_DECLARE(int) 
   > ap_directory_walk(request_rec *r) r->canonical_filename = r->filename; 
   > if (r->finfo.filetype == APR_DIR) { - cache->cached = r->filename; + 
   > cache->cached = apr_pstrdup(r->pool, r->filename); } else { 
   > cache->cached = ap_make_dirstr_parent(r->pool, r->filename); @@ -1467,7 
   > +1517,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) apr_pool_t 
   > *rxpool = NULL; cached &= auth_internal_per_conf; - cache->cached = 
   > entry_uri; + cache->cached = apr_pstrdup(r->pool, entry_uri); /* Go 
   > through the location entries, and check for matches. * We apply the 
   > directive sections in given order, we should Index: server/util.c 
   > =================================================================== --- 
   > server/util.c (revision 1890572) +++ server/util.c (working copy) @@ 
   > -76,7 +76,7 @@ #include "test_char.h" /* Win32/NetWare/OS2 need to check 
   > for both forward and back slashes - * in ap_getparents() and 
   > ap_escape_url. + * in ap_normalize_path() and ap_escape_url(). */ #ifdef 
   > CASE_BLIND_FILESYSTEM #define IS_SLASH(s) ((s == '/') || (s == '\\')) @@ 
   > -491,75 +491,127 @@ AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t 
   > return rc; } +/* Forward declare */ +static char x2c(const char *what); 
   > + +#define IS_SLASH_OR_NUL(s) (s == '\0' || IS_SLASH(s)) + /* - * Parse 
   > .. so we don't compromise security + * Inspired by mod_jk's 
   > jk_servlet_normalize(). */ -AP_DECLARE(void) ap_getparents(char *name) 
   > +AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags) { - 
   > char *next; - int l, w, first_dot; + int ret = 1; + apr_size_t l = 1, w 
   > = 1; - /* Four paseses, as per RFC 1808 */ - /* a) remove ./ path 
   > segments */ - for (next = name; *next && (*next != '.'); next++) { - } + 
   > if (!IS_SLASH(path[0])) { + /* Besides "OPTIONS *", a request-target 
   > should start with '/' + * per RFC 7230 section 5.3, so anything else is 
   > invalid. + */ + if (path[0] == '*' && path[1] == '\0') { + return 1; + } 
   > + /* However, AP_NORMALIZE_ALLOW_RELATIVE can be used to bypass + * this 
   > restriction (e.g. for subrequest file lookups). + */ + if (!(flags & 
   > AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') { + return 0; + } - l = 
   > w = first_dot = next - name; - while (name[l] != '\0') { - if (name[l] 
   > == '.' && IS_SLASH(name[l + 1]) - && (l == 0 || IS_SLASH(name[l - 1]))) 
   > - l += 2; - else - name[w++] = name[l++]; + l = w = 0; } - /* b) remove 
   > trailing . path, segment */ - if (w == 1 && name[0] == '.') - w--; - 
   > else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2])) - w--; - 
   > name[w] = '\0'; + while (path[l] != '\0') { + /* RFC-3986 section 2.3: + 
   > * For consistency, percent-encoded octets in the ranges of + * ALPHA 
   > (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), + * period (%2E), 
   > underscore (%5F), or tilde (%7E) should [...] + * be decoded to their 
   > corresponding unreserved characters by + * URI normalizers. + */ + if 
   > ((flags & AP_NORMALIZE_DECODE_UNRESERVED) + && path[l] == '%' && 
   > apr_isxdigit(path[l + 1]) + && apr_isxdigit(path[l + 2])) { + const char 
   > c = x2c(&path[l + 1]); + if (apr_isalnum(c) || (c && strchr("-._~", c))) 
   > { + /* Replace last char and fall through as the current + * read 
   > position */ + l += 2; + path[l] = c; + } + } - /* c) remove all xx/../ 
   > segments. (including leading ../ and /../) */ - l = first_dot; + if 
   > ((flags & AP_NORMALIZE_DROP_PARAMETERS) && path[l] == ';') { + do { + 
   > l++; + } while (!IS_SLASH_OR_NUL(path[l])); + continue; + } - while 
   > (name[l] != '\0') { - if (name[l] == '.' && name[l + 1] == '.' && 
   > IS_SLASH(name[l + 2]) - && (l == 0 || IS_SLASH(name[l - 1]))) { - int m 
   > = l + 3, n; + if (w == 0 || IS_SLASH(path[w - 1])) { + /* Collapse ///// 
   > sequences to / */ + if ((flags & AP_NORMALIZE_MERGE_SLASHES) && 
   > IS_SLASH(path[l])) { + do { + l++; + } while (IS_SLASH(path[l])); + 
   > continue; + } - l = l - 2; - if (l >= 0) { - while (l >= 0 && 
   > !IS_SLASH(name[l])) - l--; - l++; + if (path[l] == '.') { + /* Remove 
   > /./ segments */ + if (IS_SLASH_OR_NUL(path[l + 1])) { + l++; + if 
   > (path[l]) { + l++; + } + continue; + } + + /* Remove /xx/../ segments */ 
   > + if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) { + /* Wind w 
   > back to remove the previous segment */ + if (w > 1) { + do { + w--; + } 
   > while (w && !IS_SLASH(path[w - 1])); + } + else { + /* Already at root, 
   > ignore and return a failure + * if asked to. + */ + if (flags & 
   > AP_NORMALIZE_NOT_ABOVE_ROOT) { + ret = 0; + } + } + + /* Move l forward 
   > to the next segment */ + l += 2; + if (path[l]) { + l++; + } + continue; 
   > + } } - else - l = 0; - n = l; - while ((name[n] = name[m])) - (++n, 
   > ++m); } - else - ++l; + + path[w++] = path[l++]; } + path[w] = '\0'; - 
   > /* d) remove trailing xx/.. segment. */ - if (l == 2 && name[0] == '.' 
   > && name[1] == '.') + return ret; +} + +/* + * Parse .. so we don't 
   > compromise security + */ +AP_DECLARE(void) ap_getparents(char *name) +{ 
   > + if (!ap_normalize_path(name, AP_NORMALIZE_NOT_ABOVE_ROOT | + 
   > AP_NORMALIZE_ALLOW_RELATIVE)) { name[0] = '\0'; - else if (l > 2 && 
   > name[l - 1] == '.' && name[l - 2] == '.' - && IS_SLASH(name[l - 3])) { - 
   > l = l - 4; - if (l >= 0) { - while (l >= 0 && !IS_SLASH(name[l])) - l--; 
   > - l++; - } - else - l = 0; - name[l] = '\0'; } } + AP_DECLARE(void) 
   > ap_no2slash_ex(char *name, int is_fs_path) { Index: . 
   > =================================================================== --- 
   > . (revision 1890572) +++ . (working copy) Property changes on: . 
   > ___________________________________________________________________ 
   > Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged 
   > /httpd/httpd/trunk:r1879074-1879080,1879094-1879095,1879110-1879112,1879114,1879116-1879117,1879137,1879144-1879145,1879147,1879149,1879235,1879360 
   > |
   > 
   > —
   > You are receiving this because you authored the thread.
   > Reply to this email directly, view it on GitHub 
   > <https://github.com/apache/httpd/pull/193#issuecomment-856137707>, or 
   > unsubscribe 
   > <https://github.com/notifications/unsubscribe-auth/AACNKB2ZZSZHGVTTPC4RJYDTRUA23ANCNFSM46HENSFQ>.
   > 
   
   
   -- 
   Cheers
   
   Jean-Frederic
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@httpd.apache.org
For additional commands, e-mail: notifications-help@httpd.apache.org


[GitHub] [httpd] jfclere closed pull request #193: back port the mapping=servlet to 2.4.x

Posted by GitBox <gi...@apache.org>.
jfclere closed pull request #193:
URL: https://github.com/apache/httpd/pull/193


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@httpd.apache.org
For additional commands, e-mail: notifications-help@httpd.apache.org


[GitHub] [httpd] ylavic commented on pull request #193: back port the mapping=servlet to 2.4.x

Posted by GitBox <gi...@apache.org>.
ylavic commented on pull request #193:
URL: https://github.com/apache/httpd/pull/193#issuecomment-856137707


   This seems to be missing some changes in ap_process_request_internal(), the commits to be backported would be:
   - r1879074 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879074)
   - r1879075 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879075)
   - r1879076 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879076)
   - r1879077 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879077)
   - r1879078 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879078)
   - r1879079 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879079)
   - r1879080 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879080)
   - r1879094 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879094)
   - r1879095 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879095)
   - r1879110 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879110)
   - r1879111 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879111)
   - r1879112 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879112)
   - r1879114 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879114)
   - r1879116 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879116)
   - r1879117 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879117)
   - r1879137 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879137)
   - r1879144 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879144)
   - r1879145 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879145)
   - r1879147 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879147)
   - r1879149 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879149)
   - r1879235 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879235)
   - r1879360 (https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879360)
   
   The above includes all the changes, not only mod_proxy's, but if we go for this backport I think that they all matter.
   
   The full patch would be:
   ```
   Index: docs/manual/developer/modguide.xml
   ===================================================================
   --- docs/manual/developer/modguide.xml	(revision 1890572)
   +++ docs/manual/developer/modguide.xml	(working copy)
   @@ -237,6 +237,7 @@ can create. Some other ways of hooking are:
    <li><code>ap_hook_child_init</code>: Place a hook that executes when a child process is spawned (commonly used for initializing modules after the server has forked)</li>
    <li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li>
    <li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li>
   +<li><code>ap_hook_pre_translate_name</code>: Place a hook that executes when a URI needs to be translated into a filename on the server, before decoding</li>
    <li><code>ap_hook_translate_name</code>: Place a hook that executes when a URI needs to be translated into a filename on the server (think <code>mod_rewrite</code>)</li>
    <li><code>ap_hook_quick_handler</code>: Similar to <code>ap_hook_handler</code>, except it is run before any other request hooks (translation, auth, fixups etc)</li>
    <li><code>ap_hook_log_transaction</code>: Place a hook that executes when the server is about to add a log entry of the current request</li>
   Index: docs/manual/mod/mod_log_debug.xml
   ===================================================================
   --- docs/manual/mod/mod_log_debug.xml	(revision 1890572)
   +++ docs/manual/mod/mod_log_debug.xml	(working copy)
   @@ -103,6 +103,7 @@
        <table border="1" style="zebra">
        <columnspec><column width="1"/></columnspec>
        <tr><th>Name</th></tr>
   +    <tr><td><code>pre_translate_name</code></td></tr>
        <tr><td><code>translate_name</code></td></tr>
        <tr><td><code>type_checker</code></td></tr>
        <tr><td><code>quick_handler</code></td></tr>
   Index: docs/manual/mod/mod_lua.xml
   ===================================================================
   --- docs/manual/mod/mod_lua.xml	(revision 1890572)
   +++ docs/manual/mod/mod_lua.xml	(working copy)
   @@ -216,6 +216,13 @@ performing access control, or setting mime types:<
                been mapped to a host or virtual host</td>
        </tr>
        <tr>
   +        <td>Pre-Translate name</td>
   +        <td><directive module="mod_lua">LuaHookPreTranslateName</directive></td>
   +        <td>This phase translates the requested URI into a filename on the
   +            system, before decoding occurs. Modules such as <module>mod_proxy</module>
   +            can operate in this phase.</td>
   +    </tr>
   +    <tr>
            <td>Translate name</td>
            <td><directive module="mod_lua">LuaHookTranslateName</directive></td>
            <td>This phase translates the requested URI into a filename on the 
   @@ -438,8 +445,8 @@ end
              <td><code>filename</code></td>
              <td>string</td>
              <td>yes</td>
   -          <td>The file name that the request maps to, f.x. /www/example.com/foo.txt. This can be 
   -            changed in the translate-name or map-to-storage phases of a request to allow the 
   +          <td>The file name that the request maps to, f.x. /www/example.com/foo.txt. This can be
   +            changed in the pre-translate-name, translate-name or map-to-storage phases of a request to allow the
                default handler (or script handlers) to serve a different file than what was requested.</td>
            </tr>
            <tr>
   @@ -538,7 +545,7 @@ end
              <td>string</td>
              <td>yes</td>
              <td>Denotes whether this is a proxy request or not. This value is generally set in 
   -            the post_read_request/translate_name phase of a request.</td>
   +              the post_read_request/pre_translate_name/translate_name phase of a request.</td>
            </tr>
            <tr>
              <td><code>range</code></td>
   @@ -1495,6 +1502,23 @@ end
    </directivesynopsis>
    
    <directivesynopsis>
   +<name>LuaHookPreTranslate</name>
   +<description>Provide a hook for the pre_translate phase of a request
   +processing</description>
   +<syntax>LuaHookPreTranslate  /path/to/lua/script.lua hook_function_name</syntax>
   +<contextlist><context>server config</context><context>virtual host</context>
   +<context>directory</context><context>.htaccess</context>
   +</contextlist>
   +<override>All</override>
   +<usage>
   +<p>
   +    Just like LuaHookTranslateName, but executed at the pre_translate phase,
   +    where the URI-path is not percent decoded.
   +</p>
   +</usage>
   +</directivesynopsis>
   +
   +<directivesynopsis>
    <name>LuaHookFixups</name>
    <description>Provide a hook for the fixups phase of a request
    processing</description>
   Index: include/ap_mmn.h
   ===================================================================
   --- include/ap_mmn.h	(revision 1890572)
   +++ include/ap_mmn.h	(working copy)
   @@ -562,6 +562,10 @@
     * 20120211.106 (2.4.49-dev) Add ap_create_request().
     * 20120211.107 (2.4.49-dev) Add ap_parse_request_line() and
     *                           ap_check_request_header()
   + * 20120211.108 (2.4.49-dev) Add ap_normalize_path()
   + * 20120211.109 (2.4.49-dev) Add pre_translate_name hook
   + * 20120211.110 (2.4.49-dev) Add map_encoded_one and map_encoded_all bits to
   + *                           proxy_server_conf
     */
    
    #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
   @@ -569,7 +573,7 @@
    #ifndef MODULE_MAGIC_NUMBER_MAJOR
    #define MODULE_MAGIC_NUMBER_MAJOR 20120211
    #endif
   -#define MODULE_MAGIC_NUMBER_MINOR 107                 /* 0...n */
   +#define MODULE_MAGIC_NUMBER_MINOR 110                 /* 0...n */
    
    /**
     * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
   Index: include/http_request.h
   ===================================================================
   --- include/http_request.h	(revision 1890572)
   +++ include/http_request.h	(working copy)
   @@ -364,6 +364,18 @@ AP_DECLARE_HOOK(int,create_request,(request_rec *r
    
    /**
     * This hook allow modules an opportunity to translate the URI into an
   + * actual filename, before URL decoding happens.
   + * @param r The current request
   + * @return DECLINED to let other modules handle the pre-translation,
   + *         OK if it was handled and no other module should process it,
   + *         DONE if no further transformation should happen on the URI,
   + *         HTTP_... in case of error.
   + * @ingroup hooks
   + */
   +AP_DECLARE_HOOK(int,pre_translate_name,(request_rec *r))
   +
   +/**
   + * This hook allow modules an opportunity to translate the URI into an
     * actual filename.  If no modules do anything special, the server's default
     * rules will be followed.
     * @param r The current request
   Index: include/httpd.h
   ===================================================================
   --- include/httpd.h	(revision 1890572)
   +++ include/httpd.h	(working copy)
   @@ -1762,7 +1762,22 @@ AP_DECLARE(void) ap_no2slash(char *name);
     */
    AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path);
    
   +#define AP_NORMALIZE_ALLOW_RELATIVE     (1u <<  0)
   +#define AP_NORMALIZE_NOT_ABOVE_ROOT     (1u <<  1)
   +#define AP_NORMALIZE_DECODE_UNRESERVED  (1u <<  2)
   +#define AP_NORMALIZE_MERGE_SLASHES      (1u <<  3)
   +#define AP_NORMALIZE_DROP_PARAMETERS    (1u <<  4)
   +
    /**
   + * Remove all ////, /./ and /xx/../ substrings from a path, and more
   + * depending on passed in flags.
   + * @param path The path to normalize
   + * @param flags bitmask of AP_NORMALIZE_* flags
   + * @return non-zero on success
   + */
   +AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags);
   +
   +/**
     * Remove all ./ and xx/../ substrings from a file name. Also remove
     * any leading ../ or /../ substrings.
     * @param name the file name to parse
   Index: modules/dav/main/util.c
   ===================================================================
   --- modules/dav/main/util.c	(revision 1890572)
   +++ modules/dav/main/util.c	(working copy)
   @@ -664,7 +664,13 @@ static dav_error * dav_process_if_header(request_r
                /* note that parsed_uri.path is allocated; we can trash it */
    
                /* clean up the URI a bit */
   -            ap_getparents(parsed_uri.path);
   +            if (!ap_normalize_path(parsed_uri.path,
   +                                   AP_NORMALIZE_NOT_ABOVE_ROOT |
   +                                   AP_NORMALIZE_DECODE_UNRESERVED)) {
   +                return dav_new_error(r->pool, HTTP_BAD_REQUEST,
   +                                     DAV_ERR_IF_TAGGED, rv,
   +                                     "Invalid URI path tagged If-header.");
   +            }
    
                /* the resources we will compare to have unencoded paths */
                if (ap_unescape_url(parsed_uri.path) != OK) {
   Index: modules/examples/mod_example_hooks.c
   ===================================================================
   --- modules/examples/mod_example_hooks.c	(revision 1890572)
   +++ modules/examples/mod_example_hooks.c	(working copy)
   @@ -1175,6 +1175,22 @@ static int x_post_read_request(request_rec *r)
    
    /*
     * This routine gives our module an opportunity to translate the URI into an
   + * actual filename, before URL decoding happens.
   + *
   + * This is a RUN_FIRST hook.
   + */
   +static int x_pre_translate_name(request_rec *r)
   +{
   +    /*
   +     * We don't actually *do* anything here, except note the fact that we were
   +     * called.
   +     */
   +    trace_request(r, "x_pre_translate_name()");
   +    return DECLINED;
   +}
   +
   +/*
   + * This routine gives our module an opportunity to translate the URI into an
     * actual filename.  If we don't do anything special, the server's default
     * rules (Alias directives and the like) will continue to be followed.
     *
   @@ -1467,6 +1483,7 @@ static void x_register_hooks(apr_pool_t *p)
        ap_hook_log_transaction(x_log_transaction, NULL, NULL, APR_HOOK_MIDDLE);
        ap_hook_http_scheme(x_http_scheme, NULL, NULL, APR_HOOK_MIDDLE);
        ap_hook_default_port(x_default_port, NULL, NULL, APR_HOOK_MIDDLE);
   +    ap_hook_pre_translate_name(x_pre_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
        ap_hook_translate_name(x_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
        ap_hook_map_to_storage(x_map_to_storage, NULL,NULL, APR_HOOK_MIDDLE);
        ap_hook_header_parser(x_header_parser, NULL, NULL, APR_HOOK_MIDDLE);
   Index: modules/generators/mod_autoindex.c
   ===================================================================
   --- modules/generators/mod_autoindex.c	(revision 1890572)
   +++ modules/generators/mod_autoindex.c	(working copy)
   @@ -1266,8 +1266,9 @@ static struct ent *make_parent_entry(apr_int32_t a
        if (!(p->name = ap_make_full_path(r->pool, r->uri, "../"))) {
            return (NULL);
        }
   -    ap_getparents(p->name);
   -    if (!*p->name) {
   +    if (!ap_normalize_path(p->name, AP_NORMALIZE_ALLOW_RELATIVE |
   +                                    AP_NORMALIZE_NOT_ABOVE_ROOT)
   +            || p->name[0] == '\0') {
            return (NULL);
        }
    
   Index: modules/generators/mod_info.c
   ===================================================================
   --- modules/generators/mod_info.c	(revision 1890572)
   +++ modules/generators/mod_info.c	(working copy)
   @@ -322,6 +322,7 @@ static const hook_lookup_t request_hooks[] = {
        {"HTTP Scheme", ap_hook_get_http_scheme},
        {"Default Port", ap_hook_get_default_port},
        {"Quick Handler", ap_hook_get_quick_handler},
   +    {"Pre-Translate Name", ap_hook_get_pre_translate_name},
        {"Translate Name", ap_hook_get_translate_name},
        {"Map to Storage", ap_hook_get_map_to_storage},
        {"Check Access", ap_hook_get_access_checker_ex},
   Index: modules/loggers/mod_log_debug.c
   ===================================================================
   --- modules/loggers/mod_log_debug.c	(revision 1890572)
   +++ modules/loggers/mod_log_debug.c	(working copy)
   @@ -49,6 +49,7 @@ static const char * const hooks[] = {
        "check_authn",          /*  9 */
        "check_authz",          /* 10 */
        "insert_filter",        /* 11 */
   +    "pre_translate_name",   /* 12 */
        NULL
    };
    
   @@ -109,6 +110,12 @@ static int log_debug_handler(request_rec *r)
        return DECLINED;
    }
    
   +static int log_debug_pre_translate_name(request_rec *r)
   +{
   +    do_debug_log(r, hooks[12]);
   +    return DECLINED;
   +}
   +
    static int log_debug_translate_name(request_rec *r)
    {
        do_debug_log(r, hooks[3]);
   @@ -263,6 +270,7 @@ static void register_hooks(apr_pool_t *p)
        ap_hook_log_transaction(log_debug_log_transaction, NULL, NULL, APR_HOOK_FIRST);
        ap_hook_quick_handler(log_debug_quick_handler, NULL, NULL, APR_HOOK_FIRST);
        ap_hook_handler(log_debug_handler, NULL, NULL, APR_HOOK_FIRST);
   +    ap_hook_pre_translate_name(log_debug_pre_translate_name, NULL, NULL, APR_HOOK_FIRST);
        ap_hook_translate_name(log_debug_translate_name, NULL, NULL, APR_HOOK_FIRST);
        ap_hook_map_to_storage(log_debug_map_to_storage, NULL, NULL, APR_HOOK_FIRST);
        ap_hook_fixups(log_debug_fixups, NULL, NULL, APR_HOOK_FIRST);
   Index: modules/lua/mod_lua.c
   ===================================================================
   --- modules/lua/mod_lua.c	(revision 1890572)
   +++ modules/lua/mod_lua.c	(working copy)
   @@ -1202,6 +1202,11 @@ static int lua_check_user_id_harness_last(request_
    }
    */
    
   +static int lua_pre_trans_name_harness(request_rec *r)
   +{
   +    return lua_request_rec_hook_harness(r, "pre_translate_name", APR_HOOK_MIDDLE);
   +}
   +
    static int lua_translate_name_harness_first(request_rec *r)
    {
        return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_FIRST);
   @@ -1274,6 +1279,21 @@ static int lua_quick_harness(request_rec *r, int l
        return lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE);
    }
    
   +static const char *register_pre_trans_name_hook(cmd_parms *cmd, void *_cfg,
   +                                                const char *file,
   +                                                const char *function)
   +{
   +    return register_named_file_function_hook("pre_translate_name", cmd, _cfg, file,
   +                                             function, APR_HOOK_MIDDLE);
   +}
   +
   +static const char *register_pre_trans_name_block(cmd_parms *cmd, void *_cfg,
   +                                                 const char *line)
   +{
   +    return register_named_block_function_hook("pre_translate_name", cmd, _cfg,
   +                                              line);
   +}
   +
    static const char *register_translate_name_hook(cmd_parms *cmd, void *_cfg,
                                                    const char *file,
                                                    const char *function,
   @@ -1842,6 +1862,14 @@ static const command_rec lua_commands[] = {
        AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, RSRC_CONF|EXEC_ON_READ,
                      "Provide an authorization provider"),
    
   +    AP_INIT_TAKE2("LuaHookPreTranslateName", register_pre_trans_name_hook, NULL,
   +                  OR_ALL,
   +                  "Provide a hook for the pre_translate name phase of request processing"),
   +
   +    AP_INIT_RAW_ARGS("<LuaHookPreTranslateName", register_pre_trans_name_block, NULL,
   +                     EXEC_ON_READ | OR_ALL,
   +                     "Provide a hook for the pre_translate name phase of request processing"),
   +
        AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL,
                      OR_ALL,
                      "Provide a hook for the translate name phase of request processing"),
   @@ -2092,6 +2120,9 @@ static void lua_register_hooks(apr_pool_t *p)
                               APR_HOOK_MIDDLE);
    
        /* http_request.h hooks */
   +    ap_hook_pre_translate_name(lua_pre_trans_name_harness, NULL, NULL,
   +                               APR_HOOK_MIDDLE);
   +
        ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL,
                               AP_LUA_HOOK_FIRST);
        ap_hook_translate_name(lua_translate_name_harness, NULL, NULL,
   Index: modules/proxy/mod_proxy.c
   ===================================================================
   --- modules/proxy/mod_proxy.c	(revision 1890572)
   +++ modules/proxy/mod_proxy.c	(working copy)
   @@ -17,6 +17,7 @@
    #include "mod_proxy.h"
    #include "mod_core.h"
    #include "apr_optional.h"
   +#include "apr_strings.h"
    #include "scoreboard.h"
    #include "mod_status.h"
    #include "proxy_util.h"
   @@ -560,6 +561,201 @@ static int alias_match(const char *uri, const char
        return urip - uri;
    }
    
   +/*
   + * Inspired by mod_jk's jk_servlet_normalize().
   + */
   +static int alias_match_servlet(apr_pool_t *p,
   +                               const char **urip,
   +                               const char *alias)
   +{
   +    char *map;
   +    const char *uri = *urip;
   +    apr_array_header_t *stack;
   +    int map_pos, uri_pos, alias_pos, first_pos;
   +    int alias_depth = 0, depth;
   +
   +    /* Both uri and alias should start with '/' */
   +    if (uri[0] != '/' || alias[0] != '/') {
   +        return 0;
   +    }
   +
   +    stack = apr_array_make(p, 5, sizeof(int));
   +    map = apr_palloc(p, strlen(uri) + 1);
   +    map[0] = '/';
   +    map[1] = '\0';
   +
   +    map_pos = uri_pos = alias_pos = first_pos = 1;
   +    while (uri[uri_pos] != '\0') {
   +        /* Remove path parameters ;foo=bar/ from any path segment */
   +        if (uri[uri_pos] == ';') {
   +            do {
   +                uri_pos++;
   +            } while (uri[uri_pos] != '/' && uri[uri_pos] != '\0');
   +            continue;
   +        }
   +
   +        if (map[map_pos - 1] == '/') {
   +            /* Collapse ///// sequences to / */
   +            if (uri[uri_pos] == '/') {
   +                do {
   +                    uri_pos++;
   +                } while (uri[uri_pos] == '/');
   +                continue;
   +            }
   +
   +            if (uri[uri_pos] == '.') {
   +                /* Remove /./ segments */
   +                if (uri[uri_pos + 1] == '/'
   +                        || uri[uri_pos + 1] == ';'
   +                        || uri[uri_pos + 1] == '\0') {
   +                    uri_pos++;
   +                    if (uri[uri_pos] == '/') {
   +                        uri_pos++;
   +                    }
   +                    continue;
   +                }
   +
   +                /* Remove /xx/../ segments */
   +                if (uri[uri_pos + 1] == '.'
   +                    && (uri[uri_pos + 2] == '/'
   +                        || uri[uri_pos + 2] == ';'
   +                        || uri[uri_pos + 2] == '\0')) {
   +                    /* Wind map segment back the previous one */
   +                    if (map_pos == 1) {
   +                        /* Above root */
   +                        return 0;
   +                    }
   +                    do {
   +                        map_pos--;
   +                    } while (map[map_pos - 1] != '/');
   +                    map[map_pos] = '\0';
   +
   +                    /* Wind alias segment back, unless in deeper segment */
   +                    if (alias_depth == stack->nelts) {
   +                        if (alias[alias_pos] == '\0') {
   +                            alias_pos--;
   +                        }
   +                        while (alias_pos > 0 && alias[alias_pos] == '/') {
   +                            alias_pos--;
   +                        }
   +                        while (alias_pos > 0 && alias[alias_pos - 1] != '/') {
   +                            alias_pos--;
   +                        }
   +                        AP_DEBUG_ASSERT(alias_pos > 0);
   +                        alias_depth--;
   +                    }
   +                    apr_array_pop(stack);
   +
   +                    /* Move uri forward to the next segment */
   +                    uri_pos += 2;
   +                    if (uri[uri_pos] == '/') {
   +                        uri_pos++;
   +                    }
   +                    first_pos = 0;
   +                    continue;
   +                }
   +            }
   +            if (first_pos) {
   +                while (uri[first_pos] == '/') {
   +                    first_pos++;
   +                }
   +            }
   +
   +            /* New segment */
   +            APR_ARRAY_PUSH(stack, int) = first_pos ? first_pos : uri_pos;
   +            if (alias[alias_pos] != '\0') {
   +                if (alias[alias_pos - 1] != '/') {
   +                    /* Remain in pair with uri segments */
   +                    do {
   +                        alias_pos++;
   +                    } while (alias[alias_pos - 1] != '/' && alias[alias_pos]);
   +                }
   +                while (alias[alias_pos] == '/') {
   +                    alias_pos++;
   +                }
   +                if (alias[alias_pos] != '\0') {
   +                    alias_depth++;
   +                }
   +            }
   +        }
   +
   +        if (alias[alias_pos] != '\0') {
   +            int *match = &APR_ARRAY_IDX(stack, alias_depth - 1, int);
   +            if (*match) {
   +                if (alias[alias_pos] != uri[uri_pos]) {
   +                    /* Current segment does not match */
   +                    *match = 0;
   +                }
   +                else if (alias[alias_pos + 1] == '\0'
   +                         && alias[alias_pos] != '/') {
   +                    if (uri[uri_pos + 1] == ';') {
   +                        /* We'll preserve the parameters of the last
   +                         * segment if it does not end with '/', so mark
   +                         * the match as negative for below handling.
   +                         */
   +                        *match = -(uri_pos + 1);
   +                    }
   +                    else if (uri[uri_pos + 1] != '/'
   +                             && uri[uri_pos + 1] != '\0') {
   +                        /* Last segment does not match all the way */
   +                        *match = 0;
   +                    }
   +                }
   +            }
   +            /* Don't go past the segment if the uri isn't there yet */
   +            if (alias[alias_pos] != '/' || uri[uri_pos] == '/') {
   +                alias_pos++;
   +            }
   +        }
   +
   +        if (uri[uri_pos] == '/') {
   +            first_pos = uri_pos + 1;
   +        }
   +        map[map_pos++] = uri[uri_pos++];
   +        map[map_pos] = '\0';
   +    }
   +
   +    /* Can't reach the end of uri before the end of the alias,
   +     * for example if uri is "/" and alias is "/examples"
   +     */
   +    if (alias[alias_pos] != '\0') {
   +        return 0;
   +    }
   +
   +    /* Check whether each alias segment matched */
   +    for (depth = 0; depth < alias_depth; ++depth) {
   +        if (!APR_ARRAY_IDX(stack, depth, int)) {
   +            return 0;
   +        }
   +    }
   +
   +    /* If alias_depth == stack->nelts we have a full match, i.e.
   +     * uri == alias so we can return uri_pos as is (the end of uri)
   +     */
   +    if (alias_depth < stack->nelts) {
   +        /* Return the segment following the alias */
   +        uri_pos = APR_ARRAY_IDX(stack, alias_depth, int);
   +        if (alias_depth) {
   +            /* But if the last segment of the alias does not end with '/'
   +             * and the corresponding segment of the uri has parameters,
   +             * we want to forward those parameters (see above for the
   +             * negative pos trick/mark).
   +             */
   +            int pos = APR_ARRAY_IDX(stack, alias_depth - 1, int);
   +            if (pos < 0) {
   +                uri_pos = -pos;
   +            }
   +        }
   +    }
   +    /* If the alias lacks a trailing slash, take it from the uri (if any) */
   +    if (alias[alias_pos - 1] != '/' && uri[uri_pos - 1] == '/') {
   +        uri_pos--;
   +    }
   +
   +    *urip = map;
   +    return uri_pos;
   +}
   +
    /* Detect if an absoluteURI should be proxied or not.  Note that we
     * have to do this during this phase because later phases are
     * "short-circuiting"... i.e. translate_names will end when the first
   @@ -670,6 +866,7 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
        int mismatch = 0;
        unsigned int nocanon = ent->flags & PROXYPASS_NOCANON;
        const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
   +    const char *servlet_uri = NULL;
    
        if (dconf && (dconf->interpolate_env == 1) && (ent->flags & PROXYPASS_INTERPOLATE)) {
            fake = proxy_interpolate(r, ent->fake);
   @@ -730,7 +927,14 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
            }
        }
        else {
   -        len = alias_match(r->uri, fake);
   +        if ((ent->flags & PROXYPASS_MAP_SERVLET) == PROXYPASS_MAP_SERVLET) {
   +            servlet_uri = r->uri;
   +            len = alias_match_servlet(r->pool, &servlet_uri, fake);
   +            nocanon = 0; /* ignored since servlet's normalization applies */
   +        }
   +        else {
   +            len = alias_match(r->uri, fake);
   +        }
    
            if (len != 0) {
                if ((real[0] == '!') && (real[1] == '\0')) {
   @@ -761,7 +965,7 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
             */
            int rc = proxy_run_check_trans(r, found + 6);
            if (rc != OK && rc != DECLINED) {
   -            return DONE;
   +            return HTTP_CONTINUE;
            }
    
            r->filename = found;
   @@ -775,19 +979,33 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
                apr_table_setn(r->notes, "proxy-noquery", "1");
            }
    
   +        if (servlet_uri) {
   +            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(10248)
   +                          "Servlet path '%s' (%s) matches proxy handler '%s'",
   +                          r->uri, servlet_uri, found);
   +            /* Apply servlet normalization to r->uri so that <Location> or any
   +             * directory context match does not have to handle path parameters.
   +             * We change r->uri in-place so that r->parsed_uri.path is updated
   +             * too. Since normalized servlet_uri is necessarily shorter than
   +             * the original r->uri, strcpy() is fine.
   +             */
   +            AP_DEBUG_ASSERT(strlen(r->uri) >= strlen(servlet_uri));
   +            strcpy(r->uri, servlet_uri);
   +            return DONE;
   +        }
   +
            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03464)
                          "URI path '%s' matches proxy handler '%s'", r->uri,
                          found);
   -
            return OK;
        }
    
   -    return DONE;
   +    return HTTP_CONTINUE;
    }
    
   -static int proxy_trans(request_rec *r)
   +static int proxy_trans(request_rec *r, int pre_trans)
    {
   -    int i;
   +    int i, enc;
        struct proxy_alias *ent;
        proxy_dir_conf *dconf;
        proxy_server_conf *conf;
   @@ -794,11 +1012,32 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
    
        if (r->proxyreq) {
            /* someone has already set up the proxy, it was possibly ourselves
   -         * in proxy_detect
   +         * in proxy_detect (DONE will prevent further decoding of r->uri,
   +         * only if proxyreq is set before pre_trans already).
             */
   -        return OK;
   +        return pre_trans ? DONE : OK;
        }
    
   +    /* In early pre_trans hook, r->uri was not manipulated yet so we are
   +     * compliant with RFC1945 at this point. Otherwise, it probably isn't
   +     * an issue because this is a hybrid proxy/origin server.
   +     */
   +
   +    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
   +    conf = (proxy_server_conf *) ap_get_module_config(r->server->module_config,
   +                                                      &proxy_module);
   +
   +    /* Always and only do PROXY_MAP_ENCODED mapping in pre_trans, when
   +     * r->uri is still encoded, or we might consider for instance that
   +     * a decoded sub-delim is now a delimiter (e.g. "%3B" => ';' for
   +     * path parameters), which it's not.
   +     */
   +    if ((pre_trans && !conf->map_encoded_one)
   +            || (!pre_trans && conf->map_encoded_all)) {
   +        /* Fast path, nothing at this stage */
   +        return DECLINED;
   +    }
   +
        if ((r->unparsed_uri[0] == '*' && r->unparsed_uri[1] == '\0')
            || !r->uri || r->uri[0] != '/') {
            return DECLINED;
   @@ -808,37 +1047,42 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
            return DECLINED;
        }
    
   -    /* XXX: since r->uri has been manipulated already we're not really
   -     * compliant with RFC1945 at this point.  But this probably isn't
   -     * an issue because this is a hybrid proxy/origin server.
   -     */
   -
   -    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
   -
        /* short way - this location is reverse proxied? */
        if (dconf->alias) {
   -        int rv = ap_proxy_trans_match(r, dconf->alias, dconf);
   -        if (DONE != rv) {
   -            return rv;
   +        enc = (dconf->alias->flags & PROXYPASS_MAP_ENCODED) != 0;
   +        if (!(pre_trans ^ enc)) {
   +            int rv = ap_proxy_trans_match(r, dconf->alias, dconf);
   +            if (rv != HTTP_CONTINUE) {
   +                return rv;
   +            }
            }
        }
    
   -    conf = (proxy_server_conf *) ap_get_module_config(r->server->module_config,
   -                                                      &proxy_module);
   -
        /* long way - walk the list of aliases, find a match */
   -    if (conf->aliases->nelts) {
   -        ent = (struct proxy_alias *) conf->aliases->elts;
   -        for (i = 0; i < conf->aliases->nelts; i++) {
   -            int rv = ap_proxy_trans_match(r, &ent[i], dconf);
   -            if (DONE != rv) {
   +    for (i = 0; i < conf->aliases->nelts; i++) {
   +        ent = &((struct proxy_alias *)conf->aliases->elts)[i];
   +        enc = (ent->flags & PROXYPASS_MAP_ENCODED) != 0;
   +        if (!(pre_trans ^ enc)) {
   +            int rv = ap_proxy_trans_match(r, ent, dconf);
   +            if (rv != HTTP_CONTINUE) {
                    return rv;
                }
            }
        }
   +
        return DECLINED;
    }
    
   +static int proxy_pre_translate_name(request_rec *r)
   +{
   +    return proxy_trans(r, 1);
   +}
   +
   +static int proxy_translate_name(request_rec *r)
   +{
   +    return proxy_trans(r, 0);
   +}
   +
    static int proxy_walk(request_rec *r)
    {
        proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,
   @@ -1359,6 +1603,8 @@ static void * create_proxy_config(apr_pool_t *p, s
        ps->forward = NULL;
        ps->reverse = NULL;
        ps->domain = NULL;
   +    ps->map_encoded_one = 0;
   +    ps->map_encoded_all = 1;
        ps->id = apr_psprintf(p, "p%x", 1); /* simply for storage size */
        ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
        ps->viaopt_set = 0; /* 0 means default */
   @@ -1516,6 +1762,9 @@ static void * merge_proxy_config(apr_pool_t *p, vo
        ps->forward = overrides->forward ? overrides->forward : base->forward;
        ps->reverse = overrides->reverse ? overrides->reverse : base->reverse;
    
   +    ps->map_encoded_one = overrides->map_encoded_one || base->map_encoded_one;
   +    ps->map_encoded_all = overrides->map_encoded_all && base->map_encoded_all;
   +
        ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
        ps->id = (overrides->id == NULL) ? base->id : overrides->id;
        ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
   @@ -1640,7 +1889,7 @@ static void *merge_proxy_dir_config(apr_pool_t *p,
                                                 : add->forward_100_continue;
        new->forward_100_continue_set = add->forward_100_continue_set
                                        || base->forward_100_continue_set;
   -    
   +
        return new;
    }
    
   @@ -1814,11 +2063,31 @@ static const char *
                               "in the form 'key=value'.";
                    }
                }
   -            else
   +            else {
                    *val++ = '\0';
   -            apr_table_setn(params, word, val);
   +            }
   +            if (!strcasecmp(word, "mapping")) {
   +                if (!strcasecmp(val, "encoded")) {
   +                    flags |= PROXYPASS_MAP_ENCODED;
   +                }
   +                else if (!strcasecmp(val, "servlet")) {
   +                    flags |= PROXYPASS_MAP_SERVLET;
   +                }
   +                else {
   +                    return "unknown mapping";
   +                }
   +            }
   +            else {
   +                apr_table_setn(params, word, val);
   +            }
            }
   -    };
   +    }
   +    if (flags & PROXYPASS_MAP_ENCODED) {
   +        conf->map_encoded_one = 1;
   +    }
   +    else {
   +        conf->map_encoded_all = 0;
   +    }
    
        if (r == NULL) {
            return "ProxyPass|ProxyPassMatch needs a path when not defined in a location";
   @@ -3142,7 +3411,10 @@ static void register_hooks(apr_pool_t *p)
        /* handler */
        ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
        /* filename-to-URI translation */
   -    ap_hook_translate_name(proxy_trans, aszSucc, NULL, APR_HOOK_FIRST);
   +    ap_hook_pre_translate_name(proxy_pre_translate_name, NULL, NULL,
   +                               APR_HOOK_MIDDLE);
   +    ap_hook_translate_name(proxy_translate_name, aszSucc, NULL,
   +                           APR_HOOK_FIRST);
        /* walk <Proxy > entries and suppress default TRACE behavior */
        ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
        /* fixups */
   Index: modules/proxy/mod_proxy.h
   ===================================================================
   --- modules/proxy/mod_proxy.h	(revision 1890572)
   +++ modules/proxy/mod_proxy.h	(working copy)
   @@ -124,6 +124,8 @@ struct proxy_remote {
    #define PROXYPASS_NOCANON 0x01
    #define PROXYPASS_INTERPOLATE 0x02
    #define PROXYPASS_NOQUERY 0x04
   +#define PROXYPASS_MAP_ENCODED 0x08
   +#define PROXYPASS_MAP_SERVLET 0x18 /* + MAP_ENCODED */
    struct proxy_alias {
        const char  *real;
        const char  *fake;
   @@ -200,6 +202,8 @@ typedef struct {
        unsigned int inherit_set:1;
        unsigned int ppinherit:1;
        unsigned int ppinherit_set:1;
   +    unsigned int map_encoded_one:1;
   +    unsigned int map_encoded_all:1;
    } proxy_server_conf;
    
    typedef struct {
   @@ -1171,7 +1175,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer
     * @param r     request
     * @param ent   proxy_alias record
     * @param dconf per-dir config or NULL
   - * @return      DECLINED, DONE or OK if matched
   + * @return      OK if the alias matched,
   + *              DONE if the alias matched and r->uri was normalized so
   + *                   no further transformation should happen on it,
   + *              DECLINED if proxying is disabled for this alias,
   + *              HTTP_CONTINUE if the alias did not match
     */
    PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r,
                                            struct proxy_alias *ent,
   Index: server/request.c
   ===================================================================
   --- server/request.c	(revision 1890572)
   +++ server/request.c	(working copy)
   @@ -59,6 +59,7 @@
    #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
    
    APR_HOOK_STRUCT(
   +    APR_HOOK_LINK(pre_translate_name)
        APR_HOOK_LINK(translate_name)
        APR_HOOK_LINK(map_to_storage)
        APR_HOOK_LINK(check_user_id)
   @@ -74,6 +75,8 @@ APR_HOOK_STRUCT(
        APR_HOOK_LINK(force_authn)
    )
    
   +AP_IMPLEMENT_HOOK_RUN_FIRST(int,pre_translate_name,
   +                            (request_rec *r), (r), DECLINED)
    AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
                                (request_rec *r), (r), DECLINED)
    AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
   @@ -157,6 +160,26 @@ AP_DECLARE(int) ap_some_authn_required(request_rec
        return rv;
    }
    
   +static int walk_location_and_if(request_rec *r)
   +{
   +    int access_status;
   +
   +    if ((access_status = ap_location_walk(r))) {
   +        return access_status;
   +    }
   +    if ((access_status = ap_if_walk(r))) {
   +        return access_status;
   +    }
   +
   +    {
   +        core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
   +        if (d->log)
   +            r->log = d->log;
   +    }
   +
   +    return OK;
   +}
   +
    /* This is the master logic for processing requests.  Do NOT duplicate
     * this logic elsewhere, or the security model will be broken by future
     * API changes.  Each phase must be individually optimized to pick up
   @@ -164,17 +187,65 @@ AP_DECLARE(int) ap_some_authn_required(request_rec
     */
    AP_DECLARE(int) ap_process_request_internal(request_rec *r)
    {
   +    int access_status = DECLINED;
        int file_req = (r->main && r->filename);
   -    int access_status;
   -    core_dir_config *d;
        core_server_config *sconf =
            ap_get_core_module_config(r->server->module_config);
   +    unsigned int normalize_flags;
    
   -    /* Ignore embedded %2F's in path for proxy requests */
   -    if (!r->proxyreq && r->parsed_uri.path) {
   -        d = ap_get_core_module_config(r->per_dir_config);
   +    normalize_flags = AP_NORMALIZE_NOT_ABOVE_ROOT;
   +    if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { 
   +        normalize_flags |= AP_NORMALIZE_MERGE_SLASHES;
   +    }
   +    if (file_req) {
   +        /* File subrequests can have a relative path. */
   +        normalize_flags |= AP_NORMALIZE_ALLOW_RELATIVE;
   +    }
   +
   +    if (r->parsed_uri.path) {
   +        /* Normalize: remove /./ and shrink /../ segments, plus
   +         * decode unreserved chars (first time only to avoid
   +         * double decoding after ap_unescape_url() below).
   +         */
   +        if (!ap_normalize_path(r->parsed_uri.path,
   +                               normalize_flags |
   +                               AP_NORMALIZE_DECODE_UNRESERVED)) {
   +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10244)
   +                          "invalid URI path (%s)", r->unparsed_uri);
   +            return HTTP_BAD_REQUEST;
   +        }
   +    }
   +
   +    /* All file subrequests are a huge pain... they cannot bubble through the
   +     * next several steps.  Only file subrequests are allowed an empty uri,
   +     * otherwise let (pre_)translate_name kill the request.
   +     */
   +    if (!file_req) {
   +        ap_conf_vector_t *per_dir_config = r->per_dir_config;
   +
   +        if ((access_status = walk_location_and_if(r))) {
   +            return access_status;
   +        }
   +
   +        /* Let pre_translate_name hooks work with non-decoded URIs, and
   +         * eventually prevent further URI transformations (return DONE).
   +         */
   +        access_status = ap_run_pre_translate_name(r);
   +        if (ap_is_HTTP_ERROR(access_status)) {
   +            return access_status;
   +        }
   +
   +        /* Throw away pre_trans only merging */
   +        r->per_dir_config = per_dir_config;
   +    }
   +
   +    /* Ignore URL unescaping for translated URIs already */
   +    if (access_status != DONE && r->parsed_uri.path) {
   +        core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
   +
            if (d->allow_encoded_slashes) {
   -            access_status = ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes);
   +            access_status = ap_unescape_url_keep2f(r->parsed_uri.path,
   +                                                   d->decode_encoded_slashes);
            }
            else {
                access_status = ap_unescape_url(r->parsed_uri.path);
   @@ -183,40 +254,27 @@ AP_DECLARE(int) ap_process_request_internal(reques
                if (access_status == HTTP_NOT_FOUND) {
                    if (! d->allow_encoded_slashes) {
                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026)
   -                                  "found %%2f (encoded '/') in URI "
   -                                  "(decoded='%s'), returning 404",
   -                                  r->parsed_uri.path);
   +                                  "found %%2f (encoded '/') in URI path (%s), "
   +                                  "returning 404", r->unparsed_uri);
                    }
                }
                return access_status;
            }
   -    }
    
   -    ap_getparents(r->uri);     /* OK --- shrinking transformations... */
   -    if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { 
   -        ap_no2slash(r->uri);
   -        if (r->parsed_uri.path) {
   -            ap_no2slash(r->parsed_uri.path);
   +        if (d->allow_encoded_slashes && d->decode_encoded_slashes) {
   +            /* Decoding slashes might have created new // or /./ or /../
   +             * segments (e.g. "/.%2F/"), so re-normalize.
   +             */
   +            ap_normalize_path(r->parsed_uri.path, normalize_flags);
            }
   -     }
   +    }
    
   -    /* All file subrequests are a huge pain... they cannot bubble through the
   -     * next several steps.  Only file subrequests are allowed an empty uri,
   -     * otherwise let translate_name kill the request.
   -     */
   +    /* Same, translate_name is not suited for file subrequests */
        if (!file_req) {
   -        if ((access_status = ap_location_walk(r))) {
   +        if ((access_status = walk_location_and_if(r))) {
                return access_status;
            }
   -        if ((access_status = ap_if_walk(r))) {
   -            return access_status;
   -        }
    
   -        d = ap_get_core_module_config(r->per_dir_config);
   -        if (d->log) {
   -            r->log = d->log;
   -        }
   -
            if ((access_status = ap_run_translate_name(r))) {
                return decl_die(access_status, "translate", r);
            }
   @@ -233,18 +291,10 @@ AP_DECLARE(int) ap_process_request_internal(reques
    
        /* Rerun the location walk, which overrides any map_to_storage config.
         */
   -    if ((access_status = ap_location_walk(r))) {
   +    if ((access_status = walk_location_and_if(r))) {
            return access_status;
        }
   -    if ((access_status = ap_if_walk(r))) {
   -        return access_status;
   -    }
    
   -    d = ap_get_core_module_config(r->per_dir_config);
   -    if (d->log) {
   -        r->log = d->log;
   -    }
   -
        if ((access_status = ap_run_post_perdir_config(r))) {
            return access_status;
        }
   @@ -1370,7 +1420,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
        r->canonical_filename = r->filename;
    
        if (r->finfo.filetype == APR_DIR) {
   -        cache->cached = r->filename;
   +        cache->cached = apr_pstrdup(r->pool, r->filename);
        }
        else {
            cache->cached = ap_make_dirstr_parent(r->pool, r->filename);
   @@ -1467,7 +1517,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
            apr_pool_t *rxpool = NULL;
    
            cached &= auth_internal_per_conf;
   -        cache->cached = entry_uri;
   +        cache->cached = apr_pstrdup(r->pool, entry_uri);
    
            /* Go through the location entries, and check for matches.
             * We apply the directive sections in given order, we should
   Index: server/util.c
   ===================================================================
   --- server/util.c	(revision 1890572)
   +++ server/util.c	(working copy)
   @@ -76,7 +76,7 @@
    #include "test_char.h"
    
    /* Win32/NetWare/OS2 need to check for both forward and back slashes
   - * in ap_getparents() and ap_escape_url.
   + * in ap_normalize_path() and ap_escape_url().
     */
    #ifdef CASE_BLIND_FILESYSTEM
    #define IS_SLASH(s) ((s == '/') || (s == '\\'))
   @@ -491,75 +491,127 @@ AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t
        return rc;
    }
    
   +/* Forward declare */
   +static char x2c(const char *what);
   +
   +#define IS_SLASH_OR_NUL(s) (s == '\0' || IS_SLASH(s))
   +
    /*
   - * Parse .. so we don't compromise security
   + * Inspired by mod_jk's jk_servlet_normalize().
     */
   -AP_DECLARE(void) ap_getparents(char *name)
   +AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
    {
   -    char *next;
   -    int l, w, first_dot;
   +    int ret = 1;
   +    apr_size_t l = 1, w = 1;
    
   -    /* Four paseses, as per RFC 1808 */
   -    /* a) remove ./ path segments */
   -    for (next = name; *next && (*next != '.'); next++) {
   -    }
   +    if (!IS_SLASH(path[0])) {
   +        /* Besides "OPTIONS *", a request-target should start with '/'
   +         * per RFC 7230 section 5.3, so anything else is invalid.
   +         */
   +        if (path[0] == '*' && path[1] == '\0') {
   +            return 1;
   +        }
   +        /* However, AP_NORMALIZE_ALLOW_RELATIVE can be used to bypass
   +         * this restriction (e.g. for subrequest file lookups).
   +         */
   +        if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') {
   +            return 0;
   +        }
    
   -    l = w = first_dot = next - name;
   -    while (name[l] != '\0') {
   -        if (name[l] == '.' && IS_SLASH(name[l + 1])
   -            && (l == 0 || IS_SLASH(name[l - 1])))
   -            l += 2;
   -        else
   -            name[w++] = name[l++];
   +        l = w = 0;
        }
    
   -    /* b) remove trailing . path, segment */
   -    if (w == 1 && name[0] == '.')
   -        w--;
   -    else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
   -        w--;
   -    name[w] = '\0';
   +    while (path[l] != '\0') {
   +        /* RFC-3986 section 2.3:
   +         *  For consistency, percent-encoded octets in the ranges of
   +         *  ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
   +         *  period (%2E), underscore (%5F), or tilde (%7E) should [...]
   +         *  be decoded to their corresponding unreserved characters by
   +         *  URI normalizers.
   +         */
   +        if ((flags & AP_NORMALIZE_DECODE_UNRESERVED)
   +                && path[l] == '%' && apr_isxdigit(path[l + 1])
   +                                  && apr_isxdigit(path[l + 2])) {
   +            const char c = x2c(&path[l + 1]);
   +            if (apr_isalnum(c) || (c && strchr("-._~", c))) {
   +                /* Replace last char and fall through as the current
   +                 * read position */
   +                l += 2;
   +                path[l] = c;
   +            }
   +        }
    
   -    /* c) remove all xx/../ segments. (including leading ../ and /../) */
   -    l = first_dot;
   +        if ((flags & AP_NORMALIZE_DROP_PARAMETERS) && path[l] == ';') {
   +            do {
   +                l++;
   +            } while (!IS_SLASH_OR_NUL(path[l]));
   +            continue;
   +        }
    
   -    while (name[l] != '\0') {
   -        if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
   -            && (l == 0 || IS_SLASH(name[l - 1]))) {
   -            int m = l + 3, n;
   +        if (w == 0 || IS_SLASH(path[w - 1])) {
   +            /* Collapse ///// sequences to / */
   +            if ((flags & AP_NORMALIZE_MERGE_SLASHES) && IS_SLASH(path[l])) {
   +                do {
   +                    l++;
   +                } while (IS_SLASH(path[l]));
   +                continue;
   +            }
    
   -            l = l - 2;
   -            if (l >= 0) {
   -                while (l >= 0 && !IS_SLASH(name[l]))
   -                    l--;
   -                l++;
   +            if (path[l] == '.') {
   +                /* Remove /./ segments */
   +                if (IS_SLASH_OR_NUL(path[l + 1])) {
   +                    l++;
   +                    if (path[l]) {
   +                        l++;
   +                    }
   +                    continue;
   +                }
   +
   +                /* Remove /xx/../ segments */
   +                if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) {
   +                    /* Wind w back to remove the previous segment */
   +                    if (w > 1) {
   +                        do {
   +                            w--;
   +                        } while (w && !IS_SLASH(path[w - 1]));
   +                    }
   +                    else {
   +                        /* Already at root, ignore and return a failure
   +                         * if asked to.
   +                         */
   +                        if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
   +                            ret = 0;
   +                        }
   +                    }
   +
   +                    /* Move l forward to the next segment */
   +                    l += 2;
   +                    if (path[l]) {
   +                        l++;
   +                    }
   +                    continue;
   +                }
                }
   -            else
   -                l = 0;
   -            n = l;
   -            while ((name[n] = name[m]))
   -                (++n, ++m);
            }
   -        else
   -            ++l;
   +
   +        path[w++] = path[l++];
        }
   +    path[w] = '\0';
    
   -    /* d) remove trailing xx/.. segment. */
   -    if (l == 2 && name[0] == '.' && name[1] == '.')
   +    return ret;
   +}
   +
   +/*
   + * Parse .. so we don't compromise security
   + */
   +AP_DECLARE(void) ap_getparents(char *name)
   +{
   +    if (!ap_normalize_path(name, AP_NORMALIZE_NOT_ABOVE_ROOT |
   +                                 AP_NORMALIZE_ALLOW_RELATIVE)) {
            name[0] = '\0';
   -    else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
   -             && IS_SLASH(name[l - 3])) {
   -        l = l - 4;
   -        if (l >= 0) {
   -            while (l >= 0 && !IS_SLASH(name[l]))
   -                l--;
   -            l++;
   -        }
   -        else
   -            l = 0;
   -        name[l] = '\0';
        }
    }
   +
    AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
    {
    
   Index: .
   ===================================================================
   --- .	(revision 1890572)
   +++ .	(working copy)
   
   Property changes on: .
   ___________________________________________________________________
   Modified: svn:mergeinfo
   ## -0,0 +0,1 ##
      Merged /httpd/httpd/trunk:r1879074-1879080,1879094-1879095,1879110-1879112,1879114,1879116-1879117,1879137,1879144-1879145,1879147,1879149,1879235,1879360
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@httpd.apache.org
For additional commands, e-mail: notifications-help@httpd.apache.org


[GitHub] [httpd] jfclere commented on pull request #193: back port the mapping=servlet to 2.4.x

Posted by GitBox <gi...@apache.org>.
jfclere commented on pull request #193:
URL: https://github.com/apache/httpd/pull/193#issuecomment-857554933


   started https://github.com/apache/httpd/pull/194 to replace it.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@httpd.apache.org
For additional commands, e-mail: notifications-help@httpd.apache.org