Please add this latest patch to the Apache 1.3 tree. It fixes two
failures in the current 1.3.19 candidate:
1) the URI "#frag" would be emitted as "", because of a NULL path
2) sometimes an "@" was present in the site part even in the absence of
user info
For reference, the 1.3.17 version of this function could (aside from
dumoing core) emit bogosities such as:
http://hostpath
user@path?name=value#frag
http://@host/path?name=value#frag
Okay I guess that last one is valid but it still looks silly. I have also
attached my updated battery of test cases.
Warm regards,
Jeffrey Baker
Index: util_uri.c
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/main/util_uri.c,v
retrieving revision 1.31
diff -u -r1.31 util_uri.c
--- util_uri.c 2001/02/26 15:49:44 1.31
+++ util_uri.c 2001/02/28 23:36:54
@@ -207,7 +207,8 @@
parts[j++] = "//";
/* userinfo requires hostport */
- if (uptr->hostname && (uptr->user || uptr->password)) {
+ if (uptr->hostname && (uptr->user || uptr->password)
+ && !(flags & UNP_OMITUSER && flags & UNP_OMITPASSWORD)) {
if (uptr->user && !(flags & UNP_OMITUSER))
parts[j++] = uptr->user;
@@ -218,10 +219,10 @@
parts[j++] = uptr->password;
else
parts[j++] = "XXXXXXXX";
- }
+ }
parts[j++] = "@";
- }
+ }
/* If we get here, there must be a hostname. */
parts[j++] = uptr->hostname;
@@ -242,23 +243,26 @@
if (!(flags & UNP_OMITPATHINFO)) {
-
/* We must ensure we don't put out a hier_part and a rel_path */
if (j && uptr->path && *uptr->path != '/')
parts[j++] = "/";
- parts[j++] = uptr->path;
+
+ /* Neither path nor query can exist without a path, but fragment can */
+ if (uptr->path != NULL) {
+ parts[j++] = uptr->path;
- if (!(flags & UNP_OMITQUERY)) {
- if (uptr->query) {
- parts[j++] = "?";
- parts[j++] = uptr->query;
+ if (!(flags & UNP_OMITQUERY)) {
+ if (uptr->query) {
+ parts[j++] = "?";
+ parts[j++] = uptr->query;
+ }
}
-
- if (uptr->fragment) {
- parts[j++] = "#";
- parts[j++] = uptr->fragment;
- }
+ }
+
+ if (uptr->fragment) {
+ parts[j++] = "#";
+ parts[j++] = uptr->fragment;
}
}
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
/*
* This module is intended to test the util_uri routines by parsing a
* bunch of urls and comparing the results with what we expect to
* see.
*
* Usage:
*
* <Location /test-util-uri>
* SetHandler test-util-uri
* </Location>
*
* Then make a request to /test-util-uri. An html table of errors will
* be output... and a total count of errors.
*/
#include "httpd.h"
#include "http_protocol.h"
#include "http_config.h"
#include "http_main.h"
#include "util_uri.h"
#include <stdlib.h>
static uri_components uri;
typedef struct {
char *scheme;
char *user;
char *password;
char *hostname;
char *port;
char *path;
char *query;
char *fragment;
} uri_init;
typedef struct {
uri_init init;
unsigned flags;
char *expect;
} job;
static const job jobs[] = {
/* First the easy smoketest, then some more valid URIs */
{ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, "frag" }, 0, "#frag" },
{ { NULL, NULL, NULL, NULL, NULL, "path", NULL, NULL }, 0, "path" },
{ { NULL, NULL, NULL, NULL, NULL, "/path", NULL, NULL }, 0, "/path" },
{ { NULL, NULL, NULL, NULL, NULL, "/path", "name=value", NULL }, 0,
"/path?name=value" },
{ { NULL, NULL, NULL, NULL, NULL, "/path", NULL, "frag" }, 0, "/path#frag" },
{ { NULL, NULL, NULL, NULL, NULL, "/path", "name=value", "frag" }, 0,
"/path?name=value#frag" },
{ { NULL, NULL, NULL, NULL, NULL, "path", "name=value", "frag" }, 0,
"path?name=value#frag" },
{ { "http", NULL, NULL, "host", NULL, NULL, NULL, NULL }, 0, "http://host" },
{ { "https", NULL, NULL, "host", NULL, NULL, NULL, NULL }, 0, "https://host" },
{ { "http", NULL, NULL, "host", NULL, "/path", NULL, NULL }, 0, "http://host/path"
},
{ { "http", NULL, NULL, "host", NULL, "path", NULL, NULL }, 0, "http://host/path"
},
{ { "http", NULL, NULL, "host", "80", NULL, NULL, NULL }, 0, "http://host" },
{ { "http", NULL, NULL, "host", "81", NULL, NULL, NULL }, 0, "http://host:81" },
{ { "https", NULL, NULL, "host", "443", NULL, NULL, NULL }, 0, "https://host" },
{ { "https", NULL, NULL, "host", "444", NULL, NULL, NULL }, 0, "https://host:444"
},
{ { "http", NULL, NULL, "host", "81", "/path", NULL, NULL }, 0,
"http://host:81/path" },
{ { "http", NULL, NULL, "host", NULL, "/path", "name=value", NULL }, 0,
"http://host/path?name=value" },
{ { "http", NULL, NULL, "host", NULL, "/path", "name=value", "fragment" }, 0,
"http://host/path?name=value#fragment" },
{ { "http", "user", NULL, "host", NULL, "/path", "name=value", "fragment" }, 0,
"http://user@host/path?name=value#fragment" },
{ { "http", NULL, "pass", "host", NULL, "/path", "name=value", "fragment" }, 0,
"http://:XXXXXXXX@host/path?name=value#fragment" },
{ { "http", "user", "pass", "host", NULL, "/path", "name=value", "fragment" }, 0,
"http://user:XXXXXXXX@host/path?name=value#fragment" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "fragment" }, 0,
"http://user:XXXXXXXX@host/path?name=value#fragment" },
{ { "http", "user", "pass", "host", "81", "/path", "name=value", "fragment" }, 0,
"http://user:XXXXXXXX@host:81/path?name=value#fragment" },
{ { "https", "user", "pass", "host", "443", "/path", "name=value", "fragment" },
0, "https://user:XXXXXXXX@host/path?name=value#fragment" },
{ { "https", "user", "pass", "host", "444", "/path", "name=value", "fragment" },
0, "https://user:XXXXXXXX@host:444/path?name=value#fragment" },
/* These URIs are all bogus in some way */
{ { "http", NULL, NULL, NULL, NULL, "/path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
{ { "http", NULL, NULL, NULL, NULL, "path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
{ { "http", NULL, NULL, NULL, "81", "path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
/* XXX: these four currently fail, but they don't crash, and nobody writes URIs
this way anyway */
{ { "http", "user", NULL, NULL, NULL, "path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
{ { "http", NULL, "pass", NULL, NULL, "path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
{ { "http", "user", "pass", NULL, NULL, "path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
{ { "http", "user", "pass", NULL, NULL, "path", "name=value", "frag" }, 0,
"http:/path?name=value#frag" },
{ { NULL, NULL, NULL, "host", NULL, "/path", NULL, NULL }, 0, "http://host/path"
},
{ { NULL, NULL, NULL, NULL, "80", "/path", NULL, NULL }, 0, "/path" },
{ { NULL, NULL, NULL, NULL, "81", "/path", NULL, NULL }, 0, "/path" },
{ { NULL, NULL, NULL, "host", "80", "/path", NULL, NULL }, 0, "http://host/path"
},
{ { NULL, NULL, NULL, "host", "81", "/path", NULL, NULL }, 0,
"http://host:81/path" },
{ { NULL, NULL, NULL, NULL, NULL, NULL, "name=value", NULL }, 0, "" },
{ { NULL, NULL, NULL, NULL, NULL, NULL, "name=value", "frag" }, 0, "#frag" },
/* Now exercise the various options, starting with irrelevant ones */
{ { NULL, NULL, NULL, NULL, NULL, "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { "http", NULL, NULL, "host", NULL, "/path", "name=value", "frag" },
UNP_OMITUSER, "http://host/path?name=value#frag" },
{ { "http", NULL, NULL, "host", NULL, "/path", "name=value", "frag" },
UNP_OMITPASSWORD, "http://host/path?name=value#frag" },
{ { "http", NULL, NULL, "host", NULL, NULL, NULL, NULL }, UNP_OMITPATHINFO,
"http://host" },
{ { NULL, NULL, NULL, NULL, NULL, "/path", NULL, "frag" }, UNP_OMITQUERY,
"/path#frag" },
{ { "http", "user", "pass", "host", "port", "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { "http", NULL, "pass", "host", "port", "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { "http", NULL, NULL, "host", "port", "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { "http", NULL, NULL, NULL, "port", "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { "http", NULL, NULL, NULL, NULL, "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { NULL, NULL, NULL, NULL, NULL, "/path", "name=value", "frag" },
UNP_OMITSITEPART, "/path?name=value#frag" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_OMITUSERINFO, "http://host/path?name=value#frag" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_OMITUSER, "http://:XXXXXXXX@host/path?name=value#frag" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_OMITPASSWORD, "http://user@host/path?name=value#frag" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_REVEALPASSWORD, "http://user:pass@host/path?name=value#frag" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_OMITUSER|UNP_REVEALPASSWORD, "http://:pass@host/path?name=value#frag" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_OMITPATHINFO, "http://user:XXXXXXXX@host" },
{ { "http", "user", "pass", "host", "80", "path", NULL, NULL }, UNP_OMITPATHINFO,
"http://user:XXXXXXXX@host" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", NULL },
UNP_OMITQUERY, "http://user:XXXXXXXX@host/path" },
{ { "http", "user", "pass", "host", "80", "/path", "name=value", "frag" },
UNP_OMITQUERY, "http://user:XXXXXXXX@host/path#frag" },
};
static void fill_uri(uri_components *uri, const uri_init *init)
{
uri->scheme = init->scheme;
uri->user = init->user;
uri->password = init->password;
uri->hostname = init->hostname;
uri->port_str = init->port;
uri->port = init->port == NULL ? 0 : atoi(init->port);
uri->path = init->path;
uri->query = init->query;
uri->fragment = init->fragment;
}
static int test_util_uri(request_rec *r)
{
int i;
int failures = 0;
char *unparsed;
r->allowed |= (1 << M_GET);
if (r->method_number != M_GET)
return DECLINED;
r->content_type = "text/html";
ap_send_http_header(r);
if(r->header_only)
return 0;
ap_hard_timeout("test_util_uri", r);
ap_rputs(DOCTYPE_HTML_4_0T "<title>unparse test</title>", r);
for (i = 0; i < sizeof(jobs) / sizeof(jobs[0]); i++) {
fill_uri(&uri, &jobs[i].init);
unparsed = ap_unparse_uri_components(r->pool, &uri, jobs[i].flags);
if (strcasecmp(unparsed, jobs[i].expect)) {
failures++;
ap_rprintf(r, "<p style=\"color: red\">UNEXPECTED RESULT:");
}
ap_rprintf(r, "<p style=\"font-family: monospace\">ACTUAL: %s<br>EXPECT:
%s\n", unparsed, jobs[i].expect);
}
ap_rprintf(r, "<p>%i failures", failures);
return OK;
}
static const handler_rec test_util_uri_handlers[] =
{
{"test-util-uri", test_util_uri},
{NULL}
};
module test_util_uri_module = {
STANDARD_MODULE_STUFF,
NULL, /* initializer */
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
NULL, /* command table */
test_util_uri_handlers, /* handlers */
NULL, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
NULL, /* logger */
NULL /* header parser */
};