1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 #include "test-utils.h"
6 const char *explanation;
8 const guint final_status;
11 static SoupProxyTest tests[] = {
12 { "GET -> 200", "", SOUP_STATUS_OK },
13 { "GET -> 404", "/not-found", SOUP_STATUS_NOT_FOUND },
14 { "GET -> 401 -> 200", "/Basic/realm1/", SOUP_STATUS_OK },
15 { "GET -> 401 -> 401", "/Basic/realm2/", SOUP_STATUS_UNAUTHORIZED },
16 { "GET -> 403", "http://no-such-hostname.xx/", SOUP_STATUS_FORBIDDEN },
18 static const int ntests = sizeof (tests) / sizeof (tests[0]);
20 #define HTTP_SERVER "http://127.0.0.1:47524"
21 #define HTTPS_SERVER "https://127.0.0.1:47525"
28 static const char *proxies[] = {
29 "http://127.0.0.1:47526",
30 "http://127.0.0.1:47527",
31 "http://127.0.0.1:47528"
33 static const char *proxy_names[] = {
35 "authenticated proxy",
36 "unauthenticatable-to proxy"
40 authenticate (SoupSession *session, SoupMessage *msg,
41 SoupAuth *auth, gboolean retrying, gpointer data)
43 if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
44 if (soup_auth_is_for_proxy (auth)) {
45 debug_printf (1, " got proxy auth object for 401!\n");
48 } else if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) {
49 if (!soup_auth_is_for_proxy (auth)) {
50 debug_printf (1, " got regular auth object for 407!\n");
54 debug_printf (1, " got authenticate signal with status %d\n",
60 soup_auth_authenticate (auth, "user1", "realm1");
64 set_close_on_connect (SoupSession *session, SoupMessage *msg,
65 SoupSocket *sock, gpointer user_data)
67 /* This is used to test that we can handle the server closing
68 * the connection when returning a 407 in response to a
71 if (msg->method == SOUP_METHOD_CONNECT) {
72 soup_message_headers_append (msg->request_headers,
73 "Connection", "close");
79 test_url (const char *url, int proxy, guint expected,
80 gboolean sync, gboolean close)
86 if (!tls_available && g_str_has_prefix (url, "https:"))
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)
92 expected = SOUP_STATUS_PROXY_UNAUTHORIZED;
94 /* We create a new session for each request to ensure that
95 * connections/auth aren't cached between tests.
97 proxy_uri = soup_uri_new (proxies[proxy]);
98 session = soup_test_session_new (sync ? SOUP_TYPE_SESSION_SYNC : SOUP_TYPE_SESSION_ASYNC,
99 SOUP_SESSION_PROXY_URI, proxy_uri,
100 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
102 soup_uri_free (proxy_uri);
103 g_signal_connect (session, "authenticate",
104 G_CALLBACK (authenticate), NULL);
106 g_signal_connect (session, "request-started",
107 G_CALLBACK (set_close_on_connect), NULL);
110 msg = soup_message_new (SOUP_METHOD_GET, url);
112 g_printerr ("proxy-test: Could not parse URI\n");
116 soup_session_send_message (session, msg);
118 debug_printf (1, " %d %s\n", msg->status_code, msg->reason_phrase);
119 if (msg->status_code != expected) {
120 debug_printf (1, " EXPECTED %d!\n", expected);
124 g_object_unref (msg);
125 soup_test_session_abort_unref (session);
129 test_url_new_api (const char *url, int proxy, guint expected,
130 gboolean sync, gboolean close)
132 SoupSession *session;
135 SoupRequester *requester;
136 SoupRequest *request;
137 GInputStream *stream;
138 GError *error = NULL;
140 if (!tls_available && g_str_has_prefix (url, "https:"))
143 debug_printf (1, " GET (requester API) %s via %s%s\n", url, proxy_names[proxy],
144 close ? " (with Connection: close)" : "");
145 if (proxy == UNAUTH_PROXY && expected != SOUP_STATUS_FORBIDDEN)
146 expected = SOUP_STATUS_PROXY_UNAUTHORIZED;
148 /* We create a new session for each request to ensure that
149 * connections/auth aren't cached between tests.
151 proxy_uri = soup_uri_new (proxies[proxy]);
152 session = soup_test_session_new (sync ? SOUP_TYPE_SESSION_SYNC : SOUP_TYPE_SESSION_ASYNC,
153 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
154 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
155 SOUP_SESSION_PROXY_URI, proxy_uri,
157 soup_uri_free (proxy_uri);
159 g_signal_connect (session, "authenticate",
160 G_CALLBACK (authenticate), NULL);
162 g_signal_connect (session, "request-started",
163 G_CALLBACK (set_close_on_connect), NULL);
166 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
167 request = soup_requester_request (requester, url, NULL);
168 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
170 stream = soup_test_request_send (request, NULL, &error);
172 debug_printf (1, " Unexpected error on Request: %s\n",
175 g_clear_error (&error);
179 soup_test_request_close_stream (request, stream, NULL, NULL);
181 debug_printf (1, " Unexpected error on close: %s\n",
184 g_clear_error (&error);
186 g_object_unref (stream);
189 debug_printf (1, " %d %s\n", msg->status_code, msg->reason_phrase);
190 if (msg->status_code != expected) {
191 debug_printf (1, " EXPECTED %d!\n", expected);
195 g_object_unref (msg);
196 g_object_unref (request);
198 soup_test_session_abort_unref (session);
202 run_test (int i, gboolean sync)
204 char *http_url, *https_url;
206 debug_printf (1, "Test %d: %s (%s)\n", i + 1, tests[i].explanation,
207 sync ? "sync" : "async");
209 if (!strncmp (tests[i].url, "http", 4)) {
210 http_url = g_strdup (tests[i].url);
211 https_url = g_strdup_printf ("https%s", tests[i].url + 4);
213 http_url = g_strconcat (HTTP_SERVER, tests[i].url, NULL);
214 https_url = g_strconcat (HTTPS_SERVER, tests[i].url, NULL);
217 test_url (http_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE);
218 test_url_new_api (http_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE);
219 test_url (https_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE);
220 test_url_new_api (https_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE);
222 test_url (http_url, AUTH_PROXY, tests[i].final_status, sync, FALSE);
223 test_url_new_api (http_url, AUTH_PROXY, tests[i].final_status, sync, FALSE);
224 test_url (https_url, AUTH_PROXY, tests[i].final_status, sync, FALSE);
225 test_url_new_api (https_url, AUTH_PROXY, tests[i].final_status, sync, FALSE);
226 test_url (https_url, AUTH_PROXY, tests[i].final_status, sync, TRUE);
227 test_url_new_api (https_url, AUTH_PROXY, tests[i].final_status, sync, TRUE);
229 test_url (http_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE);
230 test_url_new_api (http_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE);
231 test_url (https_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE);
232 test_url_new_api (https_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE);
237 debug_printf (1, "\n");
241 async_proxy_test_thread (gpointer num)
243 GMainContext *context = g_main_context_new ();
245 g_main_context_push_thread_default (context);
246 run_test (GPOINTER_TO_INT (num), FALSE);
247 g_main_context_pop_thread_default (context);
248 g_main_context_unref (context);
254 sync_proxy_test_thread (gpointer num)
256 run_test (GPOINTER_TO_INT (num), TRUE);
261 do_proxy_tests (void)
265 debug_printf (1, "Basic proxy tests\n");
268 GThread *threads[ntests];
270 /* Doing the sync and async tests separately is faster
271 * than doing them both at the same time (hitting
272 * apache's connection limit maybe?)
274 for (i = 0; i < ntests; i++) {
275 threads[i] = g_thread_new ("async_proxy_test",
276 async_proxy_test_thread,
277 GINT_TO_POINTER (i));
279 for (i = 0; i < ntests; i++)
280 g_thread_join (threads[i]);
282 for (i = 0; i < ntests; i++) {
283 threads[i] = g_thread_new ("sync_proxy_test",
284 sync_proxy_test_thread,
285 GINT_TO_POINTER (i));
287 for (i = 0; i < ntests; i++)
288 g_thread_join (threads[i]);
290 for (i = 0; i < ntests; i++) {
298 server_callback (SoupServer *server, SoupMessage *msg,
299 const char *path, GHashTable *query,
300 SoupClientContext *context, gpointer data)
302 SoupURI *uri = soup_message_get_uri (msg);
304 soup_message_set_status (msg, uri->fragment ? SOUP_STATUS_BAD_REQUEST : SOUP_STATUS_OK);
308 do_proxy_fragment_test (SoupURI *base_uri)
310 SoupSession *session;
311 SoupURI *proxy_uri, *req_uri;
314 debug_printf (1, "\nTesting request with fragment via proxy\n");
316 proxy_uri = soup_uri_new (proxies[SIMPLE_PROXY]);
317 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
318 SOUP_SESSION_PROXY_URI, proxy_uri,
320 soup_uri_free (proxy_uri);
322 req_uri = soup_uri_new_with_base (base_uri, "/#foo");
323 msg = soup_message_new_from_uri (SOUP_METHOD_GET, req_uri);
324 soup_uri_free (req_uri);
325 soup_session_send_message (session, msg);
327 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
328 debug_printf (1, " unexpected status %d %s!\n",
329 msg->status_code, msg->reason_phrase);
333 g_object_unref (msg);
334 soup_test_session_abort_unref (session);
338 do_proxy_redirect_test (void)
340 SoupSession *session;
341 SoupURI *proxy_uri, *req_uri, *new_uri;
344 debug_printf (1, "\nTesting redirection through proxy\n");
346 proxy_uri = soup_uri_new (proxies[SIMPLE_PROXY]);
347 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
348 SOUP_SESSION_PROXY_URI, proxy_uri,
350 soup_uri_free (proxy_uri);
352 req_uri = soup_uri_new (HTTPS_SERVER);
353 soup_uri_set_path (req_uri, "/redirected");
354 msg = soup_message_new_from_uri (SOUP_METHOD_GET, req_uri);
355 soup_message_headers_append (msg->request_headers,
356 "Connection", "close");
357 soup_session_send_message (session, msg);
359 new_uri = soup_message_get_uri (msg);
360 if (!strcmp (req_uri->path, new_uri->path)) {
361 debug_printf (1, " message was not redirected!\n");
364 soup_uri_free (req_uri);
366 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
367 debug_printf (1, " unexpected status %d %s!\n",
368 msg->status_code, msg->reason_phrase);
372 g_object_unref (msg);
373 soup_test_session_abort_unref (session);
377 main (int argc, char **argv)
382 test_init (argc, argv, NULL);
385 server = soup_test_server_new (TRUE);
386 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
387 base_uri = soup_uri_new ("http://127.0.0.1/");
388 soup_uri_set_port (base_uri, soup_server_get_port (server));
391 do_proxy_fragment_test (base_uri);
392 do_proxy_redirect_test ();
394 soup_uri_free (base_uri);
395 soup_test_server_quit_unref (server);