add missing slash in %configure
[platform/upstream/libsoup.git] / tests / proxy-test.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 #include "test-utils.h"
4
5 typedef struct {
6         const char *explanation;
7         const char *url;
8         const guint final_status;
9         const char *bugref;
10 } SoupProxyTest;
11
12 static SoupProxyTest tests[] = {
13         { "GET -> 200", "", SOUP_STATUS_OK, NULL },
14         { "GET -> 404", "/not-found", SOUP_STATUS_NOT_FOUND, NULL },
15         { "GET -> 401 -> 200", "/Basic/realm1/", SOUP_STATUS_OK, NULL },
16         { "GET -> 401 -> 401", "/Basic/realm2/", SOUP_STATUS_UNAUTHORIZED, NULL },
17         { "GET -> 403", "http://no-such-hostname.xx/", SOUP_STATUS_FORBIDDEN, "577532" },
18         { "GET -> 200 (unproxied)", "http://localhost:47524/", SOUP_STATUS_OK, "700472" },
19 };
20 static const int ntests = sizeof (tests) / sizeof (tests[0]);
21
22 #define HTTP_SERVER    "http://127.0.0.1:47524"
23 #define HTTPS_SERVER   "https://127.0.0.1:47525"
24
25 enum {
26         SIMPLE_PROXY,
27         AUTH_PROXY,
28         UNAUTH_PROXY
29 };
30 static const char *proxies[] = {
31         "http://127.0.0.1:47526",
32         "http://127.0.0.1:47527",
33         "http://127.0.0.1:47528"
34 };
35 static const char *proxy_names[] = {
36         "simple proxy",
37         "authenticated proxy",
38         "unauthenticatable-to proxy"
39 };
40 static GProxyResolver *proxy_resolvers[3];
41 static const char *ignore_hosts[] = { "localhost", NULL };
42
43 static void
44 authenticate (SoupSession *session, SoupMessage *msg,
45               SoupAuth *auth, gboolean retrying, gpointer data)
46 {
47         if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
48                 soup_test_assert (!soup_auth_is_for_proxy (auth),
49                                   "got proxy auth object for 401");
50         } else if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) {
51                 soup_test_assert (soup_auth_is_for_proxy (auth),
52                                   "got regular auth object for 407");
53         } else {
54                 soup_test_assert (FALSE,
55                                   "got authenticate signal with status %d\n",
56                                   msg->status_code);
57         }
58
59         if (!retrying)
60                 soup_auth_authenticate (auth, "user1", "realm1");
61 }
62
63 static void
64 set_close_on_connect (SoupSession *session, SoupMessage *msg,
65                       SoupSocket *sock, gpointer user_data)
66 {
67         /* This is used to test that we can handle the server closing
68          * the connection when returning a 407 in response to a
69          * CONNECT. (Rude!)
70          */
71         if (msg->method == SOUP_METHOD_CONNECT) {
72                 soup_message_headers_append (msg->request_headers,
73                                              "Connection", "close");
74         }
75 }
76
77
78 static void
79 test_url (const char *url, int proxy, guint expected,
80           gboolean sync, gboolean close)
81 {
82         SoupSession *session;
83         SoupMessage *msg;
84         gboolean noproxy = !!strstr (url, "localhost");
85
86         if (!tls_available && g_str_has_prefix (url, "https:"))
87                 return;
88
89         debug_printf (1, "  GET %s via %s%s\n", url, proxy_names[proxy],
90                       close ? " (with Connection: close)" : "");
91         if (proxy == UNAUTH_PROXY && expected != SOUP_STATUS_FORBIDDEN && !noproxy)
92                 expected = SOUP_STATUS_PROXY_UNAUTHORIZED;
93
94         /* We create a new session for each request to ensure that
95          * connections/auth aren't cached between tests.
96          */
97         session = soup_test_session_new (sync ? SOUP_TYPE_SESSION_SYNC : SOUP_TYPE_SESSION_ASYNC,
98                                          SOUP_SESSION_PROXY_RESOLVER, proxy_resolvers[proxy],
99                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
100                                          SOUP_SESSION_SSL_STRICT, FALSE,
101                                          NULL);
102         g_signal_connect (session, "authenticate",
103                           G_CALLBACK (authenticate), NULL);
104         if (close) {
105                 /* FIXME g_test_bug ("611663") */
106                 g_signal_connect (session, "request-started",
107                                   G_CALLBACK (set_close_on_connect), NULL);
108         }
109
110         msg = soup_message_new (SOUP_METHOD_GET, url);
111         if (!msg) {
112                 g_printerr ("proxy-test: Could not parse URI\n");
113                 exit (1);
114         }
115
116         soup_session_send_message (session, msg);
117
118         debug_printf (1, "  %d %s\n", msg->status_code, msg->reason_phrase);
119         soup_test_assert_message_status (msg, expected);
120
121         g_object_unref (msg);
122         soup_test_session_abort_unref (session);
123 }
124
125 static void
126 test_url_new_api (const char *url, int proxy, guint expected,
127                   gboolean sync, gboolean close)
128 {
129         SoupSession *session;
130         SoupMessage *msg;
131         SoupRequest *request;
132         GInputStream *stream;
133         GError *error = NULL;
134         gboolean noproxy = !!strstr (url, "localhost");
135
136         /* FIXME g_test_skip() FIXME g_test_bug ("675865") */
137         if (!tls_available && g_str_has_prefix (url, "https:"))
138                 return;
139
140         debug_printf (1, "  GET (request API) %s via %s%s\n", url, proxy_names[proxy],
141                       close ? " (with Connection: close)" : "");
142         if (proxy == UNAUTH_PROXY && expected != SOUP_STATUS_FORBIDDEN && !noproxy)
143                 expected = SOUP_STATUS_PROXY_UNAUTHORIZED;
144
145         /* We create a new session for each request to ensure that
146          * connections/auth aren't cached between tests.
147          */
148         session = soup_test_session_new (sync ? SOUP_TYPE_SESSION_SYNC : SOUP_TYPE_SESSION_ASYNC,
149                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
150                                          SOUP_SESSION_PROXY_RESOLVER, proxy_resolvers[proxy],
151                                          SOUP_SESSION_SSL_STRICT, FALSE,
152                                          NULL);
153
154         g_signal_connect (session, "authenticate",
155                           G_CALLBACK (authenticate), NULL);
156         if (close) {
157                 /* FIXME g_test_bug ("611663") */
158                 g_signal_connect (session, "request-started",
159                                   G_CALLBACK (set_close_on_connect), NULL);
160         }
161
162         request = soup_session_request (session, url, NULL);
163         msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
164
165         stream = soup_test_request_send (request, NULL, 0, &error);
166         g_assert_no_error (error);
167         g_clear_error (&error);
168
169         if (stream) {
170                 soup_test_request_close_stream (request, stream, NULL, &error);
171                 g_assert_no_error (error);
172                 g_clear_error (&error);
173                 g_object_unref (stream);
174         }
175
176         debug_printf (1, "  %d %s\n", msg->status_code, msg->reason_phrase);
177         soup_test_assert_message_status (msg, expected);
178
179         g_object_unref (msg);
180         g_object_unref (request);
181
182         soup_test_session_abort_unref (session);
183 }
184
185 static void
186 do_proxy_test (SoupProxyTest *test, gboolean sync)
187 {
188         char *http_url, *https_url;
189
190         if (test->bugref)
191                 g_test_bug (test->bugref);
192
193         if (!strncmp (test->url, "http", 4)) {
194                 SoupURI *uri;
195                 guint port;
196
197                 http_url = g_strdup (test->url);
198
199                 uri = soup_uri_new (test->url);
200                 port = uri->port;
201                 soup_uri_set_scheme (uri, "https");
202                 if (port)
203                         soup_uri_set_port (uri, port + 1);
204                 https_url = soup_uri_to_string (uri, FALSE);
205                 soup_uri_free (uri);
206         } else {
207                 http_url = g_strconcat (HTTP_SERVER, test->url, NULL);
208                 https_url = g_strconcat (HTTPS_SERVER, test->url, NULL);
209         }
210
211         test_url (http_url, SIMPLE_PROXY, test->final_status, sync, FALSE);
212         test_url_new_api (http_url, SIMPLE_PROXY, test->final_status, sync, FALSE);
213         test_url (https_url, SIMPLE_PROXY, test->final_status, sync, FALSE);
214         test_url_new_api (https_url, SIMPLE_PROXY, test->final_status, sync, FALSE);
215
216         test_url (http_url, AUTH_PROXY, test->final_status, sync, FALSE);
217         test_url_new_api (http_url, AUTH_PROXY, test->final_status, sync, FALSE);
218         test_url (https_url, AUTH_PROXY, test->final_status, sync, FALSE);
219         test_url_new_api (https_url, AUTH_PROXY, test->final_status, sync, FALSE);
220         test_url (https_url, AUTH_PROXY, test->final_status, sync, TRUE);
221         test_url_new_api (https_url, AUTH_PROXY, test->final_status, sync, TRUE);
222
223         test_url (http_url, UNAUTH_PROXY, test->final_status, sync, FALSE);
224         test_url_new_api (http_url, UNAUTH_PROXY, test->final_status, sync, FALSE);
225         test_url (https_url, UNAUTH_PROXY, test->final_status, sync, FALSE);
226         test_url_new_api (https_url, UNAUTH_PROXY, test->final_status, sync, FALSE);
227
228         g_free (http_url);
229         g_free (https_url);
230 }
231
232 static void
233 do_async_proxy_test (gconstpointer data)
234 {
235         SoupProxyTest *test = (SoupProxyTest *)data;
236
237         SOUP_TEST_SKIP_IF_NO_APACHE;
238
239         do_proxy_test (test, FALSE);
240 }
241
242 static void
243 do_sync_proxy_test (gconstpointer data)
244 {
245         SoupProxyTest *test = (SoupProxyTest *)data;
246
247         SOUP_TEST_SKIP_IF_NO_APACHE;
248
249         do_proxy_test (test, TRUE);
250 }
251
252 static void
253 server_callback (SoupServer *server, SoupMessage *msg,
254                  const char *path, GHashTable *query,
255                  SoupClientContext *context, gpointer data)
256 {
257         SoupURI *uri = soup_message_get_uri (msg);
258
259         soup_message_set_status (msg, uri->fragment ? SOUP_STATUS_BAD_REQUEST : SOUP_STATUS_OK);
260 }
261
262 static void
263 do_proxy_fragment_test (gconstpointer data)
264 {
265         SoupURI *base_uri = (SoupURI *)data;
266         SoupSession *session;
267         SoupURI *proxy_uri, *req_uri;
268         SoupMessage *msg;
269
270         SOUP_TEST_SKIP_IF_NO_APACHE;
271
272         proxy_uri = soup_uri_new (proxies[SIMPLE_PROXY]);
273         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
274                                          SOUP_SESSION_PROXY_URI, proxy_uri,
275                                          NULL);
276         soup_uri_free (proxy_uri);
277
278         req_uri = soup_uri_new_with_base (base_uri, "/#foo");
279         msg = soup_message_new_from_uri (SOUP_METHOD_GET, req_uri);
280         soup_uri_free (req_uri);
281         soup_session_send_message (session, msg);
282
283         soup_test_assert_message_status (msg, SOUP_STATUS_OK);
284
285         g_object_unref (msg);
286         soup_test_session_abort_unref (session);
287 }
288
289 static void
290 do_proxy_redirect_test (void)
291 {
292         SoupSession *session;
293         SoupURI *proxy_uri, *req_uri, *new_uri;
294         SoupMessage *msg;
295
296         g_test_bug ("631368");
297
298         SOUP_TEST_SKIP_IF_NO_APACHE;
299         SOUP_TEST_SKIP_IF_NO_TLS;
300
301         proxy_uri = soup_uri_new (proxies[SIMPLE_PROXY]);
302         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
303                                          SOUP_SESSION_PROXY_URI, proxy_uri,
304                                          NULL);
305         soup_uri_free (proxy_uri);
306
307         req_uri = soup_uri_new (HTTPS_SERVER);
308         soup_uri_set_path (req_uri, "/redirected");
309         msg = soup_message_new_from_uri (SOUP_METHOD_GET, req_uri);
310         soup_message_headers_append (msg->request_headers,
311                                      "Connection", "close");
312         soup_session_send_message (session, msg);
313
314         new_uri = soup_message_get_uri (msg);
315         soup_test_assert (strcmp (req_uri->path, new_uri->path) != 0,
316                           "message was not redirected");
317         soup_uri_free (req_uri);
318
319         soup_test_assert_message_status (msg, SOUP_STATUS_OK);
320
321         g_object_unref (msg);
322         soup_test_session_abort_unref (session);
323 }
324
325 int
326 main (int argc, char **argv)
327 {
328         SoupServer *server;
329         SoupURI *base_uri;
330         char *path;
331         int i, ret;
332
333         test_init (argc, argv, NULL);
334         apache_init ();
335
336         for (i = 0; i < 3; i++) {
337                 proxy_resolvers[i] =
338                         g_simple_proxy_resolver_new (proxies[i], (char **) ignore_hosts);
339         }
340
341         server = soup_test_server_new (TRUE);
342         soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
343         base_uri = soup_uri_new ("http://127.0.0.1/");
344         soup_uri_set_port (base_uri, soup_server_get_port (server));
345
346         for (i = 0; i < ntests; i++) {
347                 path = g_strdup_printf ("/proxy/async/%s", tests[i].explanation);
348                 g_test_add_data_func (path, &tests[i], do_async_proxy_test);
349                 g_free (path);
350         }
351         for (i = 0; i < ntests; i++) {
352                 path = g_strdup_printf ("/proxy/sync/%s", tests[i].explanation);
353                 g_test_add_data_func (path, &tests[i], do_sync_proxy_test);
354                 g_free (path);
355         }
356
357         g_test_add_data_func ("/proxy/fragment", base_uri, do_proxy_fragment_test);
358         g_test_add_func ("/proxy/redirect", do_proxy_redirect_test);
359
360         ret = g_test_run ();
361
362         soup_uri_free (base_uri);
363         soup_test_server_quit_unref (server);
364
365         test_cleanup ();
366         return ret;
367 }