1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
60 * This module is intended to test the util_uri routines by parsing a
61 * bunch of urls and comparing the results with what we expect to
66 * <Location /test-util-uri>
67 * SetHandler test-util-uri
70 * Then make a request to /test-util-uri. An html apr_table_t of errors will
71 * be output... and a total count of errors.
75 #include "http_protocol.h"
76 #include "http_config.h"
77 #include "http_main.h"
92 #define T_password 0x04
93 #define T_hostname 0x08
94 #define T_port_str 0x10
97 #define T_fragment 0x80
100 /* The idea is that we list here a bunch of url pieces that we want
101 * stitched together in every way that's valid.
103 static const test_uri_t uri_tests[] = {
104 { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" },
105 { "http", "", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" },
106 { "http", "userid", "", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" },
107 { "http", "userid", "passwd", "", "80", "/path/goes/here", "query-here", "frag-here" },
108 { "http", "userid", "passwd", "hostname.goes.here", "", "/path/goes/here", "query-here", "frag-here" },
110 /* An empty path means two different things depending on whether this is a
111 * relative or an absolute uri... consider <a href="#frag"> versus "GET
112 * http://hostname HTTP/1.1". So this is why parse_uri_components returns
113 * a NULL for path when it doesn't find one, instead of returning an empty
116 * We don't really need to test it explicitly since path has no explicit
117 * character that indicates its precense, and so we test empty paths all
118 * the time by varying T_path in the loop. It would just cost us extra
119 * code to special case the empty path string...
121 { "http", "userid", "passwd", "hostname.goes.here", "80", "", "query-here", "frag-here" },
123 { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "", "frag-here" },
124 { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "" },
125 { "https", "user@d", "pa:swd", "hostname.goes.here.", "", "/~path/goes/here", "query&query?crud", "frag-here?baby" }
129 static char *my_stpcpy(char *d, const char *s)
138 /* return the number of failures */
139 static unsigned iterate_pieces(request_rec *r, const test_uri_t *pieces, int row)
145 uri_components result;
152 input_uri = apr_palloc(r->pool,
153 strlen(pieces->scheme) + 3
154 + strlen(pieces->user) + 1
155 + strlen(pieces->password) + 1
156 + strlen(pieces->hostname) + 1
157 + strlen(pieces->port_str) + 1
158 + strlen(pieces->path) +
159 + strlen(pieces->query) + 1
160 + strlen(pieces->fragment) + 1
163 for (u = 0; u < T_MAX; ++u) {
167 /* a scheme requires a hostinfo and vice versa */
168 /* a hostinfo requires a hostname */
169 if (u & (T_scheme|T_user|T_password|T_hostname|T_port_str)) {
171 strp = my_stpcpy(strp, pieces->scheme);
175 /* can't have password without user */
176 if (u & (T_user|T_password)) {
178 strp = my_stpcpy(strp, pieces->user);
179 if (u & T_password) {
180 expect |= T_password;
182 strp = my_stpcpy(strp, pieces->password);
186 expect |= T_hostname;
187 strp = my_stpcpy(strp, pieces->hostname);
188 if (u & T_port_str) {
189 expect |= T_port_str;
191 strp = my_stpcpy(strp, pieces->port_str);
196 strp = my_stpcpy(strp, pieces->path);
201 strp = my_stpcpy(strp, pieces->query);
203 if (u & T_fragment) {
204 expect |= T_fragment;
206 strp = my_stpcpy(strp, pieces->fragment);
210 sub = apr_pool_sub_make(r->pool);
211 status = ap_parse_uri_components(sub, input_uri, &result);
212 if (status == HTTP_OK) {
214 if ((expect & T_##f) \
215 && (result.f == NULL || strcmp(result.f, pieces->f))) { \
216 status = HTTP_INTERNAL_SERVER_ERROR; \
218 else if (!(expect & T_##f) && result.f != NULL) { \
219 status = HTTP_INTERNAL_SERVER_ERROR; \
231 if (status != HTTP_OK) {
232 ap_rprintf(r, "<tr><td>%d</td><td>0x%02x</td><td>0x%02x</td><td>%d</td><td>\"%s\"</td>", row, u, expect, status, input_uri);
235 ap_rvputs(r, "<td>\"", result.f, "\"<br>", NULL); \
238 ap_rputs("<td>NULL<br>", r); \
240 if (expect & T_##f) { \
241 ap_rvputs(r, "\"", pieces->f, "\"</td>", NULL); \
244 ap_rputs("NULL</td>", r); \
255 ap_rputs("</tr>\n", r);
258 apr_pool_destroy(sub);
263 static int test_util_uri(request_rec *r)
265 unsigned total_failures;
268 r->allowed |= (1 << M_GET);
269 if (r->method_number != M_GET)
272 r->content_type = "text/html";
276 ap_hard_timeout("test_util_uri", r);
284 <dd>entry number in the uri_tests array
286 <dd>fields under test
288 <dd>fields expected in the result
290 <dd>response from parse_uri_components, or 500 if unexpected results
292 <dd>the uri given to parse_uri_components
294 <p>The remaining fields are the pieces returned from parse_uri_components, and
295 the values we expected for each piece (resp.).
296 <p>Only failures are displayed.
298 <table><tr><th>row</th><th>u</th><th>expect</th><th>status</th><th>input uri</th>", r);
299 #define HEADER(f) ap_rprintf(r, "<th>" #f "<br>0x%02x</th>", T_##f)
312 total_failures = iterate_pieces(r, &uri_tests[i], i);
316 for (i = 0; i < sizeof(uri_tests) / sizeof(uri_tests[0]); ++i) {
317 total_failures += iterate_pieces(r, &uri_tests[i], i);
318 if (total_failures > 256) {
319 ap_rprintf(r, "</table>\n<b>Stopped early to save your browser "
320 "from certain death!</b>\nTOTAL FAILURES = %u\n",
326 ap_rprintf(r, "</table>\nTOTAL FAILURES = %u\n", total_failures);
331 static const handler_rec test_util_uri_handlers[] =
333 {"test-util-uri", test_util_uri},
337 module test_util_uri_module = {
338 STANDARD_MODULE_STUFF,
339 NULL, /* initializer */
340 NULL, /* dir config creater */
341 NULL, /* dir merger --- default is to override */
342 NULL, /* server config */
343 NULL, /* merge server config */
344 NULL, /* command apr_table_t */
345 test_util_uri_handlers, /* handlers */
346 NULL, /* filename translation */
347 NULL, /* check_user_id */
348 NULL, /* check auth */
349 NULL, /* check access */
350 NULL, /* type_checker */
353 NULL /* header parser */