Asterisk - The Open Source Telephony Project  18.5.0
test_http_media_cache.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Matt Jordan
5  *
6  * Matt Jordan <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief Tests for the HTTP media cache backend
22  *
23  * \author \verbatim Matt Jordan <[email protected]> \endverbatim
24  *
25  * \ingroup tests
26  */
27 
28 /*** MODULEINFO
29  <depend>TEST_FRAMEWORK</depend>
30  <depend>curl</depend>
31  <depend>res_http_media_cache</depend>
32  <support_level>core</support_level>
33  ***/
34 
35 #include "asterisk.h"
36 
37 #include <fcntl.h>
38 
39 #include "asterisk/module.h"
40 #include "asterisk/http.h"
41 #include "asterisk/bucket.h"
42 #include "asterisk/test.h"
43 
44 #define CATEGORY "/res/http_media_cache/"
45 
46 #define TEST_URI "test_media_cache"
47 
48 struct test_options {
50  int send_file;
51  struct {
52  int s_maxage;
53  int maxage;
54  int no_cache;
56  } cache_control;
57  struct timeval expires;
58  const char *status_text;
59  const char *etag;
60 };
61 
62 static struct test_options options;
63 
64 static char server_uri[512];
65 
66 #define VALIDATE_EXPIRES(test, bucket_file, expected, delta) do { \
67  RAII_VAR(struct ast_bucket_metadata *, metadata, ast_bucket_file_metadata_get((bucket_file), "__actual_expires"), ao2_cleanup); \
68  int actual_expires; \
69  ast_test_validate(test, metadata != NULL); \
70  ast_test_validate(test, sscanf(metadata->value, "%d", &actual_expires) == 1); \
71  ast_test_status_update(test, "Checking %d >= %d and %d <= %d\n", \
72  (int) ((expected) + (delta)), actual_expires, \
73  (int) ((expected) - (delta)), actual_expires); \
74  ast_test_validate(test, (((expected) + (delta) >= actual_expires) && ((expected) - (delta) <= actual_expires))); \
75 } while (0)
76 
77 #define VALIDATE_STR_METADATA(test, bucket_file, key, expected) do { \
78  RAII_VAR(struct ast_bucket_metadata *, metadata, ast_bucket_file_metadata_get((bucket_file), (key)), ao2_cleanup); \
79  ast_test_validate(test, metadata != NULL); \
80  ast_test_validate(test, !strcmp(metadata->value, (expected))); \
81 } while (0)
82 
83 #define SET_OR_APPEND_CACHE_CONTROL(str) do { \
84  if (!ast_str_strlen((str))) { \
85  ast_str_set(&(str), 0, "%s", "cache-control: "); \
86  } else { \
87  ast_str_append(&(str), 0, "%s", ", "); \
88  } \
89 } while (0)
90 
91 static int http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
92 {
93  char file_name[64] = "/tmp/test-media-cache-XXXXXX";
94  struct ast_str *http_header = ast_str_create(128);
95  struct ast_str *cache_control = ast_str_create(128);
96  int fd = -1;
97  int unmodified = 0;
98  int send_file = options.send_file && method == AST_HTTP_GET;
99 
100  if (!http_header) {
101  goto error;
102  }
103 
104  if (send_file) {
105  char buf[1024];
106 
107  fd = mkstemp(file_name);
108  if (fd == -1) {
109  ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno);
110  goto error;
111  }
112 
113  memset(buf, 1, sizeof(buf));
114  if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
115  ast_log(LOG_ERROR, "Failed to write expected number of bytes to pipe\n");
116  close(fd);
117  goto error;
118  }
119  close(fd);
120 
121  fd = open(file_name, 0);
122  if (fd == -1) {
123  ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno);
124  goto error;
125  }
126  }
127 
129  SET_OR_APPEND_CACHE_CONTROL(cache_control);
130  ast_str_append(&cache_control, 0, "max-age=%d", options.cache_control.maxage);
131  }
132 
134  SET_OR_APPEND_CACHE_CONTROL(cache_control);
135  ast_str_append(&cache_control, 0, "s-maxage=%d", options.cache_control.s_maxage);
136  }
137 
139  SET_OR_APPEND_CACHE_CONTROL(cache_control);
140  ast_str_append(&cache_control, 0, "%s", "no-cache");
141  }
142 
144  SET_OR_APPEND_CACHE_CONTROL(cache_control);
145  ast_str_append(&cache_control, 0, "%s", "must-revalidate");
146  }
147 
148  if (ast_str_strlen(cache_control)) {
149  ast_str_append(&http_header, 0, "%s\r\n", ast_str_buffer(cache_control));
150  }
151 
152  if (options.expires.tv_sec) {
153  struct ast_tm now_time;
154  char tmbuf[64];
155 
156  ast_localtime(&options.expires, &now_time, NULL);
157  ast_strftime(tmbuf, sizeof(tmbuf), "%a, %d %b %Y %T %z", &now_time);
158  ast_str_append(&http_header, 0, "Expires: %s\r\n", tmbuf);
159  }
160 
161  if (!ast_strlen_zero(options.etag)) {
162  struct ast_variable *v;
163 
164  ast_str_append(&http_header, 0, "ETag: %s\r\n", options.etag);
165  for (v = headers; v; v = v->next) {
166  if (!strcasecmp(v->name, "If-None-Match") && !strcasecmp(v->value, options.etag)) {
167  unmodified = 1;
168  break;
169  }
170  }
171  }
172 
173  if (!unmodified) {
174  ast_http_send(ser, method, options.status_code, options.status_text, http_header, NULL, send_file ? fd : 0, 1);
175  } else {
176  ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
177  }
178 
179  if (send_file) {
180  close(fd);
181  unlink(file_name);
182  }
183 
184  ast_free(cache_control);
185 
186  return 0;
187 
188 error:
189  ast_free(http_header);
190  ast_free(cache_control);
192  ast_http_error(ser, 418, "I'm a Teapot", "Please don't ask me to brew coffee.");
193 
194  return 0;
195 }
196 
197 static struct ast_http_uri test_uri = {
198  .description = "HTTP Media Cache Test URI",
199  .uri = TEST_URI,
200  .callback = http_callback,
201  .has_subtree = 1,
202  .data = NULL,
203  .key = __FILE__,
204 };
205 
206 static int pre_test_cb(struct ast_test_info *info, struct ast_test *test)
207 {
208  memset(&options, 0, sizeof(options));
209 
210  return 0;
211 }
212 
213 static void bucket_file_cleanup(void *obj)
214 {
215  struct ast_bucket_file *bucket_file = obj;
216 
217  if (bucket_file) {
218  ast_bucket_file_delete(bucket_file);
219  ao2_ref(bucket_file, -1);
220  }
221 }
222 
223 AST_TEST_DEFINE(retrieve_cache_control_directives)
224 {
225  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
226  struct timeval now = ast_tvnow();
227  char uri[1024];
228 
229  switch (cmd) {
230  case TEST_INIT:
231  info->name = __func__;
232  info->category = CATEGORY;
233  info->summary = "Test retrieval of a resource with Cache-Control directives that affect staleness";
234  info->description =
235  "This test covers retrieval of a resource with the Cache-Control header,\n"
236  "which specifies no-cache and/or must-revalidate.";
237  return AST_TEST_NOT_RUN;
238  case TEST_EXECUTE:
239  break;
240  }
241 
242  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
243 
244  options.send_file = 1;
245  options.status_code = 200;
246  options.status_text = "OK";
247 
248  ast_test_status_update(test, "Testing no-cache...\n");
250  bucket_file = ast_bucket_file_retrieve(uri);
251  ast_test_validate(test, bucket_file != NULL);
252  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1);
253  bucket_file_cleanup(bucket_file);
254 
255  ast_test_status_update(test, "Testing no-cache with ETag...\n");
257  options.etag = "123456789";
258  bucket_file = ast_bucket_file_retrieve(uri);
259  ast_test_validate(test, bucket_file != NULL);
260  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
261  bucket_file_cleanup(bucket_file);
262 
263  options.etag = NULL;
264 
265  ast_test_status_update(test, "Testing no-cache with max-age...\n");
268  bucket_file = ast_bucket_file_retrieve(uri);
269  ast_test_validate(test, bucket_file != NULL);
270  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
271  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1);
272  bucket_file_cleanup(bucket_file);
273 
276 
277  ast_test_status_update(test, "Testing must-revalidate...\n");
279  bucket_file = ast_bucket_file_retrieve(uri);
280  ast_test_validate(test, bucket_file != NULL);
281  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1);
282  bucket_file_cleanup(bucket_file);
283 
284  ast_test_status_update(test, "Testing must-revalidate with ETag...\n");
286  options.etag = "123456789";
287  bucket_file = ast_bucket_file_retrieve(uri);
288  ast_test_validate(test, bucket_file != NULL);
289  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
290  bucket_file_cleanup(bucket_file);
291 
292  options.etag = NULL;
293 
294  ast_test_status_update(test, "Testing must-revalidate with max-age...\n");
297  bucket_file = ast_bucket_file_retrieve(uri);
298  ast_test_validate(test, bucket_file != NULL);
299  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
300  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1);
301 
302  return AST_TEST_PASS;
303 }
304 
305 AST_TEST_DEFINE(retrieve_cache_control_age)
306 {
307  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
308  struct timeval now = ast_tvnow();
309  char uri[1024];
310 
311  switch (cmd) {
312  case TEST_INIT:
313  info->name = __func__;
314  info->category = CATEGORY;
315  info->summary = "Test retrieval of a resource with age specifiers in Cache-Control";
316  info->description =
317  "This test covers retrieval of a resource with the Cache-Control header,\n"
318  "which specifies max-age and/or s-maxage. The test verifies proper precedence\n"
319  "ordering of the header attributes, along with its relation if the Expires\n"
320  "header is present.";
321  return AST_TEST_NOT_RUN;
322  case TEST_EXECUTE:
323  break;
324  }
325 
326  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
327 
328  options.send_file = 1;
329  options.status_code = 200;
330  options.status_text = "OK";
331 
332  ast_test_status_update(test, "Testing max-age...\n");
334  bucket_file = ast_bucket_file_retrieve(uri);
335  ast_test_validate(test, bucket_file != NULL);
336  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
337  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
338  bucket_file_cleanup(bucket_file);
339 
340  ast_test_status_update(test, "Testing s-maxage...\n");
341  now = ast_tvnow();
344  bucket_file = ast_bucket_file_retrieve(uri);
345  ast_test_validate(test, bucket_file != NULL);
346  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
347  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
348  bucket_file_cleanup(bucket_file);
349 
350  ast_test_status_update(test, "Testing max-age and s-maxage...\n");
351  now = ast_tvnow();
354  bucket_file = ast_bucket_file_retrieve(uri);
355  ast_test_validate(test, bucket_file != NULL);
356  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 3);
357  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
358  bucket_file_cleanup(bucket_file);
359 
360  ast_test_status_update(test, "Testing max-age and Expires...\n");
361  now = ast_tvnow();
364  options.expires.tv_sec = now.tv_sec + 3000;
365  bucket_file = ast_bucket_file_retrieve(uri);
366  ast_test_validate(test, bucket_file != NULL);
367  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
368  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
369  bucket_file_cleanup(bucket_file);
370 
371  ast_test_status_update(test, "Testing s-maxage and Expires...\n");
372  now = ast_tvnow();
375  options.expires.tv_sec = now.tv_sec + 3000;
376  bucket_file = ast_bucket_file_retrieve(uri);
377  ast_test_validate(test, bucket_file != NULL);
378  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
379  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
380  bucket_file_cleanup(bucket_file);
381 
382  ast_test_status_update(test, "Testing s-maxage and Expires...\n");
383  now = ast_tvnow();
386  options.expires.tv_sec = now.tv_sec + 3000;
387  bucket_file = ast_bucket_file_retrieve(uri);
388  ast_test_validate(test, bucket_file != NULL);
389  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3);
390  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
391  bucket_file_cleanup(bucket_file);
392 
393  ast_test_status_update(test, "Testing max-age, s-maxage, and Expires...\n");
394  now = ast_tvnow();
397  options.expires.tv_sec = now.tv_sec + 3000;
398  bucket_file = ast_bucket_file_retrieve(uri);
399  ast_test_validate(test, bucket_file != NULL);
400  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 3);
401  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
402 
403  return AST_TEST_PASS;
404 }
405 
406 AST_TEST_DEFINE(retrieve_etag_expired)
407 {
408  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
409  struct timeval now = ast_tvnow();
410  char uri[1024];
411 
412  switch (cmd) {
413  case TEST_INIT:
414  info->name = __func__;
415  info->category = CATEGORY;
416  info->summary = "Test retrieval of an expired resource with an ETag";
417  info->description =
418  "This test covers a staleness check of a resource with an ETag\n"
419  "that has also expired. It guarantees that even if a resource\n"
420  "is expired, we will still not consider it stale if the resource\n"
421  "has not changed per the ETag value.";
422  return AST_TEST_NOT_RUN;
423  case TEST_EXECUTE:
424  break;
425  }
426 
427  options.send_file = 1;
428  options.status_code = 200;
429  options.status_text = "OK";
430  options.etag = "123456789";
431  options.expires.tv_sec = now.tv_sec - 1;
432 
433  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
434 
435  bucket_file = ast_bucket_file_retrieve(uri);
436  ast_test_validate(test, bucket_file != NULL);
437  ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file)));
438  ast_test_validate(test, !ast_strlen_zero(bucket_file->path));
439  VALIDATE_STR_METADATA(test, bucket_file, "etag", options.etag);
440  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 3);
441 
442  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
443 
444  return AST_TEST_PASS;
445 }
446 
447 AST_TEST_DEFINE(retrieve_expires)
448 {
449  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
450  struct timeval now = ast_tvnow();
451  char uri[1024];
452 
453  switch (cmd) {
454  case TEST_INIT:
455  info->name = __func__;
456  info->category = CATEGORY;
457  info->summary = "Test retrieval with explicit expiration";
458  info->description =
459  "This test covers retrieving a resource that has an Expires.\n"
460  "After retrieval of the resource, staleness is checked. With\n"
461  "a non-expired resource, we expect the resource to not be stale.\n"
462  "When the expiration has occurred, we expect the staleness check\n"
463  "to fail.";
464  return AST_TEST_NOT_RUN;
465  case TEST_EXECUTE:
466  break;
467  }
468 
469  options.send_file = 1;
470  options.status_code = 200;
471  options.status_text = "OK";
472  options.expires.tv_sec = now.tv_sec + 3000;
473 
474  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
475 
476  bucket_file = ast_bucket_file_retrieve(uri);
477  ast_test_validate(test, bucket_file != NULL);
478  ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file)));
479  ast_test_validate(test, !ast_strlen_zero(bucket_file->path));
480  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 3000, 3);
481 
482  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
483 
484  /* Clean up previous result */
485  bucket_file_cleanup(bucket_file);
486 
487  options.expires.tv_sec = now.tv_sec - 1;
488  bucket_file = ast_bucket_file_retrieve(uri);
489  ast_test_validate(test, bucket_file != NULL);
490  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 3);
491 
492  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1);
493 
494  return AST_TEST_PASS;
495 }
496 
497 AST_TEST_DEFINE(retrieve_etag)
498 {
499  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
500  struct timeval now = ast_tvnow();
501  char uri[1024];
502 
503  switch (cmd) {
504  case TEST_INIT:
505  info->name = __func__;
506  info->category = CATEGORY;
507  info->summary = "Test retrieval with an ETag";
508  info->description =
509  "This test covers retrieving a resource that has an ETag.\n"
510  "After retrieval of the resource, staleness is checked. With\n"
511  "matching ETags, we expect the resource to not be stale. When\n"
512  "the ETag does not match, we expect the resource to be stale.";
513  return AST_TEST_NOT_RUN;
514  case TEST_EXECUTE:
515  break;
516  }
517 
518  options.send_file = 1;
519  options.status_code = 200;
520  options.status_text = "OK";
521  options.etag = "123456789";
522 
523  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
524 
525  bucket_file = ast_bucket_file_retrieve(uri);
526  ast_test_validate(test, bucket_file != NULL);
527  ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file)));
528  ast_test_validate(test, !ast_strlen_zero(bucket_file->path));
529  VALIDATE_STR_METADATA(test, bucket_file, "etag", options.etag);
530  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 3);
531 
532  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0);
533 
534  options.etag = "99999999";
535  ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1);
536 
537  return AST_TEST_PASS;
538 }
539 
540 AST_TEST_DEFINE(retrieve_nominal)
541 {
542  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
543  struct timeval now = ast_tvnow();
544  char uri[1024];
545 
546  switch (cmd) {
547  case TEST_INIT:
548  info->name = __func__;
549  info->category = CATEGORY;
550  info->summary = "Test nominal retrieval";
551  info->description =
552  "Test nominal retrieval of a resource.";
553  return AST_TEST_NOT_RUN;
554  case TEST_EXECUTE:
555  break;
556  }
557 
558  options.send_file = 1;
559  options.status_code = 200;
560  options.status_text = "OK";
561 
562  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
563 
564  bucket_file = ast_bucket_file_retrieve(uri);
565  ast_test_validate(test, bucket_file != NULL);
566  ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file)));
567  ast_test_validate(test, !ast_strlen_zero(bucket_file->path));
568  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 3);
569 
570  return AST_TEST_PASS;
571 }
572 
573 AST_TEST_DEFINE(create_nominal)
574 {
575  RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);
576  struct timeval now = ast_tvnow();
577  char uri[1024];
578 
579  switch (cmd) {
580  case TEST_INIT:
581  info->name = __func__;
582  info->category = CATEGORY;
583  info->summary = "Test nominal creation";
584  info->description =
585  "Test nominal creation of a resource.";
586  return AST_TEST_NOT_RUN;
587  case TEST_EXECUTE:
588  break;
589  }
590 
591  options.send_file = 1;
592  options.status_code = 200;
593  options.status_text = "OK";
594 
595  snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav");
596 
597  bucket_file = ast_bucket_file_alloc(uri);
598  ast_test_validate(test, bucket_file != NULL);
599  ast_test_validate(test, ast_bucket_file_temporary_create(bucket_file) == 0);
600  ast_test_validate(test, ast_bucket_file_create(bucket_file) == 0);
601  VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 3);
602 
603  return AST_TEST_PASS;
604 }
605 
606 
607 static int process_config(int reload)
608 {
609  struct ast_config *config;
610  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
611  const char *bindaddr;
612  const char *bindport;
613  const char *prefix;
614  const char *enabled;
615 
616  config = ast_config_load("http.conf", config_flags);
617  if (!config || config == CONFIG_STATUS_FILEINVALID) {
618  return -1;
619  } else if (config == CONFIG_STATUS_FILEUNCHANGED) {
620  return 0;
621  }
622 
623  enabled = ast_config_option(config, "general", "enabled");
624  if (!enabled || ast_false(enabled)) {
625  ast_config_destroy(config);
626  return -1;
627  }
628 
629  /* Construct our Server URI */
630  bindaddr = ast_config_option(config, "general", "bindaddr");
631  if (!bindaddr) {
632  ast_config_destroy(config);
633  return -1;
634  }
635 
636  bindport = ast_config_option(config, "general", "bindport");
637  if (!bindport) {
638  bindport = "8088";
639  }
640 
641  prefix = ast_config_option(config, "general", "prefix");
642 
643  snprintf(server_uri, sizeof(server_uri), "http://%s:%s%s/%s", bindaddr, bindport, S_OR(prefix, ""), TEST_URI);
644 
645  ast_config_destroy(config);
646 
647  return 0;
648 }
649 
650 static int reload_module(void)
651 {
652  return process_config(1);
653 }
654 
655 static int load_module(void)
656 {
657  if (process_config(0)) {
659  }
660 
661  if (ast_http_uri_link(&test_uri)) {
663  }
664 
665  AST_TEST_REGISTER(create_nominal);
666 
667  AST_TEST_REGISTER(retrieve_nominal);
668  AST_TEST_REGISTER(retrieve_etag);
669  AST_TEST_REGISTER(retrieve_expires);
670  AST_TEST_REGISTER(retrieve_etag_expired);
671  AST_TEST_REGISTER(retrieve_cache_control_age);
672  AST_TEST_REGISTER(retrieve_cache_control_directives);
673 
675 
677 }
678 
679 static int unload_module(void)
680 {
681  ast_http_uri_unlink(&test_uri);
682 
683  AST_TEST_UNREGISTER(create_nominal);
684 
685  AST_TEST_UNREGISTER(retrieve_nominal);
686  AST_TEST_UNREGISTER(retrieve_etag);
687  AST_TEST_UNREGISTER(retrieve_expires);
688  AST_TEST_UNREGISTER(retrieve_etag_expired);
689  AST_TEST_UNREGISTER(retrieve_cache_control_age);
690  AST_TEST_UNREGISTER(retrieve_cache_control_directives);
691 
692  return 0;
693 }
694 
695 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP Media Cache Backend Tests",
696  .support_level = AST_MODULE_SUPPORT_CORE,
697  .load = load_module,
699  .unload = unload_module,
700  .requires = "res_http_media_cache",
701  );
struct ast_variable * next
Contains all the initialization information required to store a new test definition.
Definition: test.h:221
#define SET_OR_APPEND_CACHE_CONTROL(str)
Asterisk main include file. File version handling, generic pbx functions.
static int http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
Definition: http.c:648
char * config
Definition: conf2ael.c:66
#define CATEGORY
int ast_test_register_init(const char *category, ast_test_init_cb_t *cb)
Definition: test.c:160
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int load_module(void)
static int reload_module(void)
struct test_options::@511 cache_control
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:673
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define CONFIG_STATUS_FILEINVALID
struct ast_bucket_file * ast_bucket_file_retrieve(const char *uri)
Retrieve a bucket file.
Definition: bucket.c:815
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
Structure for variables, used for configurations and for channel variables.
Test Framework API.
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:705
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define NULL
Definition: resample.c:96
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
Definition: bucket.c:663
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
Definition: http.c:456
Bucket File API.
static void bucket_file_cleanup(void *obj)
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define VALIDATE_STR_METADATA(test, bucket_file, key, expected)
Support for Private Asterisk HTTP Servers.
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
static int process_config(int reload)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static int pre_test_cb(struct ast_test_info *info, struct ast_test *test)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
int ast_bucket_file_delete(struct ast_bucket_file *file)
Delete a bucket file from backend storage.
Definition: bucket.c:844
int ast_bucket_file_is_stale(struct ast_bucket_file *file)
Retrieve whether or not the backing datastore views the bucket file as stale.
Definition: bucket.c:824
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
const char * method
Definition: res_pjsip.c:4335
Bucket file structure, contains reference to file and information about it.
Definition: bucket.h:78
static int unload_module(void)
describes a server instance
Definition: tcptls.h:149
#define CONFIG_STATUS_FILEUNCHANGED
struct timeval expires
#define LOG_ERROR
Definition: logger.h:285
const char * status_text
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
int errno
const char * description
Definition: http.h:102
#define TEST_URI
#define ast_free(a)
Definition: astmm.h:182
static char server_uri[512]
static int reload(void)
Definition: cdr_mysql.c:741
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
Common file snapshot creation callback for creating a temporary file.
Definition: bucket.c:899
Structure used to handle boolean flags.
Definition: utils.h:199
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
AST_TEST_DEFINE(retrieve_cache_control_directives)
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
#define VALIDATE_EXPIRES(test, bucket_file, expected, delta)
Definition: test.c:65
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
Definition of a URI handler.
Definition: http.h:100
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
Definition: main/config.c:684
int error(const char *format,...)
Definition: utils/frame.c:999
static struct test_options options
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:56
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static struct ast_http_uri test_uri
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
Definition: http.c:836
int ast_bucket_file_create(struct ast_bucket_file *file)
Create a new bucket file in backend storage.
Definition: bucket.c:725
struct ast_sockaddr bindaddr
Definition: chan_ooh323.c:353
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static char prefix[MAX_PREFIX]
Definition: http.c:141
static int enabled
Definition: dnsmgr.c:91