1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2011 Red Hat, Inc.
4 */
5
6 /* Kill SoupRequester-related deprecation warnings */
7 #define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_40
8
9 #include "test-utils.h"
10
11 SoupServer *server;
12 GMainLoop *loop;
13 char buf[1024];
14
15 SoupBuffer *response, *auth_response;
16
17 #define REDIRECT_HTML_BODY "<html><body>Try again</body></html>\r\n"
18 #define AUTH_HTML_BODY "<html><body>Unauthorized</body></html>\r\n"
19
20 typedef enum {
21 NO_CANCEL,
22 SYNC_CANCEL,
23 PAUSE_AND_CANCEL_ON_IDLE
24 } CancelPolicy;
25
26 static gboolean
slow_finish_message(gpointer msg)27 slow_finish_message (gpointer msg)
28 {
29 SoupServer *server = g_object_get_data (G_OBJECT (msg), "server");
30
31 soup_server_unpause_message (server, msg);
32 return FALSE;
33 }
34
35 static void
slow_pause_message(SoupMessage * msg,gpointer server)36 slow_pause_message (SoupMessage *msg, gpointer server)
37 {
38 soup_server_pause_message (server, msg);
39 soup_add_timeout (soup_server_get_async_context (server),
40 1000, slow_finish_message, msg);
41 }
42
43 static void
server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)44 server_callback (SoupServer *server, SoupMessage *msg,
45 const char *path, GHashTable *query,
46 SoupClientContext *context, gpointer data)
47 {
48 gboolean chunked = FALSE;
49 int i;
50
51 if (strcmp (path, "/auth") == 0) {
52 soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
53 soup_message_set_response (msg, "text/html",
54 SOUP_MEMORY_STATIC,
55 AUTH_HTML_BODY,
56 strlen (AUTH_HTML_BODY));
57 soup_message_headers_append (msg->response_headers,
58 "WWW-Authenticate",
59 "Basic: realm=\"requester-test\"");
60 return;
61 } else if (strcmp (path, "/foo") == 0) {
62 soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/");
63 /* Make the response HTML so if we sniff that instead of the
64 * real body, we'll notice.
65 */
66 soup_message_set_response (msg, "text/html",
67 SOUP_MEMORY_STATIC,
68 REDIRECT_HTML_BODY,
69 strlen (REDIRECT_HTML_BODY));
70 return;
71 } else if (strcmp (path, "/chunked") == 0) {
72 chunked = TRUE;
73 } else if (strcmp (path, "/non-persistent") == 0) {
74 soup_message_headers_append (msg->response_headers,
75 "Connection", "close");
76 } else if (!strcmp (path, "/slow")) {
77 g_object_set_data (G_OBJECT (msg), "server", server);
78 g_signal_connect (msg, "wrote-headers",
79 G_CALLBACK (slow_pause_message), server);
80 }
81
82 soup_message_set_status (msg, SOUP_STATUS_OK);
83
84 if (chunked) {
85 soup_message_headers_set_encoding (msg->response_headers,
86 SOUP_ENCODING_CHUNKED);
87
88 for (i = 0; i < response->length; i += 8192) {
89 SoupBuffer *tmp;
90
91 tmp = soup_buffer_new_subbuffer (response, i,
92 MIN (8192, response->length - i));
93 soup_message_body_append_buffer (msg->response_body, tmp);
94 soup_buffer_free (tmp);
95 }
96 soup_message_body_complete (msg->response_body);
97 } else
98 soup_message_body_append_buffer (msg->response_body, response);
99 }
100
101 typedef struct {
102 GString *body;
103 gboolean cancel;
104 } RequestData;
105
106 static void
stream_closed(GObject * source,GAsyncResult * res,gpointer user_data)107 stream_closed (GObject *source, GAsyncResult *res, gpointer user_data)
108 {
109 GInputStream *stream = G_INPUT_STREAM (source);
110 GError *error = NULL;
111
112 g_input_stream_close_finish (stream, res, &error);
113 g_assert_no_error (error);
114 g_main_loop_quit (loop);
115 g_object_unref (stream);
116 }
117
118 static void
test_read_ready(GObject * source,GAsyncResult * res,gpointer user_data)119 test_read_ready (GObject *source, GAsyncResult *res, gpointer user_data)
120 {
121 GInputStream *stream = G_INPUT_STREAM (source);
122 RequestData *data = user_data;
123 GString *body = data->body;
124 GError *error = NULL;
125 gsize nread;
126
127 nread = g_input_stream_read_finish (stream, res, &error);
128 if (nread == -1) {
129 g_assert_no_error (error);
130 g_error_free (error);
131 g_input_stream_close (stream, NULL, NULL);
132 g_object_unref (stream);
133 g_main_loop_quit (loop);
134 return;
135 } else if (nread == 0) {
136 g_input_stream_close_async (stream,
137 G_PRIORITY_DEFAULT, NULL,
138 stream_closed, NULL);
139 return;
140 }
141
142 g_string_append_len (body, buf, nread);
143 g_input_stream_read_async (stream, buf, sizeof (buf),
144 G_PRIORITY_DEFAULT, NULL,
145 test_read_ready, data);
146 }
147
148 static void
auth_test_sent(GObject * source,GAsyncResult * res,gpointer user_data)149 auth_test_sent (GObject *source, GAsyncResult *res, gpointer user_data)
150 {
151 RequestData *data = user_data;
152 GInputStream *stream;
153 GError *error = NULL;
154 SoupMessage *msg;
155 const char *content_type;
156
157 stream = soup_request_send_finish (SOUP_REQUEST (source), res, &error);
158 if (!stream) {
159 g_assert_no_error (error);
160 g_clear_error (&error);
161 g_main_loop_quit (loop);
162 return;
163 }
164
165 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (source));
166 soup_test_assert_message_status (msg, SOUP_STATUS_UNAUTHORIZED);
167 g_object_unref (msg);
168
169 content_type = soup_request_get_content_type (SOUP_REQUEST (source));
170 g_assert_cmpstr (content_type, ==, "text/html");
171
172 g_input_stream_read_async (stream, buf, sizeof (buf),
173 G_PRIORITY_DEFAULT, NULL,
174 test_read_ready, data);
175 }
176
177 static void
test_sent(GObject * source,GAsyncResult * res,gpointer user_data)178 test_sent (GObject *source, GAsyncResult *res, gpointer user_data)
179 {
180 RequestData *data = user_data;
181 GInputStream *stream;
182 GError *error = NULL;
183 const char *content_type;
184
185 stream = soup_request_send_finish (SOUP_REQUEST (source), res, &error);
186 if (data->cancel) {
187 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
188 g_clear_error (&error);
189 g_main_loop_quit (loop);
190 return;
191 } else {
192 g_assert_no_error (error);
193 if (!stream) {
194 g_main_loop_quit (loop);
195 g_clear_error (&error);
196 return;
197 }
198 }
199
200 content_type = soup_request_get_content_type (SOUP_REQUEST (source));
201 g_assert_cmpstr (content_type, ==, "text/plain");
202
203 g_input_stream_read_async (stream, buf, sizeof (buf),
204 G_PRIORITY_DEFAULT, NULL,
205 test_read_ready, data);
206 }
207
208 static void
cancel_message(SoupMessage * msg,gpointer session)209 cancel_message (SoupMessage *msg, gpointer session)
210 {
211 soup_session_cancel_message (session, msg, SOUP_STATUS_FORBIDDEN);
212 }
213
214 typedef struct {
215 SoupMessage *msg;
216 SoupSession *session;
217 } CancelData;
218
219 static gboolean
cancel_message_idle(CancelData * data)220 cancel_message_idle (CancelData *data)
221 {
222 cancel_message (data->msg, data->session);
223 return FALSE;
224 }
225
226 static void
pause_and_cancel_message(SoupMessage * msg,gpointer session)227 pause_and_cancel_message (SoupMessage *msg, gpointer session)
228 {
229 CancelData *data = g_new (CancelData, 1);
230 GSource *source = g_idle_source_new ();
231
232 soup_session_pause_message (session, msg);
233 data->msg = msg;
234 data->session = session;
235 g_source_set_callback (source, (GSourceFunc)cancel_message_idle, data, g_free);
236 g_source_attach (source, soup_session_get_async_context (session));
237 g_source_unref (source);
238 }
239
240 static void
request_started(SoupSession * session,SoupMessage * msg,SoupSocket * socket,gpointer user_data)241 request_started (SoupSession *session, SoupMessage *msg,
242 SoupSocket *socket, gpointer user_data)
243 {
244 SoupSocket **save_socket = user_data;
245
246 g_clear_object (save_socket);
247 *save_socket = g_object_ref (socket);
248 }
249
250 static void
do_async_test(SoupSession * session,SoupURI * uri,GAsyncReadyCallback callback,guint expected_status,SoupBuffer * expected_response,gboolean persistent,CancelPolicy cancel_policy)251 do_async_test (SoupSession *session, SoupURI *uri,
252 GAsyncReadyCallback callback, guint expected_status,
253 SoupBuffer *expected_response,
254 gboolean persistent, CancelPolicy cancel_policy)
255 {
256 SoupRequester *requester;
257 SoupRequest *request;
258 guint started_id;
259 SoupSocket *socket = NULL;
260 SoupMessage *msg;
261 RequestData data;
262
263 if (SOUP_IS_SESSION_ASYNC (session))
264 requester = SOUP_REQUESTER (soup_session_get_feature (session, SOUP_TYPE_REQUESTER));
265 else
266 requester = NULL;
267
268 data.body = g_string_new (NULL);
269 data.cancel = cancel_policy != NO_CANCEL;
270 if (requester)
271 request = soup_requester_request_uri (requester, uri, NULL);
272 else
273 request = soup_session_request_uri (session, uri, NULL);
274 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
275
276 switch (cancel_policy) {
277 case SYNC_CANCEL:
278 g_signal_connect (msg, "got-headers",
279 G_CALLBACK (cancel_message), session);
280 break;
281 case PAUSE_AND_CANCEL_ON_IDLE:
282 g_signal_connect (msg, "got-headers",
283 G_CALLBACK (pause_and_cancel_message), session);
284 break;
285 case NO_CANCEL:
286 break;
287 }
288
289 started_id = g_signal_connect (session, "request-started",
290 G_CALLBACK (request_started),
291 &socket);
292
293 soup_request_send_async (request, NULL, callback, &data);
294 g_object_unref (request);
295
296 loop = g_main_loop_new (soup_session_get_async_context (session), TRUE);
297 g_main_loop_run (loop);
298 g_main_loop_unref (loop);
299
300 g_signal_handler_disconnect (session, started_id);
301
302 soup_test_assert_message_status (msg, expected_status);
303 g_object_unref (msg);
304
305 if (expected_response) {
306 soup_assert_cmpmem (data.body->str, data.body->len,
307 expected_response->data, expected_response->length);
308 } else
309 g_assert_cmpint (data.body->len, ==, 0);
310
311 if (persistent)
312 g_assert_true (soup_socket_is_connected (socket));
313 else
314 g_assert_false (soup_socket_is_connected (socket));
315
316 g_object_unref (socket);
317
318 g_string_free (data.body, TRUE);
319 }
320
321 static void
do_test_for_thread_and_context(SoupSession * session,SoupURI * base_uri)322 do_test_for_thread_and_context (SoupSession *session, SoupURI *base_uri)
323 {
324 SoupRequester *requester;
325 SoupURI *uri;
326
327 if (SOUP_IS_SESSION_ASYNC (session)) {
328 requester = soup_requester_new ();
329 soup_session_add_feature (session, SOUP_SESSION_FEATURE (requester));
330 g_object_unref (requester);
331 }
332 soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_SNIFFER);
333
334 debug_printf (1, " basic test\n");
335 do_async_test (session, base_uri, test_sent,
336 SOUP_STATUS_OK, response,
337 TRUE, NO_CANCEL);
338
339 debug_printf (1, " chunked test\n");
340 uri = soup_uri_new_with_base (base_uri, "/chunked");
341 do_async_test (session, uri, test_sent,
342 SOUP_STATUS_OK, response,
343 TRUE, NO_CANCEL);
344 soup_uri_free (uri);
345
346 debug_printf (1, " auth test\n");
347 uri = soup_uri_new_with_base (base_uri, "/auth");
348 do_async_test (session, uri, auth_test_sent,
349 SOUP_STATUS_UNAUTHORIZED, auth_response,
350 TRUE, NO_CANCEL);
351 soup_uri_free (uri);
352
353 debug_printf (1, " non-persistent test\n");
354 uri = soup_uri_new_with_base (base_uri, "/non-persistent");
355 do_async_test (session, uri, test_sent,
356 SOUP_STATUS_OK, response,
357 FALSE, NO_CANCEL);
358 soup_uri_free (uri);
359
360 debug_printf (1, " cancellation test\n");
361 uri = soup_uri_new_with_base (base_uri, "/");
362 do_async_test (session, uri, test_sent,
363 SOUP_STATUS_FORBIDDEN, NULL,
364 FALSE, SYNC_CANCEL);
365 soup_uri_free (uri);
366
367 debug_printf (1, " cancellation after paused test\n");
368 uri = soup_uri_new_with_base (base_uri, "/");
369 do_async_test (session, uri, test_sent,
370 SOUP_STATUS_FORBIDDEN, NULL,
371 FALSE, PAUSE_AND_CANCEL_ON_IDLE);
372 soup_uri_free (uri);
373 }
374
375 static void
do_simple_plain_test(gconstpointer data)376 do_simple_plain_test (gconstpointer data)
377 {
378 SoupURI *uri = (SoupURI *)data;
379 SoupSession *session;
380
381 g_test_bug ("653707");
382
383 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
384 do_test_for_thread_and_context (session, uri);
385 soup_test_session_abort_unref (session);
386 }
387
388 static void
do_simple_async_test(gconstpointer data)389 do_simple_async_test (gconstpointer data)
390 {
391 SoupURI *uri = (SoupURI *)data;
392 SoupSession *session;
393
394 g_test_bug ("653707");
395
396 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
397 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
398 NULL);
399 do_test_for_thread_and_context (session, uri);
400 soup_test_session_abort_unref (session);
401 }
402
403 static void
do_test_with_context_and_type(SoupURI * uri,gboolean plain_session)404 do_test_with_context_and_type (SoupURI *uri, gboolean plain_session)
405 {
406 GMainContext *async_context;
407 SoupSession *session;
408
409 g_test_bug ("653707");
410
411 async_context = g_main_context_new ();
412 g_main_context_push_thread_default (async_context);
413
414 session = soup_test_session_new (plain_session ? SOUP_TYPE_SESSION : SOUP_TYPE_SESSION_ASYNC,
415 SOUP_SESSION_ASYNC_CONTEXT, async_context,
416 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
417 NULL);
418
419 do_test_for_thread_and_context (session, uri);
420 soup_test_session_abort_unref (session);
421
422 g_main_context_pop_thread_default (async_context);
423 g_main_context_unref (async_context);
424 }
425
426 static void
do_async_test_with_context(gconstpointer data)427 do_async_test_with_context (gconstpointer data)
428 {
429 SoupURI *uri = (SoupURI *)data;
430
431 do_test_with_context_and_type (uri, FALSE);
432 }
433
434 static void
do_plain_test_with_context(gconstpointer data)435 do_plain_test_with_context (gconstpointer data)
436 {
437 SoupURI *uri = (SoupURI *)data;
438
439 do_test_with_context_and_type (uri, TRUE);
440 }
441
442 static gpointer
async_test_thread(gpointer uri)443 async_test_thread (gpointer uri)
444 {
445 do_test_with_context_and_type (uri, TRUE);
446 return NULL;
447 }
448
449 static gpointer
plain_test_thread(gpointer uri)450 plain_test_thread (gpointer uri)
451 {
452 do_test_with_context_and_type (uri, FALSE);
453 return NULL;
454 }
455
456 static void
do_async_test_in_thread(gconstpointer data)457 do_async_test_in_thread (gconstpointer data)
458 {
459 SoupURI *uri = (SoupURI *)data;
460 GThread *thread;
461
462 thread = g_thread_new ("do_async_test_in_thread",
463 async_test_thread,
464 (gpointer)uri);
465 g_thread_join (thread);
466 }
467
468 static void
do_plain_test_in_thread(gconstpointer data)469 do_plain_test_in_thread (gconstpointer data)
470 {
471 SoupURI *uri = (SoupURI *)data;
472 GThread *thread;
473
474 thread = g_thread_new ("do_plain_test_in_thread",
475 plain_test_thread,
476 (gpointer)uri);
477 g_thread_join (thread);
478 }
479
480 static void
do_sync_request(SoupSession * session,SoupRequest * request,guint expected_status,SoupBuffer * expected_response,gboolean persistent,CancelPolicy cancel_policy)481 do_sync_request (SoupSession *session, SoupRequest *request,
482 guint expected_status, SoupBuffer *expected_response,
483 gboolean persistent, CancelPolicy cancel_policy)
484 {
485 GInputStream *in;
486 SoupMessage *msg;
487 GError *error = NULL;
488 GString *body;
489 char buf[1024];
490 gssize nread;
491 guint started_id;
492 SoupSocket *socket = NULL;
493
494 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
495 if (cancel_policy == SYNC_CANCEL) {
496 g_signal_connect (msg, "got-headers",
497 G_CALLBACK (cancel_message), session);
498 }
499
500 started_id = g_signal_connect (session, "request-started",
501 G_CALLBACK (request_started),
502 &socket);
503
504 in = soup_request_send (request, NULL, &error);
505 g_signal_handler_disconnect (session, started_id);
506 if (cancel_policy == SYNC_CANCEL) {
507 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
508 g_clear_error (&error);
509 g_object_unref (msg);
510 g_object_unref (socket);
511 return;
512 } else if (!in) {
513 g_assert_no_error (error);
514 g_clear_error (&error);
515 g_object_unref (msg);
516 g_object_unref (socket);
517 return;
518 }
519
520 soup_test_assert_message_status (msg, expected_status);
521 g_object_unref (msg);
522
523 body = g_string_new (NULL);
524 do {
525 nread = g_input_stream_read (in, buf, sizeof (buf),
526 NULL, &error);
527 g_assert_no_error (error);
528 if (nread == -1) {
529 g_clear_error (&error);
530 break;
531 }
532 g_string_append_len (body, buf, nread);
533 } while (nread > 0);
534
535 g_input_stream_close (in, NULL, &error);
536 g_assert_no_error (error);
537 g_clear_error (&error);
538 g_object_unref (in);
539
540 if (expected_response) {
541 soup_assert_cmpmem (body->str, body->len,
542 expected_response->data, expected_response->length);
543 } else
544 g_assert_cmpint (body->len, ==, 0);
545
546 if (persistent)
547 g_assert_true (soup_socket_is_connected (socket));
548 else
549 g_assert_false (soup_socket_is_connected (socket));
550 g_object_unref (socket);
551
552 g_string_free (body, TRUE);
553 }
554
555 static void
do_sync_tests_for_session(SoupSession * session,SoupURI * base_uri)556 do_sync_tests_for_session (SoupSession *session, SoupURI *base_uri)
557 {
558 SoupRequester *requester;
559 SoupRequest *request;
560 SoupURI *uri;
561
562 requester = SOUP_REQUESTER (soup_session_get_feature (session, SOUP_TYPE_REQUESTER));
563
564 uri = soup_uri_copy (base_uri);
565
566 debug_printf (1, " basic test\n");
567 if (requester)
568 request = soup_requester_request_uri (requester, uri, NULL);
569 else
570 request = soup_session_request_uri (session, uri, NULL);
571 do_sync_request (session, request,
572 SOUP_STATUS_OK, response,
573 TRUE, NO_CANCEL);
574 g_object_unref (request);
575
576 debug_printf (1, " chunked test\n");
577 soup_uri_set_path (uri, "/chunked");
578 if (requester)
579 request = soup_requester_request_uri (requester, uri, NULL);
580 else
581 request = soup_session_request_uri (session, uri, NULL);
582 do_sync_request (session, request,
583 SOUP_STATUS_OK, response,
584 TRUE, NO_CANCEL);
585 g_object_unref (request);
586
587 debug_printf (1, " auth test\n");
588 soup_uri_set_path (uri, "/auth");
589 if (requester)
590 request = soup_requester_request_uri (requester, uri, NULL);
591 else
592 request = soup_session_request_uri (session, uri, NULL);
593 do_sync_request (session, request,
594 SOUP_STATUS_UNAUTHORIZED, auth_response,
595 TRUE, NO_CANCEL);
596 g_object_unref (request);
597
598 debug_printf (1, " non-persistent test\n");
599 soup_uri_set_path (uri, "/non-persistent");
600 if (requester)
601 request = soup_requester_request_uri (requester, uri, NULL);
602 else
603 request = soup_session_request_uri (session, uri, NULL);
604 do_sync_request (session, request,
605 SOUP_STATUS_OK, response,
606 FALSE, NO_CANCEL);
607 g_object_unref (request);
608
609 debug_printf (1, " cancel test\n");
610 soup_uri_set_path (uri, "/");
611 if (requester)
612 request = soup_requester_request_uri (requester, uri, NULL);
613 else
614 request = soup_session_request_uri (session, uri, NULL);
615 do_sync_request (session, request,
616 SOUP_STATUS_FORBIDDEN, NULL,
617 TRUE, SYNC_CANCEL);
618 g_object_unref (request);
619
620 soup_uri_free (uri);
621 }
622
623 static void
do_plain_sync_test(gconstpointer data)624 do_plain_sync_test (gconstpointer data)
625 {
626 SoupURI *uri = (SoupURI *)data;
627 SoupSession *session;
628
629 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
630 do_sync_tests_for_session (session, uri);
631 soup_test_session_abort_unref (session);
632 }
633
634 static void
do_sync_sync_test(gconstpointer data)635 do_sync_sync_test (gconstpointer data)
636 {
637 SoupURI *uri = (SoupURI *)data;
638 SoupSession *session;
639 SoupRequester *requester;
640
641 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
642 requester = soup_requester_new ();
643 soup_session_add_feature (session, SOUP_SESSION_FEATURE (requester));
644 g_object_unref (requester);
645 do_sync_tests_for_session (session, uri);
646 soup_test_session_abort_unref (session);
647 }
648
649 static void
do_null_char_request(SoupSession * session,const char * encoded_data,const char * expected_data,int expected_len)650 do_null_char_request (SoupSession *session, const char *encoded_data,
651 const char *expected_data, int expected_len)
652 {
653 GError *error = NULL;
654 GInputStream *stream;
655 SoupRequest *request;
656 SoupURI *uri;
657 char *uri_string, buf[256];
658 gsize nread;
659
660 uri_string = g_strdup_printf ("data:text/html,%s", encoded_data);
661 uri = soup_uri_new (uri_string);
662 g_free (uri_string);
663
664 request = soup_session_request_uri (session, uri, NULL);
665 stream = soup_test_request_send (request, NULL, 0, &error);
666 g_assert_no_error (error);
667 if (error) {
668 g_error_free (error);
669 g_object_unref (request);
670 soup_uri_free (uri);
671 return;
672 }
673
674 g_input_stream_read_all (stream, buf, sizeof (buf), &nread, NULL, &error);
675 g_assert_no_error (error);
676 g_clear_error (&error);
677
678 soup_test_request_close_stream (request, stream, NULL, &error);
679 g_assert_no_error (error);
680 g_clear_error (&error);
681
682 soup_assert_cmpmem (buf, nread, expected_data, expected_len);
683
684 g_object_unref (stream);
685 g_object_unref (request);
686 soup_uri_free (uri);
687 }
688
689 static void
do_null_char_test_for_session(SoupSession * session)690 do_null_char_test_for_session (SoupSession *session)
691 {
692 static struct {
693 const char *encoded_data;
694 const char *expected_data;
695 int expected_len;
696 } test_cases[] = {
697 { "%3Cscript%3Ea%3D'%00'%3C%2Fscript%3E", "<script>a='\0'</script>", 22 },
698 { "%00%3Cscript%3Ea%3D42%3C%2Fscript%3E", "\0<script>a=42</script>", 22 },
699 { "%3Cscript%3E%00%3Cbr%2F%3E%3C%2Fscript%3E%00", "<script>\0<br/></script>\0", 24 },
700 };
701 static int num_test_cases = G_N_ELEMENTS(test_cases);
702 int i;
703
704 for (i = 0; i < num_test_cases; i++) {
705 do_null_char_request (session, test_cases[i].encoded_data,
706 test_cases[i].expected_data, test_cases[i].expected_len);
707 }
708 }
709
710 static void
do_plain_null_char_test(void)711 do_plain_null_char_test (void)
712 {
713 SoupSession *session;
714
715 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
716 do_null_char_test_for_session (session);
717 soup_test_session_abort_unref (session);
718 }
719
720 static void
do_async_null_char_test(void)721 do_async_null_char_test (void)
722 {
723 SoupSession *session;
724
725 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
726 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
727 NULL);
728 do_null_char_test_for_session (session);
729 soup_test_session_abort_unref (session);
730 }
731
732 static void
close_test_msg_finished(SoupMessage * msg,gpointer user_data)733 close_test_msg_finished (SoupMessage *msg,
734 gpointer user_data)
735 {
736 gboolean *finished = user_data;
737
738 *finished = TRUE;
739 }
740
741 static void
do_close_test_for_session(SoupSession * session,SoupURI * uri)742 do_close_test_for_session (SoupSession *session,
743 SoupURI *uri)
744 {
745 GError *error = NULL;
746 GInputStream *stream;
747 SoupRequest *request;
748 guint64 start, end;
749 GCancellable *cancellable;
750 SoupMessage *msg;
751 gboolean finished = FALSE;
752
753 debug_printf (1, " normal close\n");
754
755 request = soup_session_request_uri (session, uri, NULL);
756 stream = soup_test_request_send (request, NULL, 0, &error);
757 g_assert_no_error (error);
758 if (error) {
759 g_error_free (error);
760 g_object_unref (request);
761 return;
762 }
763
764 start = g_get_monotonic_time ();
765 soup_test_request_close_stream (request, stream, NULL, &error);
766 g_assert_no_error (error);
767 g_clear_error (&error);
768 end = g_get_monotonic_time ();
769
770 g_assert_cmpint (end - start, <=, 500000);
771
772 g_object_unref (stream);
773 g_object_unref (request);
774
775
776 debug_printf (1, " error close\n");
777
778 request = soup_session_request_uri (session, uri, NULL);
779 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
780 g_signal_connect (msg, "finished", G_CALLBACK (close_test_msg_finished), &finished);
781 g_object_unref (msg);
782
783 stream = soup_test_request_send (request, NULL, 0, &error);
784 g_assert_no_error (error);
785 if (error) {
786 g_error_free (error);
787 g_object_unref (request);
788 return;
789 }
790
791 cancellable = g_cancellable_new ();
792 g_cancellable_cancel (cancellable);
793 soup_test_request_close_stream (request, stream, cancellable, &error);
794 if (error)
795 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
796 g_clear_error (&error);
797 g_object_unref (cancellable);
798
799 g_assert_true (finished);
800
801 g_object_unref (stream);
802 g_object_unref (request);
803 }
804
805 static void
do_async_close_test(gconstpointer data)806 do_async_close_test (gconstpointer data)
807 {
808 SoupURI *uri = (SoupURI *)data;
809 SoupSession *session;
810 SoupURI *slow_uri;
811
812 g_test_bug ("695652");
813 g_test_bug ("711260");
814
815 slow_uri = soup_uri_new_with_base ((SoupURI *)uri, "/slow");
816
817 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
818 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
819 NULL);
820 do_close_test_for_session (session, slow_uri);
821 soup_test_session_abort_unref (session);
822
823 soup_uri_free (slow_uri);
824 }
825
826 static void
do_sync_close_test(gconstpointer data)827 do_sync_close_test (gconstpointer data)
828 {
829 SoupURI *uri = (SoupURI *)data;
830 SoupSession *session;
831 SoupURI *slow_uri;
832
833 g_test_bug ("695652");
834 g_test_bug ("711260");
835
836 slow_uri = soup_uri_new_with_base ((SoupURI *)uri, "/slow");
837
838 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
839 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
840 NULL);
841 do_close_test_for_session (session, slow_uri);
842 soup_test_session_abort_unref (session);
843
844 soup_uri_free (slow_uri);
845 }
846
847 int
main(int argc,char ** argv)848 main (int argc, char **argv)
849 {
850 SoupURI *uri;
851 int ret;
852
853 test_init (argc, argv, NULL);
854
855 response = soup_test_get_index ();
856 auth_response = soup_buffer_new (SOUP_MEMORY_STATIC,
857 AUTH_HTML_BODY,
858 strlen (AUTH_HTML_BODY));
859
860 server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
861 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
862
863 uri = soup_test_server_get_uri (server, "http", NULL);
864 soup_uri_set_path (uri, "/foo");
865
866 g_test_add_data_func ("/requester/simple/SoupSession", uri, do_simple_plain_test);
867 g_test_add_data_func ("/requester/simple/SoupSessionAsync", uri, do_simple_async_test);
868 g_test_add_data_func ("/requester/threaded/SoupSession", uri, do_plain_test_in_thread);
869 g_test_add_data_func ("/requester/threaded/SoupSessionAsync", uri, do_async_test_in_thread);
870 g_test_add_data_func ("/requester/context/SoupSession", uri, do_plain_test_with_context);
871 g_test_add_data_func ("/requester/context/SoupSessionAsync", uri, do_async_test_with_context);
872 g_test_add_data_func ("/requester/sync/SoupSession", uri, do_plain_sync_test);
873 g_test_add_data_func ("/requester/sync/SoupSessionSync", uri, do_sync_sync_test);
874 g_test_add_func ("/requester/null-char/SoupSession", do_plain_null_char_test);
875 g_test_add_func ("/requester/null-char/SoupSessionAsync", do_async_null_char_test);
876 g_test_add_data_func ("/requester/close/SoupSessionAsync", uri, do_async_close_test);
877 g_test_add_data_func ("/requester/close/SoupSessionSync", uri, do_sync_close_test);
878
879 ret = g_test_run ();
880
881 soup_uri_free (uri);
882 soup_buffer_free (auth_response);
883 soup_test_server_quit_unref (server);
884
885 test_cleanup ();
886 return ret;
887 }
888