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