1/*
2   Tests for 3xx redirect interface (ne_redirect.h)
3   Copyright (C) 2002-2003, Joe Orton <joe@manyfish.co.uk>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19*/
20
21#include "config.h"
22
23#include <sys/types.h>
24
25#ifdef HAVE_STDLIB_H
26#include <stdlib.h>
27#endif
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31
32#include "ne_redirect.h"
33
34#include "tests.h"
35#include "child.h"
36#include "utils.h"
37
38struct redir_args {
39    int code;
40    const char *dest;
41    const char *path;
42};
43
44static int serve_redir(ne_socket *sock, void *ud)
45{
46    struct redir_args *args = ud;
47    char buf[BUFSIZ];
48
49    CALL(discard_request(sock));
50
51    ne_snprintf(buf, BUFSIZ,
52		"HTTP/1.0 %d Get Ye Away\r\n"
53		"Content-Length: 0\r\n"
54		"Location: %s\r\n\n",
55		args->code, args->dest);
56
57    SEND_STRING(sock, buf);
58
59    return OK;
60}
61
62/* Run a request to 'path' and retrieve the redirect destination to
63 * *redir. */
64static int process_redir(ne_session *sess, const char *path,
65                         const ne_uri **redir)
66{
67    ONN("did not get NE_REDIRECT", any_request(sess, path) != NE_REDIRECT);
68    *redir = ne_redirect_location(sess);
69    return OK;
70}
71
72static int check_redir(struct redir_args *args, const char *expect)
73{
74    ne_session *sess;
75    const ne_uri *loc;
76    char *unp;
77
78    CALL(make_session(&sess, serve_redir, args));
79    ne_redirect_register(sess);
80
81    CALL(process_redir(sess, args->path, &loc));
82    ONN("redirect location was NULL", loc == NULL);
83
84    unp = ne_uri_unparse(loc);
85    ONV(strcmp(unp, expect), ("redirected to `%s' not `%s'", unp, expect));
86    ne_free(unp);
87
88    ne_session_destroy(sess);
89    CALL(await_server());
90
91    return OK;
92}
93
94#define DEST "http://foo.com/blah/blah/bar"
95#define PATH "/redir/me"
96
97static int simple(void)
98{
99    struct redir_args args[] = {
100        {301, DEST, PATH},
101        {302, DEST, PATH},
102        {303, DEST, PATH},
103        {307, DEST, PATH},
104        {0, NULL, NULL}
105    };
106    int n;
107
108    for (n = 0; args[n].code; n++)
109        CALL(check_redir(&args[n], DEST));
110
111    return OK;
112}
113
114/* check that a non-absoluteURI is qualified properly */
115static int non_absolute(void)
116{
117    struct redir_args args = {302, "/foo/bar/blah", PATH};
118    return check_redir(&args, "http://localhost:7777/foo/bar/blah");
119}
120
121static int relative_1(void)
122{
123    struct redir_args args = {302, "norman", "/foo/bar"};
124    return check_redir(&args, "http://localhost:7777/foo/norman");
125}
126
127static int relative_2(void)
128{
129    struct redir_args args = {302, "wishbone", "/foo/bar/"};
130    return check_redir(&args, "http://localhost:7777/foo/bar/wishbone");
131}
132
133#if 0
134/* could implement failure on self-referential redirects, but
135 * realistically, the application must implement a max-redirs count
136 * check, so it's kind of redundant.  Mozilla takes this approach. */
137static int fail_loop(void)
138{
139    ne_session *sess;
140
141    CALL(make_session(&sess, serve_redir, "http://localhost:7777/foo/bar"));
142
143    ne_redirect_register(sess);
144
145    ONN("followed looping redirect",
146	any_request(sess, "/foo/bar") != NE_ERROR);
147
148    ne_session_destroy(sess);
149    return OK;
150}
151#endif
152
153/* ensure that ne_redirect_location returns NULL when no redirect has
154 * been encountered, or redirect hooks aren't registered. */
155static int no_redirect(void)
156{
157    ne_session *sess = ne_session_create("http", "localhost", 7777);
158    const ne_uri *loc;
159
160    ONN("redirect non-NULL before register", ne_redirect_location(sess));
161    ne_redirect_register(sess);
162    ONN("initial redirect non-NULL", ne_redirect_location(sess));
163
164    CALL(spawn_server(7777, single_serve_string,
165                      "HTTP/1.0 200 OK\r\n\r\n\r\n"));
166    ONREQ(any_request(sess, "/noredir"));
167    CALL(await_server());
168
169    ONN("redirect non-NULL after non-redir req", ne_redirect_location(sess));
170
171    CALL(spawn_server(7777, single_serve_string, "HTTP/1.0 302 Get Ye Away\r\n"
172                      "Location: /blah\r\n" "\r\n"));
173    CALL(process_redir(sess, "/foo", &loc));
174    CALL(await_server());
175
176    ne_session_destroy(sess);
177    return OK;
178}
179
180ne_test tests[] = {
181    T(lookup_localhost),
182    T(simple),
183    T(non_absolute),
184    T(relative_1),
185    T(relative_2),
186    T(no_redirect),
187    T(NULL)
188};
189
190