redirect.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. Tests for 3xx redirect interface (ne_redirect.h)
  3. Copyright (C) 2002-2024, Joe Orton <[email protected]>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "config.h"
  17. #include <sys/types.h>
  18. #ifdef HAVE_STDLIB_H
  19. #include <stdlib.h>
  20. #endif
  21. #ifdef HAVE_UNISTD_H
  22. #include <unistd.h>
  23. #endif
  24. #include "ne_redirect.h"
  25. #include "tests.h"
  26. #include "child.h"
  27. #include "utils.h"
  28. /* Run a request to 'path' and retrieve the redirect destination to
  29. * *redir. */
  30. static int process_redir(ne_session *sess, const char *path,
  31. const ne_uri **redir)
  32. {
  33. int ret = any_request(sess, path);
  34. ONV(ret != NE_REDIRECT,
  35. ("request got %d (%s) rather than NE_REDIRECT",
  36. ret, ne_get_error(sess)));
  37. *redir = ne_redirect_location(sess);
  38. return OK;
  39. }
  40. static int check_redir(int status_code, const char *location,
  41. const char *target, const char *fragment,
  42. const char *expect)
  43. {
  44. char *unp, *full_expect = NULL, response[BUFSIZ];
  45. ne_session *sess;
  46. ne_uri *loc;
  47. ne_request *req;
  48. ne_snprintf(response, sizeof response,
  49. "HTTP/1.0 %d Get Ye Away\r\n"
  50. "Content-Length: 0\r\n"
  51. "Location: %s\r\n\n",
  52. status_code, location);
  53. CALL(multi_session_server(&sess, "http", "localhost", 2,
  54. single_serve_string, response));
  55. if (expect[0] == '/') {
  56. ne_uri uri = {0};
  57. ne_fill_server_uri(sess, &uri);
  58. uri.path = (char *)expect;
  59. uri.fragment = (char *)fragment;
  60. full_expect = ne_uri_unparse(&uri);
  61. expect = full_expect;
  62. uri.path = NULL;
  63. uri.fragment = NULL;
  64. ne_uri_free(&uri);
  65. }
  66. /* First test the ne_get_response_location() API directly. */
  67. NE_DEBUG(NE_DBG_HTTP, "redirect: Target [%s ## %s]\n", target,
  68. fragment ? fragment : "(no fragment)");
  69. NE_DEBUG(NE_DBG_HTTP, "redirect: Location: [%s]\n", location);
  70. req = ne_request_create(sess, "GET", target);
  71. ONREQ(ne_request_dispatch(req));
  72. loc = ne_get_response_location(req, fragment);
  73. unp = ne_uri_unparse(loc);
  74. NE_DEBUG(NE_DBG_HTTP, "redirect: ne_get_response_location => [%s]\n", unp);
  75. ONV(strcmp(unp, expect), ("first redirect to `%s' not `%s'", unp, expect));
  76. ne_free(unp);
  77. ne_request_destroy(req);
  78. ne_uri_free(loc);
  79. ne_free(loc);
  80. if (fragment) {
  81. /* Can't handle fragments in the ne_redirect API, send a dummy request. */
  82. CALL(any_request(sess, "/dummy"));
  83. }
  84. else {
  85. const ne_uri *cloc;
  86. /* Second, test the ne_redirect* API. */
  87. ne_redirect_register(sess);
  88. CALL(process_redir(sess, target, &cloc));
  89. ONN("redirect location was NULL", cloc == NULL);
  90. unp = ne_uri_unparse(cloc);
  91. NE_DEBUG(NE_DBG_HTTP, "redirect: ne_redirect URI => [%s]\n", unp);
  92. ONV(strcmp(unp, expect), ("second redirect to `%s' not `%s'", unp, expect));
  93. ne_free(unp);
  94. }
  95. if (full_expect) ne_free(full_expect);
  96. return destroy_and_wait(sess);
  97. }
  98. #define DEST "http://foo.com/blah/blah/bar"
  99. #define PATH "/redir/me"
  100. static int redirects(void)
  101. {
  102. const struct {
  103. const char *target;
  104. int code;
  105. const char *location;
  106. const char *expected;
  107. const char *fragment;
  108. } ts[] = {
  109. {PATH, 301, DEST, DEST, NULL},
  110. {PATH, 302, DEST, DEST, NULL},
  111. {PATH, 303, DEST, DEST, NULL},
  112. {PATH, 307, DEST, DEST, NULL},
  113. /* Simple relative URI cases: */
  114. {PATH, 302, "/foo/bar/blah", "/foo/bar/blah", NULL},
  115. {"/foo/bar", 302, "norman", "/foo/norman", NULL},
  116. {"/foo/bar/", 302, "wishbone", "/foo/bar/wishbone", NULL},
  117. /* all 3xx should get NE_REDIRECT. */
  118. {PATH, 399, DEST, DEST, NULL},
  119. /* Handling of various request-target cases. */
  120. {"*", 307, "/fish#food", "/fish#food", NULL},
  121. {"ftp://example.com/fish", 307, "/fish#food", "ftp://example.com/fish#food", NULL},
  122. /* More relative URIs: */
  123. {"/blah", 307, "//example.com:8080/fish#food", "http://example.com:8080/fish#food", NULL},
  124. {"/blah", 307, "#food", "/blah#food", NULL},
  125. /* Fragment handling. */
  126. {"/foo", 301, "http://example.com/redirect", "http://example.com/redirect#fragment",
  127. "fragment" },
  128. {"/foo", 301, "https://blah.example.com/redirect#override",
  129. "https://blah.example.com/redirect#override", "fragment" },
  130. };
  131. unsigned n;
  132. for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {
  133. CALL(check_redir(ts[n].code, ts[n].location, ts[n].target, ts[n].fragment,
  134. ts[n].expected));
  135. }
  136. return OK;
  137. }
  138. #define RESP1 "HTTP/1.1 200 OK\r\n" "Content-Length: 0\r\n\r\n"
  139. #define RESP2 "HTTP/1.0 302 Get Ye Away\r\n" "Location: /blah\r\n" "\r\n"
  140. /* ensure that ne_redirect_location returns NULL when no redirect has
  141. * been encountered, or redirect hooks aren't registered. */
  142. static int no_redirect(void)
  143. {
  144. ne_session *sess;
  145. const ne_uri *loc;
  146. struct double_serve_args resp;
  147. resp.first.data = RESP1;
  148. resp.first.len = strlen(RESP1);
  149. resp.second.data = RESP2;
  150. resp.second.len = strlen(RESP2);
  151. CALL(session_server(&sess, double_serve_sstring, &resp));
  152. ONN("redirect non-NULL before register", ne_redirect_location(sess));
  153. ne_redirect_register(sess);
  154. ONN("initial redirect non-NULL", ne_redirect_location(sess));
  155. ONREQ(any_request(sess, "/noredir"));
  156. ONN("redirect non-NULL after non-redir req", ne_redirect_location(sess));
  157. CALL(process_redir(sess, "/foo", &loc));
  158. return destroy_and_wait(sess);
  159. }
  160. ne_test tests[] = {
  161. T(lookup_localhost),
  162. T(redirects),
  163. T(no_redirect),
  164. T(NULL)
  165. };