• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright 2007-2012 Red Hat, Inc.
4  */
5 
6 #include "test-utils.h"
7 
8 #include <gio/gnetworking.h>
9 
10 typedef struct {
11 	SoupServer *server;
12 	SoupURI *base_uri, *ssl_base_uri;
13 	GSList *handlers;
14 } ServerData;
15 
16 static void
server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)17 server_callback (SoupServer *server, SoupMessage *msg,
18 		 const char *path, GHashTable *query,
19 		 SoupClientContext *context, gpointer data)
20 {
21 	soup_message_headers_append (msg->response_headers,
22 				     "X-Handled-By", "server_callback");
23 
24 	if (!strcmp (path, "*")) {
25 		soup_test_assert (FALSE, "default server_callback got request for '*'");
26 		soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
27 		return;
28 	}
29 
30 	if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
31 		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
32 		return;
33 	}
34 
35 	soup_message_set_status (msg, SOUP_STATUS_OK);
36 	soup_message_set_response (msg, "text/plain",
37 				   SOUP_MEMORY_STATIC, "index", 5);
38 }
39 
40 static void
server_setup_nohandler(ServerData * sd,gconstpointer test_data)41 server_setup_nohandler (ServerData *sd, gconstpointer test_data)
42 {
43 	sd->server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
44 	sd->base_uri = soup_test_server_get_uri (sd->server, "http", NULL);
45 	if (tls_available)
46 		sd->ssl_base_uri = soup_test_server_get_uri (sd->server, "https", NULL);
47 }
48 
49 static void
server_add_handler(ServerData * sd,const char * path,SoupServerCallback callback,gpointer user_data,GDestroyNotify destroy)50 server_add_handler (ServerData         *sd,
51 		    const char         *path,
52 		    SoupServerCallback  callback,
53 		    gpointer            user_data,
54 		    GDestroyNotify      destroy)
55 {
56 	soup_server_add_handler (sd->server, path, callback, user_data, destroy);
57 	sd->handlers = g_slist_prepend (sd->handlers, g_strdup (path));
58 }
59 
60 static void
server_add_early_handler(ServerData * sd,const char * path,SoupServerCallback callback,gpointer user_data,GDestroyNotify destroy)61 server_add_early_handler (ServerData         *sd,
62 			  const char         *path,
63 			  SoupServerCallback  callback,
64 			  gpointer            user_data,
65 			  GDestroyNotify      destroy)
66 {
67 	soup_server_add_early_handler (sd->server, path, callback, user_data, destroy);
68 	sd->handlers = g_slist_prepend (sd->handlers, g_strdup (path));
69 }
70 
71 static void
server_setup(ServerData * sd,gconstpointer test_data)72 server_setup (ServerData *sd, gconstpointer test_data)
73 {
74 	server_setup_nohandler (sd, test_data);
75 	server_add_handler (sd, NULL, server_callback, NULL, NULL);
76 }
77 
78 static void
server_teardown(ServerData * sd,gconstpointer test_data)79 server_teardown (ServerData *sd, gconstpointer test_data)
80 {
81 	GSList *iter;
82 
83 	for (iter = sd->handlers; iter; iter = iter->next)
84 		soup_server_remove_handler (sd->server, iter->data);
85 	g_slist_free_full (sd->handlers, g_free);
86 
87 	g_clear_pointer (&sd->server, soup_test_server_quit_unref);
88 	g_clear_pointer (&sd->base_uri, soup_uri_free);
89 	g_clear_pointer (&sd->ssl_base_uri, soup_uri_free);
90 }
91 
92 static void
server_star_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)93 server_star_callback (SoupServer *server, SoupMessage *msg,
94 		      const char *path, GHashTable *query,
95 		      SoupClientContext *context, gpointer data)
96 {
97 	soup_message_headers_append (msg->response_headers,
98 				     "X-Handled-By", "star_callback");
99 
100 	if (strcmp (path, "*") != 0) {
101 		soup_test_assert (FALSE, "server_star_callback got request for '%s'", path);
102 		soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
103 		return;
104 	}
105 
106 	if (msg->method != SOUP_METHOD_OPTIONS) {
107 		soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
108 		return;
109 	}
110 
111 	soup_message_set_status (msg, SOUP_STATUS_OK);
112 }
113 
114 /* Server handlers for "*" work but are separate from handlers for
115  * all other URIs. #590751
116  */
117 static void
do_star_test(ServerData * sd,gconstpointer test_data)118 do_star_test (ServerData *sd, gconstpointer test_data)
119 {
120 	SoupSession *session;
121 	SoupMessage *msg;
122 	SoupURI *star_uri;
123 	const char *handled_by;
124 
125 	g_test_bug ("590751");
126 
127 	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
128 	star_uri = soup_uri_copy (sd->base_uri);
129 	soup_uri_set_path (star_uri, "*");
130 
131 	debug_printf (1, "  Testing with no handler\n");
132 	msg = soup_message_new_from_uri ("OPTIONS", star_uri);
133 	soup_session_send_message (session, msg);
134 
135 	soup_test_assert_message_status (msg, SOUP_STATUS_NOT_FOUND);
136 	handled_by = soup_message_headers_get_one (msg->response_headers,
137 						   "X-Handled-By");
138 	g_assert_cmpstr (handled_by, ==, NULL);
139 	g_object_unref (msg);
140 
141 	server_add_handler (sd, "*", server_star_callback, NULL, NULL);
142 
143 	debug_printf (1, "  Testing with handler\n");
144 	msg = soup_message_new_from_uri ("OPTIONS", star_uri);
145 	soup_session_send_message (session, msg);
146 
147 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
148 	handled_by = soup_message_headers_get_one (msg->response_headers,
149 						   "X-Handled-By");
150 	g_assert_cmpstr (handled_by, ==, "star_callback");
151 	g_object_unref (msg);
152 
153 	soup_test_session_abort_unref (session);
154 	soup_uri_free (star_uri);
155 }
156 
157 static void
do_one_server_aliases_test(SoupURI * uri,const char * alias,gboolean succeed)158 do_one_server_aliases_test (SoupURI    *uri,
159 			    const char *alias,
160 			    gboolean    succeed)
161 {
162 	GSocketClient *client;
163 	GSocketConnectable *addr;
164 	GSocketConnection *conn;
165 	GInputStream *in;
166 	GOutputStream *out;
167 	GError *error = NULL;
168 	GString *req;
169 	static char buf[1024];
170 
171 	debug_printf (1, "  %s via %s\n", alias, uri->scheme);
172 
173 	/* There's no way to make libsoup's client side send an absolute
174 	 * URI (to a non-proxy server), so we have to fake this.
175 	 */
176 
177 	client = g_socket_client_new ();
178 	if (uri->scheme == SOUP_URI_SCHEME_HTTPS) {
179 		g_socket_client_set_tls (client, TRUE);
180 		g_socket_client_set_tls_validation_flags (client, 0);
181 	}
182 	addr = g_network_address_new (uri->host, uri->port);
183 
184 	conn = g_socket_client_connect (client, addr, NULL, &error);
185 	g_object_unref (addr);
186 	g_object_unref (client);
187 	if (!conn) {
188 		g_assert_no_error (error);
189 		g_error_free (error);
190 		return;
191 	}
192 
193 	in = g_io_stream_get_input_stream (G_IO_STREAM (conn));
194 	out = g_io_stream_get_output_stream (G_IO_STREAM (conn));
195 
196 	req = g_string_new (NULL);
197 	g_string_append_printf (req, "GET %s://%s:%d HTTP/1.1\r\n",
198 				alias, uri->host, uri->port);
199 	g_string_append_printf (req, "Host: %s:%d\r\n",
200 				uri->host, uri->port);
201 	g_string_append (req, "Connection: close\r\n\r\n");
202 
203 	if (!g_output_stream_write_all (out, req->str, req->len, NULL, NULL, &error)) {
204 		g_assert_no_error (error);
205 		g_error_free (error);
206 		g_object_unref (conn);
207 		g_string_free (req, TRUE);
208 		return;
209 	}
210 	g_string_free (req, TRUE);
211 
212 	if (!g_input_stream_read_all (in, buf, sizeof (buf), NULL, NULL, &error)) {
213 		g_assert_no_error (error);
214 		g_error_free (error);
215 		g_object_unref (conn);
216 		return;
217 	}
218 
219 	if (succeed)
220 		g_assert_true (g_str_has_prefix (buf, "HTTP/1.1 200 "));
221 	else
222 		g_assert_true (g_str_has_prefix (buf, "HTTP/1.1 400 "));
223 
224 	g_io_stream_close (G_IO_STREAM (conn), NULL, NULL);
225 	g_object_unref (conn);
226 }
227 
228 static void
do_server_aliases_test(ServerData * sd,gconstpointer test_data)229 do_server_aliases_test (ServerData *sd, gconstpointer test_data)
230 {
231 	char *http_aliases[] = { "dav", NULL };
232 	char *https_aliases[] = { "davs", NULL };
233 	char *http_good[] = { "http", "dav", NULL };
234 	char *http_bad[] = { "https", "davs", "fred", NULL };
235 	char *https_good[] = { "https", "davs", NULL };
236 	char *https_bad[] = { "http", "dav", "fred", NULL };
237 	int i;
238 
239 	g_test_bug ("703694");
240 
241 	g_object_set (G_OBJECT (sd->server),
242 		      SOUP_SERVER_HTTP_ALIASES, http_aliases,
243 		      SOUP_SERVER_HTTPS_ALIASES, https_aliases,
244 		      NULL);
245 
246 	for (i = 0; http_good[i]; i++)
247 		do_one_server_aliases_test (sd->base_uri, http_good[i], TRUE);
248 	for (i = 0; http_bad[i]; i++)
249 		do_one_server_aliases_test (sd->base_uri, http_bad[i], FALSE);
250 
251 	if (tls_available) {
252 		for (i = 0; https_good[i]; i++)
253 			do_one_server_aliases_test (sd->ssl_base_uri, https_good[i], TRUE);
254 		for (i = 0; https_bad[i]; i++)
255 			do_one_server_aliases_test (sd->ssl_base_uri, https_bad[i], FALSE);
256 	}
257 }
258 
259 static void
do_dot_dot_test(ServerData * sd,gconstpointer test_data)260 do_dot_dot_test (ServerData *sd, gconstpointer test_data)
261 {
262 	SoupSession *session;
263 	SoupMessage *msg;
264 	SoupURI *uri;
265 
266 	g_test_bug ("667635");
267 
268 	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
269 
270 	uri = soup_uri_new_with_base (sd->base_uri, "/..%2ftest");
271 	msg = soup_message_new_from_uri ("GET", uri);
272 	soup_uri_free (uri);
273 
274 	soup_session_send_message (session, msg);
275 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
276 	g_object_unref (msg);
277 
278 	uri = soup_uri_new_with_base (sd->base_uri, "/%2e%2e%2ftest");
279 	msg = soup_message_new_from_uri ("GET", uri);
280 	soup_uri_free (uri);
281 
282 	soup_session_send_message (session, msg);
283 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
284 	g_object_unref (msg);
285 
286 #ifdef G_OS_WIN32
287 	uri = soup_uri_new_with_base (sd->base_uri, "\\..%5Ctest");
288 	msg = soup_message_new_from_uri ("GET", uri);
289 	soup_uri_free (uri);
290 
291 	soup_session_send_message (session, msg);
292 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
293 	g_object_unref (msg);
294 
295 	uri = soup_uri_new_with_base (sd->base_uri, "\\../test");
296 	msg = soup_message_new_from_uri ("GET", uri);
297 	soup_uri_free (uri);
298 
299 	soup_session_send_message (session, msg);
300 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
301 	g_object_unref (msg);
302 
303 	uri = soup_uri_new_with_base (sd->base_uri, "%5C..%2ftest");
304 	msg = soup_message_new_from_uri ("GET", uri);
305 	soup_uri_free (uri);
306 
307 	soup_session_send_message (session, msg);
308 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
309 	g_object_unref (msg);
310 
311 	uri = soup_uri_new_with_base (sd->base_uri, "/..\\test");
312 	msg = soup_message_new_from_uri ("GET", uri);
313 	soup_uri_free (uri);
314 
315 	soup_session_send_message (session, msg);
316 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
317 	g_object_unref (msg);
318 
319 	uri = soup_uri_new_with_base (sd->base_uri, "%2f..%5Ctest");
320 	msg = soup_message_new_from_uri ("GET", uri);
321 	soup_uri_free (uri);
322 
323 	soup_session_send_message (session, msg);
324 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
325 	g_object_unref (msg);
326 
327 	uri = soup_uri_new_with_base (sd->base_uri, "\\%2e%2e%5ctest");
328 	msg = soup_message_new_from_uri ("GET", uri);
329 	soup_uri_free (uri);
330 
331 	soup_session_send_message (session, msg);
332 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
333 	g_object_unref (msg);
334 
335 	uri = soup_uri_new_with_base (sd->base_uri, "\\..%%35%63..%%35%63test");
336 	msg = soup_message_new_from_uri ("GET", uri);
337 	soup_uri_free (uri);
338 
339 	soup_session_send_message (session, msg);
340 	soup_test_assert_message_status (msg, SOUP_STATUS_BAD_REQUEST);
341 	g_object_unref (msg);
342 #endif
343 
344 	soup_test_session_abort_unref (session);
345 }
346 
347 static void
ipv6_server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)348 ipv6_server_callback (SoupServer *server, SoupMessage *msg,
349 		      const char *path, GHashTable *query,
350 		      SoupClientContext *context, gpointer data)
351 {
352 	const char *host;
353 	GSocketAddress *addr;
354 	char expected_host[128];
355 
356 	addr = soup_client_context_get_local_address (context);
357 	g_snprintf (expected_host, sizeof (expected_host),
358 		    "[::1]:%d",
359 		    g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
360 
361 	host = soup_message_headers_get_one (msg->request_headers, "Host");
362 	g_assert_cmpstr (host, ==, expected_host);
363 
364 	if (g_test_failed ())
365 		soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
366 	else
367 		soup_message_set_status (msg, SOUP_STATUS_OK);
368 }
369 
370 static void
do_ipv6_test(ServerData * sd,gconstpointer test_data)371 do_ipv6_test (ServerData *sd, gconstpointer test_data)
372 {
373 	SoupSession *session;
374 	SoupMessage *msg;
375 	GError *error = NULL;
376 
377 	g_test_bug ("666399");
378 
379 	sd->server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
380 	server_add_handler (sd, NULL, ipv6_server_callback, NULL, NULL);
381 
382 	if (!soup_server_listen_local (sd->server, 0,
383 				       SOUP_SERVER_LISTEN_IPV6_ONLY,
384 				       &error)) {
385 #if GLIB_CHECK_VERSION (2, 41, 0)
386 		g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
387 #endif
388 		g_test_skip ("no IPv6 support");
389 		return;
390 	}
391 
392 	sd->base_uri = soup_test_server_get_uri (sd->server, "http", "::1");
393 
394 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
395 
396 	debug_printf (1, "  HTTP/1.1\n");
397 	msg = soup_message_new_from_uri ("GET", sd->base_uri);
398 	soup_session_send_message (session, msg);
399 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
400 	g_object_unref (msg);
401 
402 	debug_printf (1, "  HTTP/1.0\n");
403 	msg = soup_message_new_from_uri ("GET", sd->base_uri);
404 	soup_message_set_http_version (msg, SOUP_HTTP_1_0);
405 	soup_session_send_message (session, msg);
406 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
407 	g_object_unref (msg);
408 
409 	soup_test_session_abort_unref (session);
410 }
411 
412 static void
multi_server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)413 multi_server_callback (SoupServer *server, SoupMessage *msg,
414 		       const char *path, GHashTable *query,
415 		       SoupClientContext *context, gpointer data)
416 {
417 	GSocketAddress *addr;
418 	GInetSocketAddress *iaddr;
419 	SoupURI *uri;
420 	char *uristr, *addrstr;
421 
422 	addr = soup_client_context_get_local_address (context);
423 	iaddr = G_INET_SOCKET_ADDRESS (addr);
424 
425 	uri = soup_message_get_uri (msg);
426 	uristr = soup_uri_to_string (uri, FALSE);
427 
428 	addrstr = g_inet_address_to_string (g_inet_socket_address_get_address (iaddr));
429 	g_assert_cmpstr (addrstr, ==, uri->host);
430 	g_free (addrstr);
431 
432 	g_assert_cmpint (g_inet_socket_address_get_port (iaddr), ==, uri->port);
433 
434 	/* FIXME ssl */
435 
436 	soup_message_set_response (msg, "text/plain",
437 				   SOUP_MEMORY_TAKE, uristr, strlen (uristr));
438 	soup_message_set_status (msg, SOUP_STATUS_OK);
439 }
440 
441 static void
do_multi_test(ServerData * sd,SoupURI * uri1,SoupURI * uri2)442 do_multi_test (ServerData *sd, SoupURI *uri1, SoupURI *uri2)
443 {
444 	char *uristr;
445 	SoupSession *session;
446 	SoupMessage *msg;
447 
448 	server_add_handler (sd, NULL, multi_server_callback, NULL, NULL);
449 
450 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
451 
452 	uristr = soup_uri_to_string (uri1, FALSE);
453 	msg = soup_message_new ("GET", uristr);
454 	soup_session_send_message (session, msg);
455 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
456 	g_assert_cmpstr (msg->response_body->data, ==, uristr);
457 	g_object_unref (msg);
458 	g_free (uristr);
459 
460 	uristr = soup_uri_to_string (uri2, FALSE);
461 	msg = soup_message_new ("GET", uristr);
462 	soup_session_send_message (session, msg);
463 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
464 	g_assert_cmpstr (msg->response_body->data, ==, uristr);
465 	g_object_unref (msg);
466 	g_free (uristr);
467 
468 	soup_test_session_abort_unref (session);
469 
470 	soup_uri_free (uri1);
471 	soup_uri_free (uri2);
472 }
473 
474 static void
do_multi_port_test(ServerData * sd,gconstpointer test_data)475 do_multi_port_test (ServerData *sd, gconstpointer test_data)
476 {
477 	GSList *uris;
478 	SoupURI *uri1, *uri2;
479 	GError *error = NULL;
480 
481 	sd->server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
482 
483 	if (!soup_server_listen_local (sd->server, 0, SOUP_SERVER_LISTEN_IPV4_ONLY, &error)) {
484 		g_assert_no_error (error);
485 		g_error_free (error);
486 		return;
487 	}
488 	if (!soup_server_listen_local (sd->server, 0, SOUP_SERVER_LISTEN_IPV4_ONLY, &error)) {
489 		g_assert_no_error (error);
490 		g_error_free (error);
491 		return;
492 	}
493 
494 	uris = soup_server_get_uris (sd->server);
495 	g_assert_cmpint (g_slist_length (uris), ==, 2);
496 	uri1 = uris->data;
497 	uri2 = uris->next->data;
498 	g_slist_free (uris);
499 
500 	g_assert_cmpint (uri1->port, !=, uri2->port);
501 
502 	do_multi_test (sd, uri1, uri2);
503 }
504 
505 static void
do_multi_scheme_test(ServerData * sd,gconstpointer test_data)506 do_multi_scheme_test (ServerData *sd, gconstpointer test_data)
507 {
508 	GSList *uris;
509 	SoupURI *uri1, *uri2;
510 	GError *error = NULL;
511 
512 	SOUP_TEST_SKIP_IF_NO_TLS;
513 
514 	sd->server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
515 
516 	if (!soup_server_listen_local (sd->server, 0, SOUP_SERVER_LISTEN_IPV4_ONLY, &error)) {
517 		g_assert_no_error (error);
518 		g_error_free (error);
519 		return;
520 	}
521 	if (!soup_server_listen_local (sd->server, 0,
522 				       SOUP_SERVER_LISTEN_IPV4_ONLY | SOUP_SERVER_LISTEN_HTTPS,
523 				       &error)) {
524 		g_assert_no_error (error);
525 		g_error_free (error);
526 		return;
527 	}
528 
529 	uris = soup_server_get_uris (sd->server);
530 	g_assert_cmpint (g_slist_length (uris), ==, 2);
531 	uri1 = uris->data;
532 	uri2 = uris->next->data;
533 	g_slist_free (uris);
534 
535 	g_assert_cmpstr (uri1->scheme, !=, uri2->scheme);
536 
537 	do_multi_test (sd, uri1, uri2);
538 }
539 
540 static void
do_multi_family_test(ServerData * sd,gconstpointer test_data)541 do_multi_family_test (ServerData *sd, gconstpointer test_data)
542 {
543 	GSList *uris;
544 	SoupURI *uri1, *uri2;
545 	GError *error = NULL;
546 
547 	sd->server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
548 
549 	if (!soup_server_listen_local (sd->server, 0, 0, &error)) {
550 		g_assert_no_error (error);
551 		g_error_free (error);
552 		return;
553 	}
554 
555 	uris = soup_server_get_uris (sd->server);
556 	if (g_slist_length (uris) == 1) {
557 		gboolean ipv6_works;
558 
559 		/* No IPv6? Double-check */
560 		ipv6_works = soup_server_listen_local (sd->server, 0,
561 						       SOUP_SERVER_LISTEN_IPV6_ONLY,
562 						       NULL);
563 		if (ipv6_works)
564 			g_assert_false (ipv6_works);
565 		else
566 			g_test_skip ("no IPv6 support");
567 		return;
568 	}
569 
570 	g_assert_cmpint (g_slist_length (uris), ==, 2);
571 	uri1 = uris->data;
572 	uri2 = uris->next->data;
573 	g_slist_free (uris);
574 
575 	g_assert_cmpstr (uri1->host, !=, uri2->host);
576 	g_assert_cmpint (uri1->port, ==, uri2->port);
577 
578 	do_multi_test (sd, uri1, uri2);
579 }
580 
581 static void
do_gsocket_import_test(void)582 do_gsocket_import_test (void)
583 {
584 	GSocket *gsock;
585 	GSocketAddress *gaddr;
586 	SoupServer *server;
587 	GSList *listeners;
588 	SoupURI *uri;
589 	SoupSession *session;
590 	SoupMessage *msg;
591 	GError *error = NULL;
592 
593 	gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
594 			      G_SOCKET_TYPE_STREAM,
595 			      G_SOCKET_PROTOCOL_DEFAULT,
596 			      &error);
597 	g_assert_no_error (error);
598 
599 	gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
600 	g_socket_bind (gsock, gaddr, TRUE, &error);
601 	g_object_unref (gaddr);
602 	g_assert_no_error (error);
603 	g_socket_listen (gsock, &error);
604 	g_assert_no_error (error);
605 
606 	gaddr = g_socket_get_local_address (gsock, &error);
607 	g_assert_no_error (error);
608 	g_object_unref (gaddr);
609 
610 	server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
611 	soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
612 
613 	listeners = soup_server_get_listeners (server);
614 	g_assert_cmpint (g_slist_length (listeners), ==, 0);
615 	g_slist_free (listeners);
616 
617 	soup_server_listen_socket (server, gsock, 0, &error);
618 	g_assert_no_error (error);
619 	listeners = soup_server_get_listeners (server);
620 	g_assert_cmpint (g_slist_length (listeners), ==, 1);
621 	g_slist_free (listeners);
622 
623 	uri = soup_test_server_get_uri (server, "http", "127.0.0.1");
624 	g_assert_nonnull (uri);
625 	listeners = soup_server_get_listeners (server);
626 	g_assert_cmpint (g_slist_length (listeners), ==, 1);
627 	g_slist_free (listeners);
628 
629 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
630 	msg = soup_message_new_from_uri ("GET", uri);
631 	soup_session_send_message (session, msg);
632 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
633 	g_object_unref (msg);
634 
635 	soup_test_session_abort_unref (session);
636 
637 	soup_uri_free (uri);
638 	soup_test_server_quit_unref (server);
639 
640 	g_assert_false (g_socket_is_connected (gsock));
641 	g_object_unref (gsock);
642 }
643 
644 static void
do_fd_import_test(void)645 do_fd_import_test (void)
646 {
647 	GSocket *gsock;
648 	GSocketAddress *gaddr;
649 	SoupServer *server;
650 	GSList *listeners;
651 	SoupURI *uri;
652 	SoupSession *session;
653 	SoupMessage *msg;
654 	int type;
655 	GError *error = NULL;
656 
657 	gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
658 			      G_SOCKET_TYPE_STREAM,
659 			      G_SOCKET_PROTOCOL_DEFAULT,
660 			      &error);
661 	g_assert_no_error (error);
662 
663 	gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
664 	g_socket_bind (gsock, gaddr, TRUE, &error);
665 	g_object_unref (gaddr);
666 	g_assert_no_error (error);
667 	g_socket_listen (gsock, &error);
668 	g_assert_no_error (error);
669 
670 	gaddr = g_socket_get_local_address (gsock, &error);
671 	g_assert_no_error (error);
672 	g_object_unref (gaddr);
673 
674 	server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
675 	soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
676 
677 	listeners = soup_server_get_listeners (server);
678 	g_assert_cmpint (g_slist_length (listeners), ==, 0);
679 	g_slist_free (listeners);
680 
681 	soup_server_listen_fd (server, g_socket_get_fd (gsock), 0, &error);
682 	g_assert_no_error (error);
683 	listeners = soup_server_get_listeners (server);
684 	g_assert_cmpint (g_slist_length (listeners), ==, 1);
685 	g_slist_free (listeners);
686 
687 	uri = soup_test_server_get_uri (server, "http", "127.0.0.1");
688 	g_assert_nonnull (uri);
689 	listeners = soup_server_get_listeners (server);
690 	g_assert_cmpint (g_slist_length (listeners), ==, 1);
691 	g_slist_free (listeners);
692 
693 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
694 	msg = soup_message_new_from_uri ("GET", uri);
695 	soup_session_send_message (session, msg);
696 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
697 	g_object_unref (msg);
698 
699 	soup_test_session_abort_unref (session);
700 
701 	soup_uri_free (uri);
702 	soup_test_server_quit_unref (server);
703 
704 	/* @server should have closed our socket, although @gsock doesn't
705 	 * know this.
706 	 */
707 	g_socket_get_option (gsock, SOL_SOCKET, SO_TYPE, &type, &error);
708 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
709 	g_clear_error (&error);
710 	g_object_unref (gsock);
711 }
712 
713 typedef struct
714 {
715 	GIOStream parent;
716 	GInputStream *input_stream;
717 	GOutputStream *output_stream;
718 } GTestIOStream;
719 
720 typedef struct
721 {
722 	GIOStreamClass parent_class;
723 } GTestIOStreamClass;
724 
725 static GType g_test_io_stream_get_type (void);
726 G_DEFINE_TYPE (GTestIOStream, g_test_io_stream, G_TYPE_IO_STREAM);
727 
728 
729 static GInputStream *
get_input_stream(GIOStream * io_stream)730 get_input_stream (GIOStream *io_stream)
731 {
732 	GTestIOStream *self =  (GTestIOStream *) io_stream;
733 
734 	return self->input_stream;
735 }
736 
737 static GOutputStream *
get_output_stream(GIOStream * io_stream)738 get_output_stream (GIOStream *io_stream)
739 {
740 	GTestIOStream *self =  (GTestIOStream *) io_stream;
741 
742 	return self->output_stream;
743 }
744 
745 static void
finalize(GObject * object)746 finalize (GObject *object)
747 {
748 	GTestIOStream *self = (GTestIOStream *) object;
749 
750 	if (self->input_stream != NULL)
751 		g_object_unref (self->input_stream);
752 
753 	if (self->output_stream != NULL)
754 		g_object_unref (self->output_stream);
755 
756 	G_OBJECT_CLASS (g_test_io_stream_parent_class)->finalize (object);
757 }
758 
759 static void
g_test_io_stream_class_init(GTestIOStreamClass * klass)760 g_test_io_stream_class_init (GTestIOStreamClass *klass)
761 {
762 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
763 	GIOStreamClass *io_class = G_IO_STREAM_CLASS (klass);
764 
765 	object_class->finalize = finalize;
766 
767 	io_class->get_input_stream = get_input_stream;
768 	io_class->get_output_stream = get_output_stream;
769 }
770 
771 static void
g_test_io_stream_init(GTestIOStream * self)772 g_test_io_stream_init (GTestIOStream *self)
773 {
774 }
775 
776 static GIOStream *
g_test_io_stream_new(GInputStream * input,GOutputStream * output)777 g_test_io_stream_new (GInputStream *input, GOutputStream *output)
778 {
779 	GTestIOStream *self;
780 
781 	self = g_object_new (g_test_io_stream_get_type (), NULL);
782 	self->input_stream = g_object_ref (input);
783 	self->output_stream = g_object_ref (output);
784 
785 	return G_IO_STREAM (self);
786 }
787 
788 static void
mem_server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)789 mem_server_callback (SoupServer *server, SoupMessage *msg,
790 		     const char *path, GHashTable *query,
791 		     SoupClientContext *context, gpointer data)
792 {
793 	GSocketAddress *addr;
794 	GSocket *sock;
795 	const char *host;
796 
797 	addr = soup_client_context_get_local_address (context);
798 	g_assert_nonnull (addr);
799 
800 	addr = soup_client_context_get_remote_address (context);
801 	g_assert_nonnull (addr);
802 
803 	sock = soup_client_context_get_gsocket (context);
804 	g_assert_null (sock);
805 
806 	host = soup_client_context_get_host (context);
807 	g_assert_cmpstr (host, ==, "127.0.0.1");
808 
809 	server_callback (server, msg, path, query, context, data);
810 }
811 
812 static void
do_iostream_accept_test(void)813 do_iostream_accept_test (void)
814 {
815 	GError *error = NULL;
816 	SoupServer *server;
817 	GInputStream *input;
818 	GOutputStream *output;
819 	GIOStream *stream;
820 	GSocketAddress *addr;
821 	const char req[] = "GET / HTTP/1.0\r\n\r\n";
822 	gchar *reply;
823 	gsize reply_size;
824 
825 	server = soup_test_server_new (SOUP_TEST_SERVER_NO_DEFAULT_LISTENER);
826 	soup_server_add_handler (server, NULL, mem_server_callback, NULL, NULL);
827 
828 	input = g_memory_input_stream_new_from_data (req, sizeof(req), NULL);
829 	output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
830 	stream = g_test_io_stream_new (input, output);
831 
832 	addr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
833 
834 	soup_server_accept_iostream (server, stream, addr, addr, &error);
835 	g_assert_no_error (error);
836 
837 	soup_test_server_quit_unref (server);
838 
839 	reply = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output));
840 	reply_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (output));
841 	g_assert_true (reply_size > 0);
842 	g_assert_true (g_str_has_prefix (reply, "HTTP/1.0 200 OK"));
843 
844 	g_clear_object (&addr);
845 	g_clear_object (&stream);
846 	g_clear_object (&input);
847 	g_clear_object (&output);
848 	g_clear_error (&error);
849 }
850 
851 typedef struct {
852 	SoupServer *server;
853 	SoupMessage *smsg;
854 	gboolean handler_called;
855 	gboolean paused;
856 } UnhandledServerData;
857 
858 static gboolean
idle_unpause_message(gpointer user_data)859 idle_unpause_message (gpointer user_data)
860 {
861 	UnhandledServerData *usd = user_data;
862 
863 	soup_server_unpause_message (usd->server, usd->smsg);
864 	return FALSE;
865 }
866 
867 static void
unhandled_server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)868 unhandled_server_callback (SoupServer *server, SoupMessage *msg,
869 			   const char *path, GHashTable *query,
870 			   SoupClientContext *context, gpointer data)
871 {
872 	UnhandledServerData *usd = data;
873 
874 	usd->handler_called = TRUE;
875 
876 	if (soup_message_headers_get_one (msg->request_headers, "X-Test-Server-Pause")) {
877 		usd->paused = TRUE;
878 		usd->server = server;
879 		usd->smsg = msg;
880 		soup_server_pause_message (server, msg);
881 		g_idle_add (idle_unpause_message, usd);
882 	}
883 }
884 
885 static void
do_fail_404_test(ServerData * sd,gconstpointer test_data)886 do_fail_404_test (ServerData *sd, gconstpointer test_data)
887 {
888 	SoupSession *session;
889 	SoupMessage *msg;
890 	UnhandledServerData usd;
891 
892 	usd.handler_called = usd.paused = FALSE;
893 
894 	server_add_handler (sd, "/not-a-match", unhandled_server_callback, &usd, NULL);
895 
896 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
897 	msg = soup_message_new_from_uri ("GET", sd->base_uri);
898 	soup_session_send_message (session, msg);
899 	soup_test_assert_message_status (msg, SOUP_STATUS_NOT_FOUND);
900 	g_object_unref (msg);
901 
902 	g_assert_false (usd.handler_called);
903 	g_assert_false (usd.paused);
904 
905 	soup_test_session_abort_unref (session);
906 }
907 
908 static void
do_fail_500_test(ServerData * sd,gconstpointer pause)909 do_fail_500_test (ServerData *sd, gconstpointer pause)
910 {
911 	SoupSession *session;
912 	SoupMessage *msg;
913 	UnhandledServerData usd;
914 
915 	usd.handler_called = usd.paused = FALSE;
916 
917 	server_add_handler (sd, NULL, unhandled_server_callback, &usd, NULL);
918 
919 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
920 	msg = soup_message_new_from_uri ("GET", sd->base_uri);
921 	if (pause)
922 		soup_message_headers_append (msg->request_headers, "X-Test-Server-Pause", "true");
923 	soup_session_send_message (session, msg);
924 	soup_test_assert_message_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
925 	g_object_unref (msg);
926 
927 	g_assert_true (usd.handler_called);
928 	if (pause)
929 		g_assert_true (usd.paused);
930 	else
931 		g_assert_false (usd.paused);
932 
933 	soup_test_session_abort_unref (session);
934 }
935 
936 static void
stream_got_chunk(SoupMessage * msg,SoupBuffer * chunk,gpointer user_data)937 stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data)
938 {
939 	GChecksum *checksum = user_data;
940 
941 	g_checksum_update (checksum, (const guchar *)chunk->data, chunk->length);
942 }
943 
944 static void
stream_got_body(SoupMessage * msg,gpointer user_data)945 stream_got_body (SoupMessage *msg, gpointer user_data)
946 {
947 	GChecksum *checksum = user_data;
948 	const char *md5 = g_checksum_get_string (checksum);
949 
950 	soup_message_set_status (msg, SOUP_STATUS_OK);
951 	soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY,
952 				   md5, strlen (md5));
953 	g_checksum_free (checksum);
954 }
955 
956 static void
early_stream_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)957 early_stream_callback (SoupServer *server, SoupMessage *msg,
958 		       const char *path, GHashTable *query,
959 		       SoupClientContext *context, gpointer data)
960 {
961 	GChecksum *checksum;
962 
963 	if (msg->method != SOUP_METHOD_POST) {
964 		soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
965 		return;
966 	}
967 
968 	checksum = g_checksum_new (G_CHECKSUM_MD5);
969 	g_signal_connect (msg, "got-chunk",
970 			  G_CALLBACK (stream_got_chunk), checksum);
971 	g_signal_connect (msg, "got-body",
972 			  G_CALLBACK (stream_got_body), checksum);
973 
974 	soup_message_body_set_accumulate (msg->request_body, TRUE);
975 }
976 
977 static void
do_early_stream_test(ServerData * sd,gconstpointer test_data)978 do_early_stream_test (ServerData *sd, gconstpointer test_data)
979 {
980 	SoupSession *session;
981 	SoupMessage *msg;
982 	SoupBuffer *index;
983 	char *md5;
984 
985 	server_add_early_handler (sd, NULL, early_stream_callback, NULL, NULL);
986 
987 	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
988 
989 	msg = soup_message_new_from_uri ("POST", sd->base_uri);
990 
991 	index = soup_test_get_index ();
992 	soup_message_body_append (msg->request_body, SOUP_MEMORY_COPY,
993 				  index->data, index->length);
994 	soup_session_send_message (session, msg);
995 
996 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
997 
998 	md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5,
999 					   (guchar *) index->data, index->length);
1000 	g_assert_cmpstr (md5, ==, msg->response_body->data);
1001 	g_free (md5);
1002 
1003 	g_object_unref (msg);
1004 	soup_test_session_abort_unref (session);
1005 }
1006 
1007 static void
early_respond_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)1008 early_respond_callback (SoupServer *server, SoupMessage *msg,
1009 			const char *path, GHashTable *query,
1010 			SoupClientContext *context, gpointer data)
1011 {
1012 	if (!strcmp (path, "/"))
1013 		soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
1014 }
1015 
1016 static void
do_early_respond_test(ServerData * sd,gconstpointer test_data)1017 do_early_respond_test (ServerData *sd, gconstpointer test_data)
1018 {
1019 	SoupSession *session;
1020 	SoupMessage *msg;
1021 	SoupURI *uri2;
1022 
1023 	server_add_early_handler (sd, NULL, early_respond_callback, NULL, NULL);
1024 
1025 	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
1026 
1027 	/* The early handler will intercept, and the normal handler will be skipped */
1028 	msg = soup_message_new_from_uri ("GET", sd->base_uri);
1029 	soup_session_send_message (session, msg);
1030 	soup_test_assert_message_status (msg, SOUP_STATUS_FORBIDDEN);
1031 	g_assert_cmpint (msg->response_body->length, ==, 0);
1032 	g_object_unref (msg);
1033 
1034 	/* The early handler will ignore this one */
1035 	uri2 = soup_uri_new_with_base (sd->base_uri, "/subdir");
1036 	msg = soup_message_new_from_uri ("GET", uri2);
1037 	soup_session_send_message (session, msg);
1038 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
1039 	g_assert_cmpstr (msg->response_body->data, ==, "index");
1040 	g_object_unref (msg);
1041 	soup_uri_free (uri2);
1042 
1043 	soup_test_session_abort_unref (session);
1044 }
1045 
1046 static void
early_multi_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)1047 early_multi_callback (SoupServer *server, SoupMessage *msg,
1048 		      const char *path, GHashTable *query,
1049 		      SoupClientContext *context, gpointer data)
1050 {
1051 	soup_message_headers_append (msg->response_headers, "X-Early", "yes");
1052 }
1053 
1054 static void
do_early_multi_test(ServerData * sd,gconstpointer test_data)1055 do_early_multi_test (ServerData *sd, gconstpointer test_data)
1056 {
1057 	SoupSession *session;
1058 	SoupMessage *msg;
1059 	SoupURI *uri;
1060 	struct {
1061 		const char *path;
1062 		gboolean expect_normal, expect_early;
1063 	} multi_tests[] = {
1064 		{ "/", FALSE, FALSE },
1065 		{ "/normal", TRUE, FALSE },
1066 		{ "/normal/subdir", TRUE, FALSE },
1067 		{ "/normal/early", FALSE, TRUE },
1068 		{ "/normal/early/subdir", FALSE, TRUE },
1069 		{ "/early", FALSE, TRUE },
1070 		{ "/early/subdir", FALSE, TRUE },
1071 		{ "/early/normal", TRUE, FALSE },
1072 		{ "/early/normal/subdir", TRUE, FALSE },
1073 		{ "/both", TRUE, TRUE },
1074 		{ "/both/subdir", TRUE, TRUE }
1075 	};
1076 	int i;
1077 	const char *header;
1078 
1079 	server_add_handler (sd, "/normal", server_callback, NULL, NULL);
1080 	server_add_early_handler (sd, "/normal/early", early_multi_callback, NULL, NULL);
1081 	server_add_early_handler (sd, "/early", early_multi_callback, NULL, NULL);
1082 	server_add_handler (sd, "/early/normal", server_callback, NULL, NULL);
1083 	server_add_handler (sd, "/both", server_callback, NULL, NULL);
1084 	server_add_early_handler (sd, "/both", early_multi_callback, NULL, NULL);
1085 
1086 	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
1087 
1088 	for (i = 0; i < G_N_ELEMENTS (multi_tests); i++) {
1089 		uri = soup_uri_new_with_base (sd->base_uri, multi_tests[i].path);
1090 		msg = soup_message_new_from_uri ("GET", uri);
1091 		soup_uri_free (uri);
1092 
1093 		soup_session_send_message (session, msg);
1094 
1095 		/* The normal handler sets status to OK. The early handler doesn't
1096 		 * touch status, meaning that if it runs and the normal handler doesn't,
1097 		 * then SoupServer will set the status to INTERNAL_SERVER_ERROR
1098 		 * (since a handler ran, but didn't set the status). If neither handler
1099 		 * runs then SoupServer will set the status to NOT_FOUND.
1100 		 */
1101 		if (multi_tests[i].expect_normal)
1102 			soup_test_assert_message_status (msg, SOUP_STATUS_OK);
1103 		else if (multi_tests[i].expect_early)
1104 			soup_test_assert_message_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
1105 		else
1106 			soup_test_assert_message_status (msg, SOUP_STATUS_NOT_FOUND);
1107 
1108 		header = soup_message_headers_get_one (msg->response_headers, "X-Early");
1109 		if (multi_tests[i].expect_early)
1110 			g_assert_cmpstr (header, ==, "yes");
1111 		else
1112 			g_assert_cmpstr (header, ==, NULL);
1113 		if (multi_tests[i].expect_normal)
1114 			g_assert_cmpstr (msg->response_body->data, ==, "index");
1115 		else
1116 			g_assert_cmpint (msg->response_body->length, ==, 0);
1117 
1118 		g_object_unref (msg);
1119 	}
1120 
1121 	soup_test_session_abort_unref (session);
1122 }
1123 
1124 typedef struct {
1125 	GIOStream *iostream;
1126 	GInputStream *istream;
1127 	GOutputStream *ostream;
1128 
1129 	gssize nread, nwrote;
1130 	guchar *buffer;
1131 } TunnelEnd;
1132 
1133 typedef struct {
1134 	SoupServer *self;
1135 	SoupMessage *msg;
1136 	SoupClientContext *context;
1137 	GCancellable *cancellable;
1138 
1139 	TunnelEnd client, server;
1140 } Tunnel;
1141 
1142 #define BUFSIZE 8192
1143 
1144 static void tunnel_read_cb (GObject      *object,
1145 			    GAsyncResult *result,
1146 			    gpointer      user_data);
1147 
1148 static void
tunnel_close(Tunnel * tunnel)1149 tunnel_close (Tunnel *tunnel)
1150 {
1151 	if (tunnel->cancellable) {
1152 		g_cancellable_cancel (tunnel->cancellable);
1153 		g_object_unref (tunnel->cancellable);
1154 	}
1155 
1156 	if (tunnel->client.iostream) {
1157 		g_io_stream_close (tunnel->client.iostream, NULL, NULL);
1158 		g_object_unref (tunnel->client.iostream);
1159 	}
1160 	if (tunnel->server.iostream) {
1161 		g_io_stream_close (tunnel->server.iostream, NULL, NULL);
1162 		g_object_unref (tunnel->server.iostream);
1163 	}
1164 
1165 	g_free (tunnel->client.buffer);
1166 	g_free (tunnel->server.buffer);
1167 
1168 	g_clear_object (&tunnel->self);
1169 	g_clear_object (&tunnel->msg);
1170 
1171 	g_free (tunnel);
1172 }
1173 
1174 static void
tunnel_wrote_cb(GObject * object,GAsyncResult * result,gpointer user_data)1175 tunnel_wrote_cb (GObject      *object,
1176 		 GAsyncResult *result,
1177 		 gpointer      user_data)
1178 {
1179 	Tunnel *tunnel = user_data;
1180 	TunnelEnd *write_end, *read_end;
1181 	GError *error = NULL;
1182 	gssize nwrote;
1183 
1184 	nwrote = g_output_stream_write_finish (G_OUTPUT_STREAM (object), result, &error);
1185 	if (nwrote <= 0) {
1186 		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
1187 			g_error_free (error);
1188 			return;
1189 		} else if (error) {
1190 			g_print ("Tunnel write failed: %s\n", error->message);
1191 			g_error_free (error);
1192 		}
1193 		tunnel_close (tunnel);
1194 		return;
1195 	}
1196 
1197 	if (object == (GObject *)tunnel->client.ostream) {
1198 		write_end = &tunnel->client;
1199 		read_end = &tunnel->server;
1200 	} else {
1201 		write_end = &tunnel->server;
1202 		read_end = &tunnel->client;
1203 	}
1204 
1205 	write_end->nwrote += nwrote;
1206 	if (write_end->nwrote < read_end->nread) {
1207 		g_output_stream_write_async (write_end->ostream,
1208 					     read_end->buffer + write_end->nwrote,
1209 					     read_end->nread - write_end->nwrote,
1210 					     G_PRIORITY_DEFAULT, tunnel->cancellable,
1211 					     tunnel_wrote_cb, tunnel);
1212 	} else {
1213 		g_input_stream_read_async (read_end->istream,
1214 					   read_end->buffer, BUFSIZE,
1215 					   G_PRIORITY_DEFAULT, tunnel->cancellable,
1216 					   tunnel_read_cb, tunnel);
1217 	}
1218 }
1219 
1220 static void
tunnel_read_cb(GObject * object,GAsyncResult * result,gpointer user_data)1221 tunnel_read_cb (GObject      *object,
1222 		GAsyncResult *result,
1223 		gpointer      user_data)
1224 {
1225 	Tunnel *tunnel = user_data;
1226 	TunnelEnd *read_end, *write_end;
1227 	GError *error = NULL;
1228 	gssize nread;
1229 
1230 	nread = g_input_stream_read_finish (G_INPUT_STREAM (object), result, &error);
1231 	if (nread <= 0) {
1232 		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
1233 			g_error_free (error);
1234 			return;
1235 		} else if (error) {
1236 			g_print ("Tunnel read failed: %s\n", error->message);
1237 			g_error_free (error);
1238 		}
1239 		tunnel_close (tunnel);
1240 		return;
1241 	}
1242 
1243 	if (object == (GObject *)tunnel->client.istream) {
1244 		read_end = &tunnel->client;
1245 		write_end = &tunnel->server;
1246 	} else {
1247 		read_end = &tunnel->server;
1248 		write_end = &tunnel->client;
1249 	}
1250 
1251 	read_end->nread = nread;
1252 	write_end->nwrote = 0;
1253 	g_output_stream_write_async (write_end->ostream,
1254 				     read_end->buffer, read_end->nread,
1255 				     G_PRIORITY_DEFAULT, tunnel->cancellable,
1256 				     tunnel_wrote_cb, tunnel);
1257 }
1258 
1259 static void
start_tunnel(SoupMessage * msg,gpointer user_data)1260 start_tunnel (SoupMessage *msg, gpointer user_data)
1261 {
1262 	Tunnel *tunnel = user_data;
1263 
1264 	tunnel->client.iostream = soup_client_context_steal_connection (tunnel->context);
1265 	tunnel->client.istream = g_io_stream_get_input_stream (tunnel->client.iostream);
1266 	tunnel->client.ostream = g_io_stream_get_output_stream (tunnel->client.iostream);
1267 	g_clear_object (&tunnel->self);
1268 	g_clear_object (&tunnel->msg);
1269 
1270 	tunnel->client.buffer = g_malloc (BUFSIZE);
1271 	tunnel->server.buffer = g_malloc (BUFSIZE);
1272 
1273 	tunnel->cancellable = g_cancellable_new ();
1274 
1275 	g_input_stream_read_async (tunnel->client.istream,
1276 				   tunnel->client.buffer, BUFSIZE,
1277 				   G_PRIORITY_DEFAULT, tunnel->cancellable,
1278 				   tunnel_read_cb, tunnel);
1279 	g_input_stream_read_async (tunnel->server.istream,
1280 				   tunnel->server.buffer, BUFSIZE,
1281 				   G_PRIORITY_DEFAULT, tunnel->cancellable,
1282 				   tunnel_read_cb, tunnel);
1283 }
1284 
1285 
1286 static void
tunnel_connected_cb(GObject * object,GAsyncResult * result,gpointer user_data)1287 tunnel_connected_cb (GObject      *object,
1288 		     GAsyncResult *result,
1289 		     gpointer      user_data)
1290 {
1291 	Tunnel *tunnel = user_data;
1292 	GError *error = NULL;
1293 
1294 	tunnel->server.iostream = (GIOStream *)
1295 		g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (object), result, &error);
1296 	if (!tunnel->server.iostream) {
1297 		soup_message_set_status (tunnel->msg, SOUP_STATUS_BAD_GATEWAY);
1298 		soup_message_set_response (tunnel->msg, "text/plain",
1299 					   SOUP_MEMORY_COPY,
1300 					   error->message, strlen (error->message));
1301 		g_error_free (error);
1302 		soup_server_unpause_message (tunnel->self, tunnel->msg);
1303 		tunnel_close (tunnel);
1304 		return;
1305 	}
1306 
1307 	tunnel->server.istream = g_io_stream_get_input_stream (tunnel->server.iostream);
1308 	tunnel->server.ostream = g_io_stream_get_output_stream (tunnel->server.iostream);
1309 
1310 	soup_message_set_status (tunnel->msg, SOUP_STATUS_OK);
1311 	soup_server_unpause_message (tunnel->self, tunnel->msg);
1312 	g_signal_connect (tunnel->msg, "wrote-body",
1313 			  G_CALLBACK (start_tunnel), tunnel);
1314 }
1315 
1316 static void
proxy_server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)1317 proxy_server_callback (SoupServer *server, SoupMessage *msg,
1318 		       const char *path, GHashTable *query,
1319 		       SoupClientContext *context, gpointer data)
1320 {
1321 	GSocketClient *sclient;
1322 	SoupURI *dest_uri;
1323 	Tunnel *tunnel;
1324 
1325 	if (msg->method != SOUP_METHOD_CONNECT) {
1326 		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
1327 		return;
1328 	}
1329 
1330 	soup_server_pause_message (server, msg);
1331 
1332 	tunnel = g_new0 (Tunnel, 1);
1333 	tunnel->self = g_object_ref (server);
1334 	tunnel->msg = g_object_ref (msg);
1335 	tunnel->context = context;
1336 
1337 	dest_uri = soup_message_get_uri (msg);
1338 	sclient = g_socket_client_new ();
1339 	g_socket_client_connect_to_host_async (sclient, dest_uri->host, dest_uri->port,
1340 					       NULL, tunnel_connected_cb, tunnel);
1341 	g_object_unref (sclient);
1342 }
1343 
1344 static void
do_steal_connect_test(ServerData * sd,gconstpointer test_data)1345 do_steal_connect_test (ServerData *sd, gconstpointer test_data)
1346 {
1347 	SoupServer *proxy;
1348 	SoupURI *proxy_uri;
1349 	SoupSession *session;
1350 	SoupMessage *msg;
1351 	const char *handled_by;
1352 
1353 	SOUP_TEST_SKIP_IF_NO_TLS;
1354 
1355 	proxy = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
1356 	proxy_uri = soup_test_server_get_uri (proxy, SOUP_URI_SCHEME_HTTP, "127.0.0.1");
1357 	soup_server_add_handler (proxy, NULL, proxy_server_callback, NULL, NULL);
1358 
1359 	session = soup_test_session_new (SOUP_TYPE_SESSION,
1360 					 SOUP_SESSION_PROXY_URI, proxy_uri,
1361 					 NULL);
1362 	msg = soup_message_new_from_uri ("GET", sd->ssl_base_uri);
1363 	soup_session_send_message (session, msg);
1364 
1365 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
1366 	handled_by = soup_message_headers_get_one (msg->response_headers, "X-Handled-By");
1367 	g_assert_cmpstr (handled_by, ==, "server_callback");
1368 
1369 	g_object_unref (msg);
1370 	soup_test_session_abort_unref (session);
1371 
1372 	soup_test_server_quit_unref (proxy);
1373 	soup_uri_free (proxy_uri);
1374 }
1375 
1376 int
main(int argc,char ** argv)1377 main (int argc, char **argv)
1378 {
1379 	int ret;
1380 
1381 	test_init (argc, argv, NULL);
1382 
1383 	g_test_add ("/server/OPTIONS *", ServerData, NULL,
1384 		    server_setup, do_star_test, server_teardown);
1385 	g_test_add ("/server/aliases", ServerData, NULL,
1386 		    server_setup, do_server_aliases_test, server_teardown);
1387 	g_test_add ("/server/..-in-path", ServerData, NULL,
1388 		    server_setup, do_dot_dot_test, server_teardown);
1389 	g_test_add ("/server/ipv6", ServerData, NULL,
1390 		    NULL, do_ipv6_test, server_teardown);
1391 	g_test_add ("/server/multi/port", ServerData, NULL,
1392 		    NULL, do_multi_port_test, server_teardown);
1393 	g_test_add ("/server/multi/scheme", ServerData, NULL,
1394 		    NULL, do_multi_scheme_test, server_teardown);
1395 	g_test_add ("/server/multi/family", ServerData, NULL,
1396 		    NULL, do_multi_family_test, server_teardown);
1397 	g_test_add_func ("/server/import/gsocket", do_gsocket_import_test);
1398 	g_test_add_func ("/server/import/fd", do_fd_import_test);
1399 	g_test_add_func ("/server/accept/iostream", do_iostream_accept_test);
1400 	g_test_add ("/server/fail/404", ServerData, NULL,
1401 		    server_setup_nohandler, do_fail_404_test, server_teardown);
1402 	g_test_add ("/server/fail/500", ServerData, GINT_TO_POINTER (FALSE),
1403 		    server_setup_nohandler, do_fail_500_test, server_teardown);
1404 	g_test_add ("/server/fail/500-pause", ServerData, GINT_TO_POINTER (TRUE),
1405 		    server_setup_nohandler, do_fail_500_test, server_teardown);
1406 	g_test_add ("/server/early/stream", ServerData, NULL,
1407 		    server_setup_nohandler, do_early_stream_test, server_teardown);
1408 	g_test_add ("/server/early/respond", ServerData, NULL,
1409 		    server_setup, do_early_respond_test, server_teardown);
1410 	g_test_add ("/server/early/multi", ServerData, NULL,
1411 		    server_setup_nohandler, do_early_multi_test, server_teardown);
1412 	g_test_add ("/server/steal/CONNECT", ServerData, NULL,
1413 		    server_setup, do_steal_connect_test, server_teardown);
1414 
1415 	ret = g_test_run ();
1416 
1417 	test_cleanup ();
1418 	return ret;
1419 }
1420