1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright 2012 Red Hat, Inc.
4 */
5
6 #include "test-utils.h"
7
8 static void
server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * context,gpointer data)9 server_callback (SoupServer *server, SoupMessage *msg,
10 const char *path, GHashTable *query,
11 SoupClientContext *context, gpointer data)
12 {
13 const char *last_modified, *etag;
14 const char *header;
15 guint status = SOUP_STATUS_OK;
16
17 if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
18 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
19 return;
20 }
21
22 header = soup_message_headers_get_one (msg->request_headers,
23 "Test-Set-Expires");
24 if (header) {
25 soup_message_headers_append (msg->response_headers,
26 "Expires",
27 header);
28 }
29
30 header = soup_message_headers_get_one (msg->request_headers,
31 "Test-Set-Cache-Control");
32 if (header) {
33 soup_message_headers_append (msg->response_headers,
34 "Cache-Control",
35 header);
36 }
37
38 last_modified = soup_message_headers_get_one (msg->request_headers,
39 "Test-Set-Last-Modified");
40 if (last_modified) {
41 soup_message_headers_append (msg->response_headers,
42 "Last-Modified",
43 last_modified);
44 }
45
46 etag = soup_message_headers_get_one (msg->request_headers,
47 "Test-Set-ETag");
48 if (etag) {
49 soup_message_headers_append (msg->response_headers,
50 "ETag",
51 etag);
52 }
53
54
55 header = soup_message_headers_get_one (msg->request_headers,
56 "If-Modified-Since");
57 if (header && last_modified) {
58 SoupDate *date;
59 time_t lastmod, check;
60
61 date = soup_date_new_from_string (last_modified);
62 lastmod = soup_date_to_time_t (date);
63 soup_date_free (date);
64
65 date = soup_date_new_from_string (header);
66 check = soup_date_to_time_t (date);
67 soup_date_free (date);
68
69 if (lastmod <= check)
70 status = SOUP_STATUS_NOT_MODIFIED;
71 }
72
73 header = soup_message_headers_get_one (msg->request_headers,
74 "If-None-Match");
75 if (header && etag) {
76 if (!strcmp (header, etag))
77 status = SOUP_STATUS_NOT_MODIFIED;
78 }
79
80 header = soup_message_headers_get_one (msg->request_headers,
81 "Test-Set-My-Header");
82 if (header) {
83 soup_message_headers_append (msg->response_headers,
84 "My-Header",
85 header);
86 }
87
88 if (status == SOUP_STATUS_OK) {
89 GChecksum *sum;
90 const char *body;
91
92 sum = g_checksum_new (G_CHECKSUM_SHA256);
93 g_checksum_update (sum, (guchar *)path, strlen (path));
94 if (last_modified)
95 g_checksum_update (sum, (guchar *)last_modified, strlen (last_modified));
96 if (etag)
97 g_checksum_update (sum, (guchar *)etag, strlen (etag));
98 body = g_checksum_get_string (sum);
99 soup_message_set_response (msg, "text/plain",
100 SOUP_MEMORY_COPY,
101 body, strlen (body) + 1);
102 g_checksum_free (sum);
103 }
104 soup_message_set_status (msg, status);
105 }
106
107 static gboolean
is_network_stream(GInputStream * stream)108 is_network_stream (GInputStream *stream)
109 {
110 while (G_IS_FILTER_INPUT_STREAM (stream))
111 stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
112
113 return !G_IS_FILE_INPUT_STREAM (stream);
114 }
115
116 static char *do_request (SoupSession *session,
117 SoupURI *base_uri,
118 const char *method,
119 const char *path,
120 SoupMessageHeaders *response_headers,
121 ...) G_GNUC_NULL_TERMINATED;
122
123 static gboolean last_request_hit_network;
124 static gboolean last_request_validated;
125 static gboolean last_request_unqueued;
126 static guint cancelled_requests;
127
128 static void
copy_headers(const char * name,const char * value,gpointer user_data)129 copy_headers (const char *name,
130 const char *value,
131 gpointer user_data)
132 {
133 SoupMessageHeaders *headers = (SoupMessageHeaders *) user_data;
134 soup_message_headers_append (headers, name, value);
135 }
136
137 static char *
do_request(SoupSession * session,SoupURI * base_uri,const char * method,const char * path,SoupMessageHeaders * response_headers,...)138 do_request (SoupSession *session,
139 SoupURI *base_uri,
140 const char *method,
141 const char *path,
142 SoupMessageHeaders *response_headers,
143 ...)
144 {
145 SoupRequestHTTP *req;
146 SoupMessage *msg;
147 GInputStream *stream;
148 SoupURI *uri;
149 va_list ap;
150 const char *header, *value;
151 char buf[256];
152 gsize nread;
153 GError *error = NULL;
154
155 last_request_validated = last_request_hit_network = FALSE;
156 last_request_unqueued = FALSE;
157
158 uri = soup_uri_new_with_base (base_uri, path);
159 req = soup_session_request_http_uri (session, method, uri, NULL);
160 soup_uri_free (uri);
161 msg = soup_request_http_get_message (req);
162
163 va_start (ap, response_headers);
164 while ((header = va_arg (ap, const char *))) {
165 value = va_arg (ap, const char *);
166 soup_message_headers_append (msg->request_headers,
167 header, value);
168 }
169 va_end (ap);
170
171 stream = soup_test_request_send (SOUP_REQUEST (req), NULL, 0, &error);
172 if (!stream) {
173 debug_printf (1, " could not send request: %s\n",
174 error->message);
175 g_error_free (error);
176 g_object_unref (req);
177 g_object_unref (msg);
178 return NULL;
179 }
180
181 if (response_headers)
182 soup_message_headers_foreach (msg->response_headers, copy_headers, response_headers);
183
184 g_object_unref (msg);
185
186 if (last_request_validated)
187 last_request_unqueued = FALSE;
188 else
189 soup_test_assert (!last_request_unqueued,
190 "Request unqueued before finishing");
191
192 last_request_hit_network = is_network_stream (stream);
193
194 g_input_stream_read_all (stream, buf, sizeof (buf), &nread,
195 NULL, &error);
196 if (error) {
197 debug_printf (1, " could not read response: %s\n",
198 error->message);
199 g_clear_error (&error);
200 }
201 soup_test_request_close_stream (SOUP_REQUEST (req), stream,
202 NULL, &error);
203 if (error) {
204 debug_printf (1, " could not close stream: %s\n",
205 error->message);
206 g_clear_error (&error);
207 }
208 g_object_unref (stream);
209 g_object_unref (req);
210
211 /* Cache writes are G_PRIORITY_LOW, so they won't have happened yet... */
212 soup_cache_flush ((SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE));
213
214 return nread ? g_memdup (buf, nread) : g_strdup ("");
215 }
216
217 static void
do_request_with_cancel(SoupSession * session,SoupURI * base_uri,const char * method,const char * path,SoupTestRequestFlags flags)218 do_request_with_cancel (SoupSession *session,
219 SoupURI *base_uri,
220 const char *method,
221 const char *path,
222 SoupTestRequestFlags flags)
223 {
224 SoupRequestHTTP *req;
225 GInputStream *stream;
226 SoupURI *uri;
227 GError *error = NULL;
228 GCancellable *cancellable;
229
230 last_request_validated = last_request_hit_network = last_request_unqueued = FALSE;
231 cancelled_requests = 0;
232
233 uri = soup_uri_new_with_base (base_uri, path);
234 req = soup_session_request_http_uri (session, method, uri, NULL);
235 soup_uri_free (uri);
236 cancellable = flags & SOUP_TEST_REQUEST_CANCEL_CANCELLABLE ? g_cancellable_new () : NULL;
237 stream = soup_test_request_send (SOUP_REQUEST (req), cancellable, flags, &error);
238 if (stream) {
239 debug_printf (1, " could not cancel the request\n");
240 g_object_unref (stream);
241 g_object_unref (req);
242 return;
243 } else
244 g_clear_error (&error);
245
246 g_clear_object (&cancellable);
247 g_clear_object (&stream);
248 g_clear_object (&req);
249
250 soup_cache_flush ((SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE));
251 }
252
253 static void
message_starting(SoupMessage * msg,gpointer data)254 message_starting (SoupMessage *msg, gpointer data)
255 {
256 if (soup_message_headers_get_one (msg->request_headers,
257 "If-Modified-Since") ||
258 soup_message_headers_get_one (msg->request_headers,
259 "If-None-Match")) {
260 debug_printf (2, " Conditional request for %s\n",
261 soup_message_get_uri (msg)->path);
262 last_request_validated = TRUE;
263 }
264 }
265
266 static void
request_queued(SoupSession * session,SoupMessage * msg,gpointer data)267 request_queued (SoupSession *session, SoupMessage *msg,
268 gpointer data)
269 {
270 g_signal_connect (msg, "starting",
271 G_CALLBACK (message_starting),
272 data);
273 }
274
275 static void
request_unqueued(SoupSession * session,SoupMessage * msg,gpointer data)276 request_unqueued (SoupSession *session, SoupMessage *msg,
277 gpointer data)
278 {
279 if (msg->status_code == SOUP_STATUS_CANCELLED)
280 cancelled_requests++;
281 last_request_unqueued = TRUE;
282 }
283
284 static void
do_basics_test(gconstpointer data)285 do_basics_test (gconstpointer data)
286 {
287 SoupURI *base_uri = (SoupURI *)data;
288 SoupSession *session;
289 SoupCache *cache;
290 char *cache_dir;
291 char *body1, *body2, *body3, *body4, *body5, *cmp;
292
293 cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
294 debug_printf (2, " Caching to %s\n", cache_dir);
295 cache = soup_cache_new (cache_dir, SOUP_CACHE_SINGLE_USER);
296 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
297 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
298 SOUP_SESSION_ADD_FEATURE, cache,
299 NULL);
300
301 g_signal_connect (session, "request-queued",
302 G_CALLBACK (request_queued), NULL);
303 g_signal_connect (session, "request-unqueued",
304 G_CALLBACK (request_unqueued), NULL);
305
306 debug_printf (2, " Initial requests\n");
307 body1 = do_request (session, base_uri, "GET", "/1", NULL,
308 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
309 NULL);
310 body2 = do_request (session, base_uri, "GET", "/2", NULL,
311 "Test-Set-Last-Modified", "Fri, 01 Jan 2010 00:00:00 GMT",
312 "Test-Set-Cache-Control", "must-revalidate",
313 NULL);
314 body3 = do_request (session, base_uri, "GET", "/3", NULL,
315 "Test-Set-Last-Modified", "Fri, 01 Jan 2010 00:00:00 GMT",
316 "Test-Set-Expires", "Sat, 02 Jan 2011 00:00:00 GMT",
317 "Test-Set-Cache-Control", "must-revalidate",
318 NULL);
319 body4 = do_request (session, base_uri, "GET", "/4", NULL,
320 "Test-Set-ETag", "\"abcdefg\"",
321 "Test-Set-Cache-Control", "must-revalidate",
322 NULL);
323 body5 = do_request (session, base_uri, "GET", "/5", NULL,
324 "Test-Set-Cache-Control", "no-cache",
325 NULL);
326
327
328 /* Resource with future Expires should have been cached */
329 debug_printf (1, " Fresh cached resource\n");
330 cmp = do_request (session, base_uri, "GET", "/1", NULL,
331 NULL);
332 soup_test_assert (!last_request_hit_network,
333 "Request for /1 not filled from cache");
334 soup_test_assert (last_request_unqueued,
335 "Cached resource /1 not unqueued");
336 g_assert_cmpstr (body1, ==, cmp);
337 g_free (cmp);
338
339
340 /* Resource with long-ago Last-Modified should have been cached */
341 debug_printf (1, " Heuristically-fresh cached resource\n");
342 cmp = do_request (session, base_uri, "GET", "/2", NULL,
343 NULL);
344 /* Not validated even if it has must-revalidate, because it hasn't expired */
345 soup_test_assert (!last_request_validated,
346 "Request for /2 was validated");
347 soup_test_assert (!last_request_hit_network,
348 "Request for /2 not filled from cache");
349 soup_test_assert (last_request_unqueued,
350 "Cached resource /2 not unqueued");
351 g_assert_cmpstr (body2, ==, cmp);
352 g_free (cmp);
353
354
355 /* Adding a query string should bypass the cache but not invalidate it */
356 debug_printf (1, " Fresh cached resource with a query\n");
357 cmp = do_request (session, base_uri, "GET", "/1?attr=value", NULL,
358 NULL);
359 soup_test_assert (last_request_hit_network,
360 "Request for /1?attr=value filled from cache");
361 soup_test_assert (last_request_unqueued,
362 "Cached resource /1?attr=value not unqueued");
363 g_free (cmp);
364 debug_printf (2, " Second request\n");
365 cmp = do_request (session, base_uri, "GET", "/1", NULL,
366 NULL);
367 soup_test_assert (!last_request_hit_network,
368 "Second request for /1 not filled from cache");
369 soup_test_assert (last_request_unqueued,
370 "Request for /1 not unqueued");
371 g_assert_cmpstr (body1, ==, cmp);
372 g_free (cmp);
373
374
375 /* Expired + must-revalidate causes a conditional request */
376 debug_printf (1, " Unchanged must-revalidate resource w/ Last-Modified\n");
377 cmp = do_request (session, base_uri, "GET", "/3", NULL,
378 "Test-Set-Last-Modified", "Fri, 01 Jan 2010 00:00:00 GMT",
379 "Test-Set-Expires", "Sat, 02 Jan 2011 00:00:00 GMT",
380 "Test-Set-Cache-Control", "must-revalidate",
381 NULL);
382 soup_test_assert (last_request_validated,
383 "Request for /3 not validated");
384 soup_test_assert (!last_request_hit_network,
385 "Request for /3 not filled from cache");
386 soup_test_assert (last_request_unqueued,
387 "Cached resource /3 not unqueued");
388 g_assert_cmpstr (body3, ==, cmp);
389 g_free (cmp);
390
391
392 /* Validation failure should update cache */
393 debug_printf (1, " Changed must-revalidate resource w/ Last-Modified\n");
394 cmp = do_request (session, base_uri, "GET", "/3", NULL,
395 "Test-Set-Last-Modified", "Sat, 02 Jan 2010 00:00:00 GMT",
396 "Test-Set-Expires", "Sat, 02 Jan 2011 00:00:00 GMT",
397 "Test-Set-Cache-Control", "must-revalidate",
398 NULL);
399 soup_test_assert (last_request_validated,
400 "Request for /3 not validated");
401 soup_test_assert (last_request_hit_network,
402 "Request for /3 filled from cache");
403 soup_test_assert (last_request_unqueued,
404 "Request for /3 not unqueued");
405 g_assert_cmpstr (body3, !=, cmp);
406 g_free (cmp);
407
408 debug_printf (2, " Second request\n");
409 cmp = do_request (session, base_uri, "GET", "/3", NULL,
410 "Test-Set-Last-Modified", "Sat, 02 Jan 2010 00:00:00 GMT",
411 "Test-Set-Cache-Control", "must-revalidate",
412 NULL);
413 soup_test_assert (last_request_validated,
414 "Second request for /3 not validated");
415 soup_test_assert (!last_request_hit_network,
416 "Second request for /3 not filled from cache");
417 soup_test_assert (last_request_unqueued,
418 "Cached resource /3 not unqueued");
419 g_assert_cmpstr (body3, !=, cmp);
420 g_free (cmp);
421
422 /* ETag + must-revalidate causes a conditional request */
423 debug_printf (1, " Unchanged must-revalidate resource w/ ETag\n");
424 cmp = do_request (session, base_uri, "GET", "/4", NULL,
425 "Test-Set-ETag", "\"abcdefg\"",
426 NULL);
427 soup_test_assert (last_request_validated,
428 "Request for /4 not validated");
429 soup_test_assert (!last_request_hit_network,
430 "Request for /4 not filled from cache");
431 soup_test_assert (last_request_unqueued,
432 "Cached resource /4 not unqueued");
433 g_assert_cmpstr (body4, ==, cmp);
434 g_free (cmp);
435
436
437 /* Cache-Control: no-cache prevents caching */
438 debug_printf (1, " Uncacheable resource\n");
439 cmp = do_request (session, base_uri, "GET", "/5", NULL,
440 "Test-Set-Cache-Control", "no-cache",
441 NULL);
442 soup_test_assert (last_request_hit_network,
443 "Request for /5 filled from cache");
444 soup_test_assert (last_request_unqueued,
445 "Request for /5 not unqueued");
446 g_assert_cmpstr (body5, ==, cmp);
447 g_free (cmp);
448
449
450 /* PUT to a URI invalidates the cache entry */
451 debug_printf (1, " Invalidating and re-requesting a cached resource\n");
452 cmp = do_request (session, base_uri, "PUT", "/1", NULL,
453 NULL);
454 soup_test_assert (last_request_hit_network,
455 "PUT filled from cache");
456 g_free (cmp);
457 cmp = do_request (session, base_uri, "GET", "/1", NULL,
458 NULL);
459 soup_test_assert (last_request_hit_network,
460 "PUT failed to invalidate cache entry");
461 g_assert_true (last_request_hit_network);
462 g_free (cmp);
463
464
465 soup_test_session_abort_unref (session);
466 g_object_unref (cache);
467
468 g_free (cache_dir);
469 g_free (body1);
470 g_free (body2);
471 g_free (body3);
472 g_free (body4);
473 g_free (body5);
474 }
475
476 static void
do_cancel_test(gconstpointer data)477 do_cancel_test (gconstpointer data)
478 {
479 SoupURI *base_uri = (SoupURI *)data;
480 SoupSession *session;
481 SoupCache *cache;
482 char *cache_dir;
483 char *body1, *body2;
484 guint flags;
485
486 g_test_bug ("692310");
487
488 cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
489 debug_printf (2, " Caching to %s\n", cache_dir);
490 cache = soup_cache_new (cache_dir, SOUP_CACHE_SINGLE_USER);
491 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
492 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
493 SOUP_SESSION_ADD_FEATURE, cache,
494 NULL);
495 g_signal_connect (session, "request-unqueued",
496 G_CALLBACK (request_unqueued), NULL);
497
498 debug_printf (2, " Initial requests\n");
499 body1 = do_request (session, base_uri, "GET", "/1", NULL,
500 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
501 NULL);
502 body2 = do_request (session, base_uri, "GET", "/2", NULL,
503 "Test-Set-Last-Modified", "Fri, 01 Jan 2010 00:00:00 GMT",
504 "Test-Set-Expires", "Fri, 01 Jan 2011 00:00:00 GMT",
505 "Test-Set-Cache-Control", "must-revalidate",
506 NULL);
507
508 /* Check that messages are correctly processed on cancellations. */
509 debug_printf (1, " Cancel fresh resource with soup_session_message_cancel()\n");
510 flags = SOUP_TEST_REQUEST_CANCEL_MESSAGE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
511 do_request_with_cancel (session, base_uri, "GET", "/1", flags);
512 g_assert_cmpint (cancelled_requests, ==, 1);
513 soup_test_assert (last_request_unqueued,
514 "Cancelled request /1 not unqueued");
515
516 debug_printf (1, " Cancel fresh resource with g_cancellable_cancel()\n");
517 flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
518 do_request_with_cancel (session, base_uri, "GET", "/1", flags);
519 g_assert_cmpint (cancelled_requests, ==, 1);
520 soup_test_assert (last_request_unqueued,
521 "Cancelled request /1 not unqueued");
522
523 soup_test_session_abort_unref (session);
524
525 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
526 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
527 SOUP_SESSION_ADD_FEATURE, cache,
528 NULL);
529 g_signal_connect (session, "request-unqueued",
530 G_CALLBACK (request_unqueued), NULL);
531
532 /* Check that messages are correctly processed on cancellations. */
533 debug_printf (1, " Cancel a revalidating resource with soup_session_message_cancel()\n");
534 flags = SOUP_TEST_REQUEST_CANCEL_MESSAGE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
535 do_request_with_cancel (session, base_uri, "GET", "/2", flags);
536 g_assert_cmpint (cancelled_requests, ==, 2);
537 soup_test_assert (last_request_unqueued,
538 "Cancelled request /2 not unqueued");
539
540 debug_printf (1, " Cancel a revalidating resource with g_cancellable_cancel()\n");
541 flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
542 do_request_with_cancel (session, base_uri, "GET", "/2", flags);
543 g_assert_cmpint (cancelled_requests, ==, 2);
544 soup_test_assert (last_request_unqueued,
545 "Cancelled request /2 not unqueued");
546
547 soup_test_session_abort_unref (session);
548
549 g_object_unref (cache);
550 g_free (cache_dir);
551 g_free (body1);
552 g_free (body2);
553 }
554
555 static gboolean
unref_stream(gpointer stream)556 unref_stream (gpointer stream)
557 {
558 g_object_unref (stream);
559 return FALSE;
560 }
561
562 static void
base_stream_unreffed(gpointer loop,GObject * ex_base_stream)563 base_stream_unreffed (gpointer loop, GObject *ex_base_stream)
564 {
565 g_main_loop_quit (loop);
566 }
567
568 static void
do_refcounting_test(gconstpointer data)569 do_refcounting_test (gconstpointer data)
570 {
571 SoupURI *base_uri = (SoupURI *)data;
572 SoupSession *session;
573 SoupCache *cache;
574 char *cache_dir;
575 SoupRequestHTTP *req;
576 GInputStream *stream, *base_stream;
577 SoupURI *uri;
578 GError *error = NULL;
579 guint flags;
580 GMainLoop *loop;
581
582 g_test_bug ("682527");
583
584 cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
585 debug_printf (2, " Caching to %s\n", cache_dir);
586 cache = soup_cache_new (cache_dir, SOUP_CACHE_SINGLE_USER);
587 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
588 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
589 SOUP_SESSION_ADD_FEATURE, cache,
590 NULL);
591
592 last_request_validated = last_request_hit_network = FALSE;
593 cancelled_requests = 0;
594
595 uri = soup_uri_new_with_base (base_uri, "/1");
596 req = soup_session_request_http_uri (session, "GET", uri, NULL);
597 soup_uri_free (uri);
598
599 flags = SOUP_TEST_REQUEST_CANCEL_AFTER_SEND_FINISH | SOUP_TEST_REQUEST_CANCEL_MESSAGE;
600 stream = soup_test_request_send (SOUP_REQUEST (req), NULL, flags, &error);
601 if (!stream) {
602 debug_printf (1, " could not send request: %s\n",
603 error->message);
604 g_error_free (error);
605 g_object_unref (req);
606 return;
607 }
608 g_object_unref (req);
609
610 base_stream = g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (stream));
611
612 debug_printf (1, " Checking that the base stream is properly unref'ed\n");
613 loop = g_main_loop_new (NULL, FALSE);
614 g_object_weak_ref (G_OBJECT (base_stream), base_stream_unreffed, loop);
615 g_idle_add (unref_stream, stream);
616 g_main_loop_run (loop);
617 g_main_loop_unref (loop);
618
619 soup_cache_flush ((SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE));
620
621 soup_test_session_abort_unref (session);
622
623 g_object_unref (cache);
624 g_free (cache_dir);
625 }
626
627 static void
do_headers_test(gconstpointer data)628 do_headers_test (gconstpointer data)
629 {
630 SoupURI *base_uri = (SoupURI *)data;
631 SoupSession *session;
632 SoupMessageHeaders *headers;
633 SoupCache *cache;
634 char *cache_dir;
635 char *body1, *cmp;
636 const char *header_value;
637
638 cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
639 debug_printf (2, " Caching to %s\n", cache_dir);
640 cache = soup_cache_new (cache_dir, SOUP_CACHE_SINGLE_USER);
641 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
642 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
643 SOUP_SESSION_ADD_FEATURE, cache,
644 NULL);
645
646 g_signal_connect (session, "request-queued",
647 G_CALLBACK (request_queued), NULL);
648
649 debug_printf (2, " Initial requests\n");
650 body1 = do_request (session, base_uri, "GET", "/1", NULL,
651 "Test-Set-Last-Modified", "Fri, 01 Jan 2100 00:00:00 GMT",
652 "Test-Set-My-Header", "My header value",
653 NULL);
654
655 /* My-Header new value should be updated in cache */
656 debug_printf (2, " Fresh cached resource which updates My-Header\n");
657 cmp = do_request (session, base_uri, "GET", "/1", NULL,
658 "Test-Set-Last-Modified", "Fri, 01 Jan 2010 00:00:00 GMT",
659 "Test-Set-My-Header", "My header NEW value",
660 NULL);
661 soup_test_assert (last_request_validated,
662 "Request for /1 not validated");
663 soup_test_assert (!last_request_hit_network,
664 "Request for /1 not filled from cache");
665 g_free (cmp);
666
667 /* Check that cache returns the updated header */
668 debug_printf (2, " Fresh cached resource with new value for My-Header\n");
669 headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
670 cmp = do_request (session, base_uri, "GET", "/1", headers,
671 "Test-Set-Last-Modified", "Fri, 01 Jan 2010 00:00:00 GMT",
672 NULL);
673 soup_test_assert (!last_request_hit_network,
674 "Request for /1 not filled from cache");
675 g_free (cmp);
676
677 header_value = soup_message_headers_get_list (headers, "My-Header");
678 g_assert_cmpstr (header_value, ==, "My header NEW value");
679 soup_message_headers_free (headers);
680
681 soup_test_session_abort_unref (session);
682 g_object_unref (cache);
683
684 g_free (cache_dir);
685 g_free (body1);
686 }
687
688 static guint
count_cached_resources_in_dir(const char * cache_dir)689 count_cached_resources_in_dir (const char *cache_dir)
690 {
691 GDir *dir;
692 const char *name;
693 guint retval = 0;
694
695 dir = g_dir_open (cache_dir, 0, NULL);
696 while ((name = g_dir_read_name (dir))) {
697 if (g_str_has_prefix (name, "soup."))
698 continue;
699
700 retval++;
701 }
702 g_dir_close (dir);
703
704 return retval;
705 }
706
707 static void
do_leaks_test(gconstpointer data)708 do_leaks_test (gconstpointer data)
709 {
710 SoupURI *base_uri = (SoupURI *)data;
711 SoupSession *session;
712 SoupCache *cache;
713 char *cache_dir;
714 char *body;
715
716 cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
717 debug_printf (2, " Caching to %s\n", cache_dir);
718 cache = soup_cache_new (cache_dir, SOUP_CACHE_SINGLE_USER);
719 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
720 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
721 SOUP_SESSION_ADD_FEATURE, cache,
722 NULL);
723
724 debug_printf (2, " Initial requests\n");
725 body = do_request (session, base_uri, "GET", "/1", NULL,
726 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
727 NULL);
728 g_free (body);
729 body = do_request (session, base_uri, "GET", "/2", NULL,
730 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
731 NULL);
732 g_free (body);
733 body = do_request (session, base_uri, "GET", "/3", NULL,
734 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
735 NULL);
736 g_free (body);
737
738 debug_printf (2, " Dumping the cache\n");
739 soup_cache_dump (cache);
740
741 g_assert_cmpuint (count_cached_resources_in_dir (cache_dir), ==, 3);
742
743 body = do_request (session, base_uri, "GET", "/4", NULL,
744 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
745 NULL);
746 g_free (body);
747 body = do_request (session, base_uri, "GET", "/5", NULL,
748 "Test-Set-Expires", "Fri, 01 Jan 2100 00:00:00 GMT",
749 NULL);
750 g_free (body);
751
752 /* Destroy the cache without dumping the last two resources */
753 soup_test_session_abort_unref (session);
754 g_object_unref (cache);
755
756 cache = soup_cache_new (cache_dir, SOUP_CACHE_SINGLE_USER);
757
758 debug_printf (2, " Loading the cache\n");
759 g_assert_cmpuint (count_cached_resources_in_dir (cache_dir), ==, 5);
760 soup_cache_load (cache);
761 g_assert_cmpuint (count_cached_resources_in_dir (cache_dir), ==, 3);
762
763 g_object_unref (cache);
764 g_free (cache_dir);
765 }
766
767 int
main(int argc,char ** argv)768 main (int argc, char **argv)
769 {
770 SoupServer *server;
771 SoupURI *base_uri;
772 int ret;
773
774 test_init (argc, argv, NULL);
775
776 server = soup_test_server_new (TRUE);
777 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
778 base_uri = soup_test_server_get_uri (server, "http", NULL);
779
780 g_test_add_data_func ("/cache/basics", base_uri, do_basics_test);
781 g_test_add_data_func ("/cache/cancellation", base_uri, do_cancel_test);
782 g_test_add_data_func ("/cache/refcounting", base_uri, do_refcounting_test);
783 g_test_add_data_func ("/cache/headers", base_uri, do_headers_test);
784 g_test_add_data_func ("/cache/leaks", base_uri, do_leaks_test);
785
786 ret = g_test_run ();
787
788 soup_uri_free (base_uri);
789 soup_test_server_quit_unref (server);
790
791 test_cleanup ();
792 return ret;
793 }
794