in modules/proxy/mod_proxy.c [606:796]
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;
}