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