]> granicus.if.org Git - apache/blob - modules/test/mod_test_util_uri.c
More cleanup.
[apache] / modules / test / mod_test_util_uri.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
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
17  *    distribution.
18  *
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.
25  *
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.
30  *
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.
34  *
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
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
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/>.
53  *
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.
57  */
58
59 /*
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
62  * see.
63  *
64  * Usage:
65  *
66  * <Location /test-util-uri>
67  * SetHandler test-util-uri
68  * </Location>
69  *
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.
72  */
73
74 #include "httpd.h"
75 #include "http_protocol.h"
76 #include "http_config.h"
77 #include "http_main.h"
78
79 typedef struct {
80     const char *scheme;
81     const char *user;
82     const char *password;
83     const char *hostname;
84     const char *port_str;
85     const char *path;
86     const char *query;
87     const char *fragment;
88 } test_uri_t;
89
90 #define T_scheme        0x01
91 #define T_user          0x02
92 #define T_password      0x04
93 #define T_hostname      0x08
94 #define T_port_str      0x10
95 #define T_path          0x20
96 #define T_query         0x40
97 #define T_fragment      0x80
98 #define T_MAX           0x100
99
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.
102  */
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" },
109 #if 0
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
114      * string.
115      *
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...
120      */
121     { "http", "userid", "passwd", "hostname.goes.here", "80", "", "query-here", "frag-here" },
122 #endif
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" }
126
127 };
128
129 static char *my_stpcpy(char *d, const char *s)
130 {
131     while((*d = *s)) {
132         ++d;
133         ++s;
134     }
135     return d;
136 }
137
138 /* return the number of failures */
139 static unsigned iterate_pieces(request_rec *r, const test_uri_t *pieces, int row)
140 {
141     unsigned u;
142     apr_pool_t *sub;
143     char *input_uri;
144     char *strp;
145     uri_components result;
146     unsigned expect;
147     int status;
148     unsigned failures;
149
150     failures = 0;
151
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
161         + 1);
162
163     for (u = 0; u < T_MAX; ++u) {
164         strp = input_uri;
165         expect = 0;
166
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)) {
170             expect |= T_scheme;
171             strp = my_stpcpy(strp, pieces->scheme);
172             *strp++ = ':';
173             *strp++ = '/';
174             *strp++ = '/';
175             /* can't have password without user */
176             if (u & (T_user|T_password)) {
177                 expect |= T_user;
178                 strp = my_stpcpy(strp, pieces->user);
179                 if (u & T_password) {
180                     expect |= T_password;
181                     *strp++ = ':';
182                     strp = my_stpcpy(strp, pieces->password);
183                 }
184                 *strp++ = '@';
185             }
186             expect |= T_hostname;
187             strp = my_stpcpy(strp, pieces->hostname);
188             if (u & T_port_str) {
189                 expect |= T_port_str;
190                 *strp++ = ':';
191                 strp = my_stpcpy(strp, pieces->port_str);
192             }
193         }
194         if (u & T_path) {
195             expect |= T_path;
196             strp = my_stpcpy(strp, pieces->path);
197         }
198         if (u & T_query) {
199             expect |= T_query;
200             *strp++ = '?';
201             strp = my_stpcpy(strp, pieces->query);
202         }
203         if (u & T_fragment) {
204             expect |= T_fragment;
205             *strp++ = '#';
206             strp = my_stpcpy(strp, pieces->fragment);
207         }
208         *strp = 0;
209
210         sub = apr_pool_sub_make(r->pool);
211         status = ap_parse_uri_components(sub, input_uri, &result);
212         if (status == HTTP_OK) {
213 #define CHECK(f)                                                        \
214             if ((expect & T_##f)                                        \
215                 && (result.f == NULL || strcmp(result.f, pieces->f))) { \
216                 status = HTTP_INTERNAL_SERVER_ERROR;                    \
217             }                                                           \
218             else if (!(expect & T_##f) && result.f != NULL) {           \
219                 status = HTTP_INTERNAL_SERVER_ERROR;                    \
220             }
221             CHECK(scheme)
222             CHECK(user)
223             CHECK(password)
224             CHECK(hostname)
225             CHECK(port_str)
226             CHECK(path)
227             CHECK(query)
228             CHECK(fragment)
229 #undef CHECK
230         }
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);
233 #define DUMP(f)                                                         \
234             if (result.f) {                                             \
235                 ap_rvputs(r, "<td>\"", result.f, "\"<br>", NULL);               \
236             }                                                           \
237             else {                                                      \
238                 ap_rputs("<td>NULL<br>", r);                            \
239             }                                                           \
240             if (expect & T_##f) {                                       \
241                 ap_rvputs(r, "\"", pieces->f, "\"</td>", NULL);         \
242             }                                                           \
243             else {                                                      \
244                 ap_rputs("NULL</td>", r);                                       \
245             }
246             DUMP(scheme);
247             DUMP(user);
248             DUMP(password);
249             DUMP(hostname);
250             DUMP(port_str);
251             DUMP(path);
252             DUMP(query);
253             DUMP(fragment);
254 #undef DUMP
255             ap_rputs("</tr>\n", r);
256             ++failures;
257         }
258         apr_pool_destroy(sub);
259     }
260     return failures;
261 }
262
263 static int test_util_uri(request_rec *r)
264 {
265     unsigned total_failures;
266     int i;
267
268     r->allowed |= (1 << M_GET);
269     if (r->method_number != M_GET)
270         return DECLINED;
271
272     r->content_type = "text/html";              
273     if(r->header_only) {
274         return 0;
275     }
276     ap_hard_timeout("test_util_uri", r);
277
278     ap_rputs(
279 DOCTYPE_HTML_2_0 "
280 <html><body>
281 <p>Key:
282 <dl>
283 <dt>row
284 <dd>entry number in the uri_tests array
285 <dt>u
286 <dd>fields under test
287 <dt>expected
288 <dd>fields expected in the result
289 <dt>status
290 <dd>response from parse_uri_components, or 500 if unexpected results
291 <dt>input uri
292 <dd>the uri given to parse_uri_components
293 </dl>
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.
297 <p>
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)
300     HEADER(scheme);
301     HEADER(user);
302     HEADER(password);
303     HEADER(hostname);
304     HEADER(port_str);
305     HEADER(path);
306     HEADER(query);
307     HEADER(fragment);
308 #undef HEADER
309
310     if (r->args) {
311         i = atoi(r->args);
312         total_failures = iterate_pieces(r, &uri_tests[i], i);
313     }
314     else {
315         total_failures = 0;
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",
321                            total_failures);
322                 return OK;
323             }
324         }
325     }
326     ap_rprintf(r, "</table>\nTOTAL FAILURES = %u\n", total_failures);
327
328     return OK;
329 }
330
331 static const handler_rec test_util_uri_handlers[] =
332 {
333     {"test-util-uri", test_util_uri},
334     {NULL}
335 };
336
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 */
351     NULL,                       /* fixups */
352     NULL,                       /* logger */
353     NULL                        /* header parser */
354 };