1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3  * Copyright 2007-2012 Red Hat, Inc.
4  */
5 
6 #include "test-utils.h"
7 #include "soup-connection.h"
8 #include "soup-session-private.h"
9 #include "soup-message-headers-private.h"
10 
11 SoupServer *server;
12 GUri *base_uri;
13 
14 static gboolean
auth_callback(SoupAuthDomain * auth_domain,SoupMessage * msg,const char * username,const char * password,gpointer data)15 auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg,
16 	       const char *username, const char *password, gpointer data)
17 {
18 	return !strcmp (username, "user") && !strcmp (password, "password");
19 }
20 
21 static gboolean
timeout_finish_message(gpointer msg)22 timeout_finish_message (gpointer msg)
23 {
24 	SoupServer *server = g_object_get_data (G_OBJECT (msg), "server");
25 
26 	soup_server_unpause_message (server, msg);
27 	return FALSE;
28 }
29 
30 static void
server_callback(SoupServer * server,SoupServerMessage * msg,const char * path,GHashTable * query,gpointer data)31 server_callback (SoupServer        *server,
32 		 SoupServerMessage *msg,
33 		 const char        *path,
34 		 GHashTable        *query,
35 		 gpointer           data)
36 {
37 	const char *method = soup_server_message_get_method (msg);
38 	GUri *uri = soup_server_message_get_uri (msg);
39 
40 	if (method != SOUP_METHOD_GET && method != SOUP_METHOD_POST) {
41 		soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL);
42 		return;
43 	}
44 
45 	if (!strcmp (path, "/redirect")) {
46 		soup_server_message_set_redirect (msg, SOUP_STATUS_FOUND, "/");
47 		return;
48 	}
49 
50 	if (!strcmp (path, "/slow")) {
51                 GSource *timeout;
52 		soup_server_pause_message (server, msg);
53 		g_object_set_data (G_OBJECT (msg), "server", server);
54 		timeout = soup_add_timeout (g_main_context_get_thread_default (),
55                                             1000, timeout_finish_message, msg);
56                 g_source_unref (timeout);
57 	}
58 
59         if (!strcmp (path, "/invalid_utf8_headers")) {
60                 SoupMessageHeaders *headers = soup_server_message_get_response_headers (msg);
61                 const char *invalid_utf8_value = "\xe2\x82\xa0gh\xe2\xffjl";
62 
63                 /* Purposefully insert invalid utf8 data */
64                 g_assert_false (g_utf8_validate (invalid_utf8_value, -1, NULL));
65                 soup_message_headers_append (headers, "InvalidValue", invalid_utf8_value);
66         }
67 
68 	soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
69 	if (!strcmp (g_uri_get_host (uri), "foo")) {
70 		soup_server_message_set_response (msg, "text/plain",
71                                                   SOUP_MEMORY_STATIC, "foo-index", 9);
72 		return;
73 	} else {
74 		soup_server_message_set_response (msg, "text/plain",
75 						  SOUP_MEMORY_STATIC, "index", 5);
76 		return;
77 	}
78 }
79 
80 /* Host header handling: client must be able to override the default
81  * value, server must be able to recognize different Host values.
82  */
83 static void
do_host_test(void)84 do_host_test (void)
85 {
86 	SoupSession *session;
87 	SoupMessage *one, *two;
88 	GBytes *body_one, *body_two;
89 
90 	g_test_bug ("539803");
91 
92 	session = soup_test_session_new (NULL);
93 
94 	one = soup_message_new_from_uri ("GET", base_uri);
95 	two = soup_message_new_from_uri ("GET", base_uri);
96 	soup_message_headers_replace (soup_message_get_request_headers (two), "Host", "foo");
97 
98 	body_one = soup_session_send_and_read (session, one, NULL, NULL);
99 	body_two = soup_session_send_and_read (session, two, NULL, NULL);
100 
101 	soup_test_session_abort_unref (session);
102 
103 	soup_test_assert_message_status (one, SOUP_STATUS_OK);
104 	g_assert_cmpstr (g_bytes_get_data (body_one, NULL), ==, "index");
105 	g_bytes_unref (body_one);
106 	g_object_unref (one);
107 
108 	soup_test_assert_message_status (two, SOUP_STATUS_OK);
109 	g_assert_cmpstr (g_bytes_get_data (body_two, NULL), ==, "foo-index");
110 	g_bytes_unref (body_two);
111 	g_object_unref (two);
112 }
113 
114 /* request with too big header should be discarded with a IO error to
115  * prevent DOS attacks.
116  */
117 static void
do_host_big_header(void)118 do_host_big_header (void)
119 {
120 	SoupMessage *msg;
121 	SoupSession *session;
122 	int i;
123 	GInputStream *stream;
124 	GError *error = NULL;
125 
126 	g_test_bug ("792173");
127 
128 	session = soup_test_session_new (NULL);
129 
130 	msg = soup_message_new_from_uri ("GET", base_uri);
131 	for (i = 0; i < 2048; i++) {
132 		char *key = g_strdup_printf ("test-long-header-key%d", i);
133 		char *value = g_strdup_printf ("test-long-header-key%d", i);
134 		soup_message_headers_append (soup_message_get_request_headers (msg), key, value);
135 		g_free (value);
136 		g_free (key);
137 	}
138 
139 	stream = soup_session_send (session, msg, NULL, &error);
140 	g_assert_null (stream);
141 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED);
142 
143 	soup_test_session_abort_unref (session);
144 
145 	g_object_unref (msg);
146 }
147 
148 /* Dropping the application's ref on the session from a callback
149  * should not cause the session to be freed at an incorrect time.
150  * (This test will crash if it fails.)
151  */
152 static void
cu_one_completed(SoupMessage * msg,SoupSession * session)153 cu_one_completed (SoupMessage *msg,
154 		  SoupSession *session)
155 {
156 	debug_printf (2, "  Message 1 completed\n");
157 	g_object_unref (session);
158 }
159 
160 static gboolean
cu_idle_quit(gpointer loop)161 cu_idle_quit (gpointer loop)
162 {
163 	g_main_loop_quit (loop);
164 	return FALSE;
165 }
166 
167 static void
cu_two_completed(SoupMessage * msg,GMainLoop * loop)168 cu_two_completed (SoupMessage *msg,
169 		  GMainLoop   *loop)
170 {
171 	debug_printf (2, "  Message 2 completed\n");
172 	g_idle_add (cu_idle_quit, loop);
173 }
174 
175 static void
do_callback_unref_test(void)176 do_callback_unref_test (void)
177 {
178 	SoupServer *bad_server;
179 	SoupSession *session;
180 	SoupMessage *one, *two;
181 	GMainLoop *loop;
182 	GUri *bad_uri;
183 
184 	g_test_bug ("533473");
185 
186 	/* Get a guaranteed-bad URI */
187 	bad_server = soup_test_server_new (SOUP_TEST_SERVER_DEFAULT);
188 	bad_uri = soup_test_server_get_uri (bad_server, "http", NULL);
189 	soup_test_server_quit_unref (bad_server);
190 
191 	session = soup_test_session_new (NULL);
192 	g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session);
193 
194 	loop = g_main_loop_new (NULL, TRUE);
195 
196 	one = soup_message_new_from_uri ("GET", bad_uri);
197 	g_signal_connect (one, "finished",
198 			  G_CALLBACK (cu_one_completed), session);
199 	g_object_add_weak_pointer (G_OBJECT (one), (gpointer *)&one);
200 	two = soup_message_new_from_uri ("GET", bad_uri);
201 	g_signal_connect (two, "finished",
202 			  G_CALLBACK (cu_two_completed), loop);
203 	g_object_add_weak_pointer (G_OBJECT (two), (gpointer *)&two);
204 	g_uri_unref (bad_uri);
205 
206 	soup_session_send_async (session, one, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
207 	soup_session_send_async (session, two, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
208 	g_object_unref (one);
209 	g_object_unref (two);
210 
211 	g_main_loop_run (loop);
212 	g_main_loop_unref (loop);
213 
214 	g_assert_null (session);
215 	if (session) {
216 		g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session);
217 		g_object_unref (session);
218 	}
219 	g_assert_null (one);
220 	if (one) {
221 		g_object_remove_weak_pointer (G_OBJECT (one), (gpointer *)&one);
222 		g_object_unref (one);
223 	}
224 	g_assert_null (two);
225 	if (two) {
226 		g_object_remove_weak_pointer (G_OBJECT (two), (gpointer *)&two);
227 		g_object_unref (two);
228 	}
229 
230 	/* Otherwise, if we haven't crashed, we're ok. */
231 }
232 
233 /* SoupSession should clean up all internal signal handlers on a message after
234  * it is finished, allowing the message to be reused if desired.
235  */
236 static void
ensure_no_signal_handlers(SoupMessage * msg,guint * signal_ids,guint n_signal_ids)237 ensure_no_signal_handlers (SoupMessage *msg, guint *signal_ids, guint n_signal_ids)
238 {
239 	int i;
240 	guint id;
241 
242 	for (i = 0; i < n_signal_ids; i++) {
243 		if (strcmp (g_signal_name (signal_ids[i]), "authenticate") == 0)
244 			continue;
245 
246 		id = g_signal_handler_find (msg, G_SIGNAL_MATCH_ID, signal_ids[i],
247 					    0, NULL, NULL, NULL);
248 		soup_test_assert (id == 0,
249 				  "message has handler for '%s'",
250 				  g_signal_name (signal_ids[i]));
251 	}
252 }
253 
254 static gboolean
reuse_test_authenticate(SoupMessage * msg,SoupAuth * auth,gboolean retrying)255 reuse_test_authenticate (SoupMessage *msg,
256 			 SoupAuth    *auth,
257 			 gboolean     retrying)
258 {
259 	/* Get it wrong the first time, then succeed */
260 	if (!retrying)
261 		soup_auth_authenticate (auth, "user", "wrong password");
262 	else
263 		soup_auth_authenticate (auth, "user", "password");
264 
265 	return TRUE;
266 }
267 
268 static void
reuse_preconnect_finished(SoupSession * session,GAsyncResult * result,GError ** error)269 reuse_preconnect_finished (SoupSession   *session,
270                            GAsyncResult  *result,
271                            GError       **error)
272 {
273         g_assert_false (soup_session_preconnect_finish (session, result, error));
274 }
275 
276 static void
reuse_websocket_connect_finished(SoupSession * session,GAsyncResult * result,GError ** error)277 reuse_websocket_connect_finished (SoupSession   *session,
278                                   GAsyncResult  *result,
279                                   GError       **error)
280 {
281         g_assert_false (soup_session_websocket_connect_finish (session, result, error));
282 }
283 
284 static void
do_msg_reuse_test(void)285 do_msg_reuse_test (void)
286 {
287 	SoupSession *session;
288 	SoupMessage *msg;
289         GBytes *body;
290 	GUri *uri;
291 	guint *signal_ids, n_signal_ids;
292         GInputStream *stream;
293         GError *error = NULL;
294 
295 	g_test_bug ("559054");
296 
297 	signal_ids = g_signal_list_ids (SOUP_TYPE_MESSAGE, &n_signal_ids);
298 
299 	session = soup_test_session_new (NULL);
300 
301 	debug_printf (1, "  First message\n");
302 	msg = soup_message_new_from_uri ("GET", base_uri);
303 	g_signal_connect (msg, "authenticate",
304                           G_CALLBACK (reuse_test_authenticate), NULL);
305 	body = soup_test_session_async_send (session, msg, NULL, NULL);
306         g_assert_nonnull (body);
307 	ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
308         g_bytes_unref (body);
309 
310 	debug_printf (1, "  Redirect message\n");
311 	uri = g_uri_parse_relative (base_uri, "/redirect", SOUP_HTTP_URI_FLAGS, NULL);
312 	soup_message_set_uri (msg, uri);
313 	g_uri_unref (uri);
314 	body = soup_test_session_async_send (session, msg, NULL, NULL);
315         g_assert_nonnull (body);
316 	g_assert_true (soup_uri_equal (soup_message_get_uri (msg), base_uri));
317 	ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
318         g_bytes_unref (body);
319 
320 	debug_printf (1, "  Auth message\n");
321 	uri = g_uri_parse_relative (base_uri, "/auth", SOUP_HTTP_URI_FLAGS, NULL);
322 	soup_message_set_uri (msg, uri);
323 	g_uri_unref (uri);
324 	body = soup_test_session_async_send (session, msg, NULL, NULL);
325         g_assert_nonnull (body);
326 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
327         g_bytes_unref (body);
328 	soup_message_set_uri (msg, base_uri);
329 	body = soup_test_session_async_send (session, msg, NULL, NULL);
330         g_assert_nonnull (body);
331 	ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
332         g_bytes_unref (body);
333 
334         debug_printf (1, "  Reuse before finishing\n");
335         msg = soup_message_new_from_uri ("GET", base_uri);
336         stream = soup_test_request_send (session, msg, NULL, 0, &error);
337         g_assert_no_error (error);
338         g_assert_null (soup_test_request_send (session, msg, NULL, 0, &error));
339         g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_MESSAGE_ALREADY_IN_QUEUE);
340         g_clear_error (&error);
341         g_assert_null (soup_test_session_async_send (session, msg, NULL, &error));
342         g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_MESSAGE_ALREADY_IN_QUEUE);
343         g_clear_error (&error);
344         g_assert_null (soup_session_send (session, msg, NULL, &error));
345         g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_MESSAGE_ALREADY_IN_QUEUE);
346         g_clear_error (&error);
347         g_assert_null (soup_session_send_and_read (session, msg, NULL, &error));
348         g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_MESSAGE_ALREADY_IN_QUEUE);
349         g_clear_error (&error);
350         soup_session_preconnect_async (session, msg, G_PRIORITY_DEFAULT, NULL,
351                                        (GAsyncReadyCallback)reuse_preconnect_finished, &error);
352         while (error == NULL)
353                 g_main_context_iteration (NULL, TRUE);
354         g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_MESSAGE_ALREADY_IN_QUEUE);
355         g_clear_error (&error);
356         soup_session_websocket_connect_async (session, msg, NULL, NULL, G_PRIORITY_DEFAULT, NULL,
357                                               (GAsyncReadyCallback)reuse_websocket_connect_finished, &error);
358         while (error == NULL)
359                 g_main_context_iteration (NULL, TRUE);
360         g_assert_error (error, SOUP_SESSION_ERROR, SOUP_SESSION_ERROR_MESSAGE_ALREADY_IN_QUEUE);
361         g_clear_error (&error);
362         g_object_unref (stream);
363 
364         while (g_main_context_pending (NULL))
365                 g_main_context_iteration (NULL, FALSE);
366 
367         ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
368 
369 	soup_test_session_abort_unref (session);
370 	g_object_unref (msg);
371 	g_free (signal_ids);
372 }
373 
374 /* Handle unexpectedly-early aborts. */
375 static void
ea_msg_completed_one(SoupSession * session,GAsyncResult * result,GMainLoop * loop)376 ea_msg_completed_one (SoupSession  *session,
377 		      GAsyncResult *result,
378 		      GMainLoop    *loop)
379 {
380 	GError *error = NULL;
381 
382 	debug_printf (2, "  Message 1 completed\n");
383 	g_assert_null (soup_session_send_finish (session, result, &error));
384 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
385 	g_clear_error (&error);
386 	g_main_loop_quit (loop);
387 }
388 
389 static gboolean
ea_abort_session(gpointer session)390 ea_abort_session (gpointer session)
391 {
392 	soup_session_abort (session);
393 	return FALSE;
394 }
395 
396 static void
ea_message_network_event(SoupMessage * msg,GSocketClientEvent event,GIOStream * connection,SoupSession * session)397 ea_message_network_event (SoupMessage       *msg,
398 			  GSocketClientEvent event,
399 			  GIOStream         *connection,
400 			  SoupSession       *session)
401 {
402 	if (event != G_SOCKET_CLIENT_RESOLVING)
403 		return;
404 
405 	g_idle_add_full (G_PRIORITY_HIGH,
406 			 ea_abort_session,
407 			 session, NULL);
408 	g_signal_handlers_disconnect_by_func (msg, ea_message_network_event, session);
409 }
410 
411 static void
ea_message_starting(SoupMessage * msg,GCancellable * cancellable)412 ea_message_starting (SoupMessage  *msg,
413 		     GCancellable *cancellable)
414 {
415 	g_cancellable_cancel (cancellable);
416 }
417 
418 static void
do_early_abort_test(void)419 do_early_abort_test (void)
420 {
421 	SoupSession *session;
422 	SoupMessage *msg;
423 	GCancellable *cancellable;
424 	GMainContext *context;
425 	GMainLoop *loop;
426 	GError *error = NULL;
427 
428 	g_test_bug ("596074");
429 	g_test_bug ("618641");
430 
431 	session = soup_test_session_new (NULL);
432 	msg = soup_message_new_from_uri ("GET", base_uri);
433 
434 	context = g_main_context_default ();
435 	loop = g_main_loop_new (context, TRUE);
436 	soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL,
437 				 (GAsyncReadyCallback)ea_msg_completed_one,
438 				 loop);
439 	g_object_unref (msg);
440 	g_main_context_iteration (context, FALSE);
441 
442 	soup_session_abort (session);
443 	while (g_main_context_pending (context))
444 		g_main_context_iteration (context, FALSE);
445 	g_main_loop_unref (loop);
446 	soup_test_session_abort_unref (session);
447 
448 	session = soup_test_session_new (NULL);
449 	msg = soup_message_new_from_uri ("GET", base_uri);
450 
451 	g_signal_connect (msg, "network-event",
452 			  G_CALLBACK (ea_message_network_event),
453 			  session);
454 	g_assert_null (soup_test_session_async_send (session, msg, NULL, &error));
455 	debug_printf (2, "  Message 2 completed\n");
456 
457 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
458 	g_clear_error (&error);
459 	g_object_unref (msg);
460 
461 	while (g_main_context_pending (context))
462 		g_main_context_iteration (context, FALSE);
463 
464 	soup_test_session_abort_unref (session);
465 
466 	g_test_bug ("668098");
467 
468 	session = soup_test_session_new (NULL);
469 	msg = soup_message_new_from_uri ("GET", base_uri);
470 	cancellable = g_cancellable_new ();
471 
472 	g_signal_connect (msg, "starting",
473 			  G_CALLBACK (ea_message_starting), cancellable);
474 	g_assert_null (soup_test_session_async_send (session, msg, cancellable, &error));
475 	debug_printf (2, "  Message 3 completed\n");
476 
477 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
478 	g_clear_error (&error);
479 	g_object_unref (cancellable);
480 	g_object_unref (msg);
481 
482 	while (g_main_context_pending (context))
483 		g_main_context_iteration (context, FALSE);
484 
485 	soup_test_session_abort_unref (session);
486 }
487 
488 static void
do_one_accept_language_test(const char * language,const char * expected_header)489 do_one_accept_language_test (const char *language, const char *expected_header)
490 {
491 	SoupSession *session;
492 	SoupMessage *msg;
493 	const char *val;
494 
495 	debug_printf (1, "  LANGUAGE=%s\n", language);
496 	g_setenv ("LANGUAGE", language, TRUE);
497 	session = soup_test_session_new ("accept-language-auto", TRUE,
498 					 NULL);
499 	msg = soup_message_new_from_uri ("GET", base_uri);
500 	soup_test_session_send_message (session, msg);
501 	soup_test_session_abort_unref (session);
502 
503 	soup_test_assert_message_status (msg, SOUP_STATUS_OK);
504 	val = soup_message_headers_get_list (soup_message_get_request_headers (msg),
505 					     "Accept-Language");
506 	g_assert_cmpstr (val, ==, expected_header);
507 
508 	g_object_unref (msg);
509 }
510 
511 static void
do_accept_language_test(void)512 do_accept_language_test (void)
513 {
514 	const char *orig_language;
515 
516 	g_test_bug ("602547");
517 
518 	orig_language = g_getenv ("LANGUAGE");
519 	do_one_accept_language_test ("C", "en");
520 	do_one_accept_language_test ("fr_FR", "fr-fr, fr;q=0.9");
521 	do_one_accept_language_test ("fr_FR:de:en_US", "fr-fr, fr;q=0.9, de;q=0.8, en-us;q=0.7, en;q=0.6");
522 
523 	if (orig_language)
524 		g_setenv ("LANGUAGE", orig_language, TRUE);
525 	else
526 		g_unsetenv ("LANGUAGE");
527 }
528 
529 static gboolean
cancel_message_timeout(GCancellable * cancellable)530 cancel_message_timeout (GCancellable *cancellable)
531 {
532 	g_cancellable_cancel (cancellable);
533 	return FALSE;
534 }
535 
536 static void
do_cancel_while_reading_test_for_session(SoupSession * session)537 do_cancel_while_reading_test_for_session (SoupSession *session)
538 {
539 	SoupMessage *msg;
540 	GUri *uri;
541 	GCancellable *cancellable;
542 	GError *error = NULL;
543 
544 	uri = g_uri_parse_relative (base_uri, "/slow", SOUP_HTTP_URI_FLAGS, NULL);
545 	msg = soup_message_new_from_uri ("GET", uri);
546 	g_uri_unref (uri);
547 
548 	cancellable = g_cancellable_new ();
549 	g_timeout_add_full (G_PRIORITY_DEFAULT, 100,
550 			    (GSourceFunc)cancel_message_timeout,
551 			    g_object_ref (cancellable),
552 			    g_object_unref);
553 
554 	g_assert_null (soup_test_session_async_send (session, msg, cancellable, &error));
555 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
556 	g_clear_error (&error);
557 	g_object_unref (cancellable);
558 	g_object_unref (msg);
559 }
560 
561 static void
do_cancel_while_reading_test(void)562 do_cancel_while_reading_test (void)
563 {
564 	SoupSession *session;
565 
566 	g_test_bug ("637741");
567 	g_test_bug ("676038");
568 
569 	session = soup_test_session_new (NULL);
570 	do_cancel_while_reading_test_for_session (session);
571 	soup_test_session_abort_unref (session);
572 }
573 
574 static void
do_cancel_while_reading_req_test_for_session(SoupSession * session,guint flags)575 do_cancel_while_reading_req_test_for_session (SoupSession *session,
576 					      guint flags)
577 {
578 	SoupMessage *msg;
579 	GUri *uri;
580 	GCancellable *cancellable;
581 	GError *error = NULL;
582 
583 	uri = g_uri_parse_relative (base_uri, "/slow", SOUP_HTTP_URI_FLAGS, NULL);
584 	msg = soup_message_new_from_uri ("GET", uri);
585 	g_uri_unref (uri);
586 
587 	cancellable = g_cancellable_new ();
588 	soup_test_request_send (session, msg, cancellable, flags, &error);
589 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
590 	g_clear_error (&error);
591 
592 	g_object_unref (msg);
593 	g_object_unref (cancellable);
594 }
595 
596 static void
do_cancel_while_reading_immediate_req_test(void)597 do_cancel_while_reading_immediate_req_test (void)
598 {
599 	SoupSession *session;
600 	guint flags;
601 
602 	g_test_bug ("692310");
603 
604 	flags = SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
605 
606 	session = soup_test_session_new (NULL);
607 	do_cancel_while_reading_req_test_for_session (session, flags);
608 	soup_test_session_abort_unref (session);
609 }
610 
611 static void
do_cancel_while_reading_delayed_req_test(void)612 do_cancel_while_reading_delayed_req_test (void)
613 {
614 	SoupSession *session;
615 	guint flags;
616 
617 	flags = SOUP_TEST_REQUEST_CANCEL_SOON;
618 
619 	session = soup_test_session_new (NULL);
620 	do_cancel_while_reading_req_test_for_session (session, flags);
621 	soup_test_session_abort_unref (session);
622 }
623 
624 static void
do_cancel_while_reading_preemptive_req_test(void)625 do_cancel_while_reading_preemptive_req_test (void)
626 {
627 	SoupSession *session;
628 	guint flags;
629 
630 	g_test_bug ("637039");
631 
632 	flags = SOUP_TEST_REQUEST_CANCEL_PREEMPTIVE;
633 
634 	session = soup_test_session_new (NULL);
635 	do_cancel_while_reading_req_test_for_session (session, flags);
636 	soup_test_session_abort_unref (session);
637 }
638 
639 static void
do_one_cancel_after_send_request_test(SoupSession * session,gboolean reuse_cancellable,gboolean cancelled_by_session)640 do_one_cancel_after_send_request_test (SoupSession *session,
641                                        gboolean     reuse_cancellable,
642                                        gboolean     cancelled_by_session)
643 {
644         SoupMessage *msg;
645         GCancellable *cancellable;
646         GInputStream *istream;
647         GOutputStream *ostream;
648         guint flags = SOUP_TEST_REQUEST_CANCEL_AFTER_SEND_FINISH;
649         GBytes *body;
650         GError *error = NULL;
651 
652         if (cancelled_by_session)
653                 flags |= SOUP_TEST_REQUEST_CANCEL_BY_SESSION;
654 
655         msg = soup_message_new_from_uri ("GET", base_uri);
656         cancellable = g_cancellable_new ();
657         istream = soup_test_request_send (session, msg, cancellable, flags, &error);
658         g_assert_no_error (error);
659         g_assert_nonnull (istream);
660 
661         /* If we use a new cancellable to read the stream
662          * it shouldn't fail with cancelled error.
663          */
664         if (!reuse_cancellable) {
665                 g_object_unref (cancellable);
666                 cancellable = g_cancellable_new ();
667         }
668         ostream = g_memory_output_stream_new_resizable ();
669         g_output_stream_splice (ostream, istream,
670                                 G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
671                                 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
672                                 cancellable, &error);
673 
674         if (reuse_cancellable || cancelled_by_session) {
675                 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
676                 g_clear_error (&error);
677         } else {
678                 g_assert_no_error (error);
679                 body = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (ostream));
680                 g_assert_cmpstr (g_bytes_get_data (body, NULL), ==, "index");
681                 g_bytes_unref (body);
682         }
683 
684         while (g_main_context_pending (NULL))
685 		g_main_context_iteration (NULL, FALSE);
686 
687         g_object_unref (cancellable);
688         g_object_unref (ostream);
689         g_object_unref (istream);
690         g_object_unref (msg);
691 }
692 
693 static void
do_cancel_after_send_request_tests(void)694 do_cancel_after_send_request_tests (void)
695 {
696         SoupSession *session;
697 
698         session = soup_test_session_new (NULL);
699         do_one_cancel_after_send_request_test (session, TRUE, FALSE);
700         do_one_cancel_after_send_request_test (session, FALSE, FALSE);
701         do_one_cancel_after_send_request_test (session, FALSE, TRUE);
702         soup_test_session_abort_unref (session);
703 }
704 
705 static void
do_msg_flags_test(void)706 do_msg_flags_test (void)
707 {
708 	SoupMessage *msg;
709 
710 	msg = soup_message_new ("GET", "http://foo.org");
711 
712 	/* Flags are initially empty */
713 	g_assert_cmpuint (soup_message_get_flags (msg), ==, 0);
714 	g_assert_false (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT));
715 
716 	/* Set a single flag */
717 	soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
718 	g_assert_cmpuint (soup_message_get_flags (msg), ==, SOUP_MESSAGE_NO_REDIRECT);
719 	g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT));
720 	g_assert_false (soup_message_query_flags (msg, SOUP_MESSAGE_NEW_CONNECTION));
721 
722 	/* Add another flag */
723 	soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
724 	g_assert_cmpuint (soup_message_get_flags (msg), ==, (SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION));
725 	g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION));
726 
727 	/* Add an existing flag */
728 	soup_message_add_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
729 	g_assert_cmpuint (soup_message_get_flags (msg), ==, (SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION));
730         g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION));
731 
732 	/* Remove a single flag */
733 	soup_message_remove_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
734 	g_assert_cmpuint (soup_message_get_flags (msg), ==, SOUP_MESSAGE_NO_REDIRECT);
735         g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT));
736         g_assert_false (soup_message_query_flags (msg, SOUP_MESSAGE_NEW_CONNECTION));
737 
738 	/* Remove a non-existing flag */
739 	soup_message_remove_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
740 	g_assert_cmpuint (soup_message_get_flags (msg), ==, SOUP_MESSAGE_NO_REDIRECT);
741         g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT));
742         g_assert_false (soup_message_query_flags (msg, SOUP_MESSAGE_NEW_CONNECTION));
743 
744 	/* Add a set of flags */
745 	soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION | SOUP_MESSAGE_IDEMPOTENT | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE);
746 	g_assert_cmpuint (soup_message_get_flags (msg), ==, (SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION | SOUP_MESSAGE_IDEMPOTENT | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE));
747 	g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION | SOUP_MESSAGE_IDEMPOTENT | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE));
748 
749 	/* Remove a set of flags */
750 	soup_message_remove_flags (msg, (SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_IDEMPOTENT));
751 	g_assert_cmpuint (soup_message_get_flags (msg), ==, (SOUP_MESSAGE_NEW_CONNECTION | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE));
752 	g_assert_true (soup_message_query_flags (msg, SOUP_MESSAGE_NEW_CONNECTION | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE));
753 
754 	/* Remove all flags */
755 	soup_message_set_flags (msg, 0);
756 	g_assert_cmpuint (soup_message_get_flags (msg), ==, 0);
757         g_assert_false (soup_message_query_flags (msg, SOUP_MESSAGE_NO_REDIRECT | SOUP_MESSAGE_NEW_CONNECTION | SOUP_MESSAGE_IDEMPOTENT | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE));
758 
759 	g_object_unref (msg);
760 }
761 
762 static void
do_connection_id_test(void)763 do_connection_id_test (void)
764 {
765         SoupSession *session = soup_test_session_new (NULL);
766         SoupMessage *msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
767 
768         /* Test that the ID is set for each new connection and that it is
769          * cached after the message is completed */
770 
771         g_assert_cmpuint (soup_message_get_connection_id (msg), ==, 0);
772 
773         guint status = soup_test_session_send_message (session, msg);
774 
775         g_assert_cmpuint (status, ==, SOUP_STATUS_OK);
776         g_assert_cmpuint (soup_message_get_connection_id (msg), ==, 1);
777 
778         status = soup_test_session_send_message (session, msg);
779 
780         g_assert_cmpuint (status, ==, SOUP_STATUS_OK);
781         g_assert_cmpuint (soup_message_get_connection_id (msg), ==, 2);
782 
783 	GUri *uri = g_uri_parse_relative (base_uri, "/redirect", SOUP_HTTP_URI_FLAGS, NULL);
784 	soup_message_set_uri (msg, uri);
785         g_uri_unref (uri);
786 
787         status = soup_test_session_send_message (session, msg);
788 
789         g_assert_cmpuint (status, ==, SOUP_STATUS_OK);
790         g_assert_cmpuint (soup_message_get_connection_id (msg), ==, 3);
791 
792         g_object_unref (msg);
793         soup_test_session_abort_unref (session);
794 }
795 
796 static void
do_remote_address_test(void)797 do_remote_address_test (void)
798 {
799         SoupSession *session;
800         SoupMessage *msg1, *msg2;
801         GBytes *body;
802 
803         session = soup_test_session_new (NULL);
804 
805         msg1 = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
806         g_assert_null (soup_message_get_remote_address (msg1));
807         body = soup_test_session_async_send (session, msg1, NULL, NULL);
808         g_assert_nonnull (soup_message_get_remote_address (msg1));
809         g_bytes_unref (body);
810 
811         /* In case of reusing an idle conection, we still get a remote address */
812         msg2 = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
813         g_assert_null (soup_message_get_remote_address (msg2));
814         body = soup_test_session_async_send (session, msg2, NULL, NULL);
815         g_assert_cmpuint (soup_message_get_connection_id (msg1), ==, soup_message_get_connection_id (msg2));
816         g_assert_true (soup_message_get_remote_address (msg1) == soup_message_get_remote_address (msg2));
817         g_bytes_unref (body);
818         g_object_unref (msg2);
819 
820         /* We get a new one if we force a new connection */
821         msg2 = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
822         soup_message_add_flags (msg2, SOUP_MESSAGE_NEW_CONNECTION);
823         g_assert_null (soup_message_get_remote_address (msg2));
824         body = soup_test_session_async_send (session, msg2, NULL, NULL);
825         g_assert_nonnull (soup_message_get_remote_address (msg2));
826         g_assert_cmpuint (soup_message_get_connection_id (msg1), !=, soup_message_get_connection_id (msg2));
827         g_assert_false (soup_message_get_remote_address (msg1) == soup_message_get_remote_address (msg2));
828         g_bytes_unref (body);
829         g_object_unref (msg2);
830 
831         g_object_unref (msg1);
832         soup_test_session_abort_unref (session);
833 }
834 
835 static void
redirect_handler(SoupMessage * msg,SoupSession * session)836 redirect_handler (SoupMessage *msg,
837                   SoupSession *session)
838 {
839         SoupMessage *new_msg;
840         GBytes *body;
841 
842         new_msg = soup_message_new_from_uri ("GET", base_uri);
843         body = soup_test_session_async_send (session, new_msg, NULL, NULL);
844         g_assert_nonnull (body);
845         g_assert_cmpstr (g_bytes_get_data (body, NULL), ==, "index");
846         g_object_unref (new_msg);
847 }
848 
849 static void
do_new_request_on_redirect_test(void)850 do_new_request_on_redirect_test (void)
851 {
852         SoupSession *session;
853         GUri *uri;
854         SoupMessage *msg;
855         GBytes *body;
856 
857         session = soup_test_session_new (NULL);
858 
859         uri = g_uri_parse_relative (base_uri, "/redirect", SOUP_HTTP_URI_FLAGS, NULL);
860         msg = soup_message_new_from_uri ("GET", uri);
861         g_signal_connect_after (msg, "got-body",
862                                 G_CALLBACK (redirect_handler),
863                                 session);
864         body = soup_test_session_async_send (session, msg, NULL, NULL);
865         g_assert_nonnull (body);
866         g_assert_cmpstr (g_bytes_get_data (body, NULL), ==, "index");
867 
868         g_bytes_unref (body);
869         g_object_unref (msg);
870         g_uri_unref (uri);
871         soup_test_session_abort_unref (session);
872 }
873 
874 static void
wrote_informational_check_content_length(SoupServerMessage * msg,gpointer user_data)875 wrote_informational_check_content_length (SoupServerMessage *msg,
876                                           gpointer           user_data)
877 {
878         SoupMessageHeaders *response_headers;
879 
880         response_headers = soup_server_message_get_response_headers (msg);
881         g_assert_null (soup_message_headers_get_one (response_headers, "Content-Length"));
882 }
883 
884 static void
upgrade_server_check_content_length_callback(SoupServer * server,SoupServerMessage * msg,const char * path,GHashTable * query,gpointer data)885 upgrade_server_check_content_length_callback (SoupServer        *server,
886                                               SoupServerMessage *msg,
887                                               const char        *path,
888                                               GHashTable        *query,
889                                               gpointer           data)
890 {
891         SoupMessageHeaders *request_headers;
892 
893         if (soup_server_message_get_method (msg) != SOUP_METHOD_GET) {
894                 soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL);
895                 return;
896         }
897 
898         soup_server_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS, NULL);
899 
900         request_headers = soup_server_message_get_request_headers (msg);
901         soup_message_headers_append (request_headers, "Upgrade", "ECHO");
902         soup_message_headers_append (request_headers, "Connection", "upgrade");
903 
904         g_signal_connect (msg, "wrote-informational",
905                           G_CALLBACK (wrote_informational_check_content_length), NULL);
906 }
907 
908 static void
switching_protocols_check_length(SoupMessage * msg,gpointer user_data)909 switching_protocols_check_length (SoupMessage *msg,
910                                   gpointer     user_data)
911 {
912         SoupMessageHeaders *response_headers;
913 
914         response_headers = soup_message_get_response_headers (msg);
915         g_assert_null (soup_message_headers_get_one (response_headers, "Content-Length"));
916 }
917 
918 static void
do_response_informational_content_length_test(void)919 do_response_informational_content_length_test (void)
920 {
921         SoupServer *server;
922         SoupSession *session;
923         SoupMessage *msg;
924         SoupMessageHeaders *request_headers;
925 
926         server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
927         soup_server_add_handler (server, NULL, upgrade_server_check_content_length_callback, NULL, NULL);
928 
929         session = soup_test_session_new (NULL);
930         msg = soup_message_new_from_uri ("GET", base_uri);
931         request_headers = soup_message_get_request_headers (msg);
932         soup_message_headers_append (request_headers, "Upgrade", "echo");
933         soup_message_headers_append (request_headers, "Connection", "upgrade");
934 
935         soup_message_add_status_code_handler (msg, "got-informational",
936                                               SOUP_STATUS_SWITCHING_PROTOCOLS,
937                                               G_CALLBACK (switching_protocols_check_length), NULL);
938 
939         soup_test_session_send_message (session, msg);
940         g_object_unref (msg);
941 
942         soup_test_session_abort_unref (session);
943         soup_test_server_quit_unref (server);
944 }
945 
946 static void
do_invalid_utf8_headers_test(void)947 do_invalid_utf8_headers_test (void)
948 {
949         SoupSession *session;
950         SoupMessage *msg;
951         GUri *uri;
952         SoupMessageHeaders *headers;
953         guint status;
954         const char *header_value;
955 
956         session = soup_test_session_new (NULL);
957 
958         uri = g_uri_parse_relative (base_uri, "/invalid_utf8_headers", SOUP_HTTP_URI_FLAGS, NULL);
959         msg = soup_message_new_from_uri ("GET", uri);
960 
961         status = soup_test_session_send_message (session, msg);
962         g_assert_cmpuint (status, ==, SOUP_STATUS_OK);
963 
964         headers = soup_message_get_response_headers (msg);
965         header_value = soup_message_headers_get_one (headers, "InvalidValue");
966         g_assert_nonnull (header_value);
967         g_assert_true (g_utf8_validate (header_value, -1, NULL));
968 
969         g_object_unref (msg);
970         g_uri_unref (uri);
971         soup_test_session_abort_unref (session);
972 }
973 
974 int
main(int argc,char ** argv)975 main (int argc, char **argv)
976 {
977 	SoupAuthDomain *auth_domain;
978 	int ret;
979 
980 	test_init (argc, argv, NULL);
981 
982 	server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
983 	soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
984 	base_uri = soup_test_server_get_uri (server, "http", NULL);
985 
986 	auth_domain = soup_auth_domain_basic_new (
987 		"realm", "misc-test",
988 		"auth-callback", auth_callback,
989 		NULL);
990         soup_auth_domain_add_path (auth_domain, "/auth");
991 	soup_server_add_auth_domain (server, auth_domain);
992 	g_object_unref (auth_domain);
993 
994 	g_test_add_func ("/misc/bigheader", do_host_big_header);
995 	g_test_add_func ("/misc/host", do_host_test);
996 	g_test_add_func ("/misc/callback-unref/msg", do_callback_unref_test);
997 	g_test_add_func ("/misc/msg-reuse", do_msg_reuse_test);
998 	g_test_add_func ("/misc/early-abort/msg", do_early_abort_test);
999 	g_test_add_func ("/misc/accept-language", do_accept_language_test);
1000 	g_test_add_func ("/misc/cancel-while-reading/msg", do_cancel_while_reading_test);
1001 	g_test_add_func ("/misc/cancel-while-reading/req/immediate", do_cancel_while_reading_immediate_req_test);
1002 	g_test_add_func ("/misc/cancel-while-reading/req/delayed", do_cancel_while_reading_delayed_req_test);
1003 	g_test_add_func ("/misc/cancel-while-reading/req/preemptive", do_cancel_while_reading_preemptive_req_test);
1004         g_test_add_func ("/misc/cancel-after-send-request", do_cancel_after_send_request_tests);
1005 	g_test_add_func ("/misc/msg-flags", do_msg_flags_test);
1006         g_test_add_func ("/misc/connection-id", do_connection_id_test);
1007         g_test_add_func ("/misc/remote-address", do_remote_address_test);
1008         g_test_add_func ("/misc/new-request-on-redirect", do_new_request_on_redirect_test);
1009         g_test_add_func ("/misc/response/informational/content-length", do_response_informational_content_length_test);
1010         g_test_add_func ("/misc/invalid-utf8-headers", do_invalid_utf8_headers_test);
1011 
1012 	ret = g_test_run ();
1013 
1014 	g_uri_unref (base_uri);
1015 	soup_test_server_quit_unref (server);
1016 
1017 	test_cleanup ();
1018 	return ret;
1019 }
1020