1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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"
19 const char *explanation;
21 const guint final_status;
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 },
31 static int ntests = sizeof (tests) / sizeof (tests[0]);
33 #define HTTP_SERVER "http://127.0.0.1:47524"
34 #define HTTPS_SERVER "https://127.0.0.1:47525"
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"
46 static const char *proxy_names[] = {
48 "authenticated proxy",
49 "unauthenticatable-to proxy"
53 authenticate (SoupSession *session, SoupMessage *msg,
54 SoupAuth *auth, gboolean retrying, gpointer data)
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");
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");
67 debug_printf (1, " got authenticate signal with status %d\n",
73 soup_auth_authenticate (auth, "user1", "realm1");
77 set_close_on_connect (SoupSession *session, SoupMessage *msg,
78 SoupSocket *sock, gpointer user_data)
80 /* This is used to test that we can handle the server closing
81 * the connection when returning a 407 in response to a
84 if (msg->method == SOUP_METHOD_CONNECT) {
85 soup_message_headers_append (msg->request_headers,
86 "Connection", "close");
92 test_url (const char *url, int proxy, guint expected,
93 gboolean sync, gboolean close)
99 if (!tls_available && g_str_has_prefix (url, "https:"))
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;
107 /* We create a new session for each request to ensure that
108 * connections/auth aren't cached between tests.
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,
114 soup_uri_free (proxy_uri);
115 g_signal_connect (session, "authenticate",
116 G_CALLBACK (authenticate), NULL);
118 g_signal_connect (session, "request-started",
119 G_CALLBACK (set_close_on_connect), NULL);
122 msg = soup_message_new (SOUP_METHOD_GET, url);
124 fprintf (stderr, "proxy-test: Could not parse URI\n");
128 soup_session_send_message (session, msg);
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);
136 g_object_unref (msg);
137 soup_test_session_abort_unref (session);
140 static GMainLoop *loop;
143 request_completed (GObject *source, GAsyncResult *result, gpointer user_data)
145 SoupRequest *req = SOUP_REQUEST (source);
146 GInputStream **stream_p = user_data;
147 GError *error = NULL;
149 debug_printf (2, " Request completed\n");
150 *stream_p = soup_request_send_finish (req, result, &error);
152 debug_printf (1, " Unexpected error on Request: %s\n",
155 g_error_free (error);
158 g_main_loop_quit (loop);
162 test_url_new_api (const char *url, int proxy, guint expected,
163 gboolean sync, gboolean close)
165 SoupSession *session;
168 SoupRequester *requester;
169 SoupRequest *request;
170 GInputStream *stream;
172 if (!tls_available && g_str_has_prefix (url, "https:"))
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;
180 /* We create a new session for each request to ensure that
181 * connections/auth aren't cached between tests.
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,
189 soup_uri_free (proxy_uri);
191 g_signal_connect (session, "authenticate",
192 G_CALLBACK (authenticate), NULL);
194 g_signal_connect (session, "request-started",
195 G_CALLBACK (set_close_on_connect), NULL);
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));
203 GError *error = NULL;
205 stream = soup_request_send (request, NULL, &error);
207 debug_printf (1, " Unexpected error on Request: %s\n",
210 g_error_free (error);
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);
220 g_input_stream_close (stream, NULL, NULL);
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);
228 g_object_unref (msg);
229 g_object_unref (request);
231 soup_test_session_abort_unref (session);
235 run_test (int i, gboolean sync)
237 char *http_url, *https_url;
239 debug_printf (1, "Test %d: %s (%s)\n", i + 1, tests[i].explanation,
240 sync ? "sync" : "async");
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);
246 http_url = g_strconcat (HTTP_SERVER, tests[i].url, NULL);
247 https_url = g_strconcat (HTTPS_SERVER, tests[i].url, NULL);
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);
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);
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);
270 debug_printf (1, "\n");
274 server_callback (SoupServer *server, SoupMessage *msg,
275 const char *path, GHashTable *query,
276 SoupClientContext *context, gpointer data)
278 SoupURI *uri = soup_message_get_uri (msg);
280 soup_message_set_status (msg, uri->fragment ? SOUP_STATUS_BAD_REQUEST : SOUP_STATUS_OK);
284 do_proxy_fragment_test (SoupURI *base_uri)
286 SoupSession *session;
287 SoupURI *proxy_uri, *req_uri;
290 debug_printf (1, "\nTesting request with fragment via proxy\n");
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,
296 soup_uri_free (proxy_uri);
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);
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);
309 g_object_unref (msg);
310 soup_test_session_abort_unref (session);
314 do_proxy_redirect_test (void)
316 SoupSession *session;
317 SoupURI *proxy_uri, *req_uri, *new_uri;
320 debug_printf (1, "\nTesting redirection through proxy\n");
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,
326 soup_uri_free (proxy_uri);
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);
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");
340 soup_uri_free (req_uri);
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);
348 g_object_unref (msg);
349 soup_test_session_abort_unref (session);
353 main (int argc, char **argv)
359 test_init (argc, argv, NULL);
362 for (i = 0; i < ntests; i++) {
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));
372 do_proxy_fragment_test (base_uri);
373 do_proxy_redirect_test ();
375 soup_uri_free (base_uri);
376 soup_test_server_quit_unref (server);