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