http_lib.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <stdio.h> /* for sscanf() */
  10. #include <string.h>
  11. #include <openssl/http.h>
  12. #include <openssl/httperr.h>
  13. #include <openssl/bio.h> /* for BIO_snprintf() */
  14. #include <openssl/err.h>
  15. #include "internal/cryptlib.h" /* for ossl_assert() */
  16. static void init_pstring(char **pstr)
  17. {
  18. if (pstr != NULL) {
  19. *pstr = NULL;
  20. }
  21. }
  22. static int copy_substring(char **dest, const char *start, const char *end)
  23. {
  24. return dest == NULL
  25. || (*dest = OPENSSL_strndup(start, end - start)) != NULL;
  26. }
  27. static void free_pstring(char **pstr)
  28. {
  29. if (pstr != NULL) {
  30. OPENSSL_free(*pstr);
  31. *pstr = NULL;
  32. }
  33. }
  34. int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
  35. char **pport, int *pport_num,
  36. char **ppath, char **pquery, char **pfrag)
  37. {
  38. const char *p, *tmp;
  39. const char *scheme, *scheme_end;
  40. const char *user, *user_end;
  41. const char *host, *host_end;
  42. const char *port, *port_end;
  43. unsigned int portnum;
  44. const char *path, *path_end;
  45. const char *query, *query_end;
  46. const char *frag, *frag_end;
  47. init_pstring(pscheme);
  48. init_pstring(puser);
  49. init_pstring(phost);
  50. init_pstring(pport);
  51. init_pstring(ppath);
  52. init_pstring(pfrag);
  53. init_pstring(pquery);
  54. if (url == NULL) {
  55. ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
  56. return 0;
  57. }
  58. /* check for optional prefix "<scheme>://" */
  59. scheme = scheme_end = url;
  60. p = strstr(url, "://");
  61. if (p == NULL) {
  62. p = url;
  63. } else {
  64. scheme_end = p;
  65. if (scheme_end == scheme)
  66. goto parse_err;
  67. p += strlen("://");
  68. }
  69. /* parse optional "userinfo@" */
  70. user = user_end = host = p;
  71. host = strchr(p, '@');
  72. if (host != NULL)
  73. user_end = host++;
  74. else
  75. host = p;
  76. /* parse hostname/address as far as needed here */
  77. if (host[0] == '[') {
  78. /* IPv6 literal, which may include ':' */
  79. host_end = strchr(host + 1, ']');
  80. if (host_end == NULL)
  81. goto parse_err;
  82. p = ++host_end;
  83. } else {
  84. /* look for start of optional port, path, query, or fragment */
  85. host_end = strchr(host, ':');
  86. if (host_end == NULL)
  87. host_end = strchr(host, '/');
  88. if (host_end == NULL)
  89. host_end = strchr(host, '?');
  90. if (host_end == NULL)
  91. host_end = strchr(host, '#');
  92. if (host_end == NULL) /* the remaining string is just the hostname */
  93. host_end = host + strlen(host);
  94. p = host_end;
  95. }
  96. /* parse optional port specification starting with ':' */
  97. port = "0"; /* default */
  98. if (*p == ':')
  99. port = ++p;
  100. /* remaining port spec handling is also done for the default values */
  101. /* make sure a decimal port number is given */
  102. if (!sscanf(port, "%u", &portnum) || portnum > 65535) {
  103. ERR_raise_data(ERR_LIB_HTTP, HTTP_R_INVALID_PORT_NUMBER, "%s", port);
  104. goto err;
  105. }
  106. for (port_end = port; '0' <= *port_end && *port_end <= '9'; port_end++)
  107. ;
  108. if (port == p) /* port was given explicitly */
  109. p += port_end - port;
  110. /* check for optional path starting with '/' or '?'. Else must start '#' */
  111. path = p;
  112. if (*path != '\0' && *path != '/' && *path != '?' && *path != '#') {
  113. ERR_raise(ERR_LIB_HTTP, HTTP_R_INVALID_URL_PATH);
  114. goto parse_err;
  115. }
  116. path_end = query = query_end = frag = frag_end = path + strlen(path);
  117. /* parse optional "?query" */
  118. tmp = strchr(p, '?');
  119. if (tmp != NULL) {
  120. p = tmp;
  121. if (pquery != NULL) {
  122. path_end = p;
  123. query = p + 1;
  124. }
  125. }
  126. /* parse optional "#fragment" */
  127. tmp = strchr(p, '#');
  128. if (tmp != NULL) {
  129. if (query == path_end) /* we did not record a query component */
  130. path_end = tmp;
  131. query_end = tmp;
  132. frag = tmp + 1;
  133. }
  134. if (!copy_substring(pscheme, scheme, scheme_end)
  135. || !copy_substring(phost, host, host_end)
  136. || !copy_substring(pport, port, port_end)
  137. || !copy_substring(puser, user, user_end)
  138. || !copy_substring(pquery, query, query_end)
  139. || !copy_substring(pfrag, frag, frag_end))
  140. goto err;
  141. if (pport_num != NULL)
  142. *pport_num = (int)portnum;
  143. if (*path == '/') {
  144. if (!copy_substring(ppath, path, path_end))
  145. goto err;
  146. } else if (ppath != NULL) { /* must prepend '/' */
  147. size_t buflen = 1 + path_end - path + 1;
  148. if ((*ppath = OPENSSL_malloc(buflen)) == NULL)
  149. goto err;
  150. BIO_snprintf(*ppath, buflen, "/%s", path);
  151. }
  152. return 1;
  153. parse_err:
  154. ERR_raise(ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_URL);
  155. err:
  156. free_pstring(pscheme);
  157. free_pstring(puser);
  158. free_pstring(phost);
  159. free_pstring(pport);
  160. free_pstring(ppath);
  161. free_pstring(pquery);
  162. free_pstring(pfrag);
  163. return 0;
  164. }
  165. int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
  166. char **pport, int *pport_num,
  167. char **ppath, char **pquery, char **pfrag)
  168. {
  169. char *scheme, *port;
  170. int ssl = 0, portnum;
  171. init_pstring(pport);
  172. if (pssl != NULL)
  173. *pssl = 0;
  174. if (!OSSL_parse_url(url, &scheme, puser, phost, &port, pport_num,
  175. ppath, pquery, pfrag))
  176. return 0;
  177. /* check for optional HTTP scheme "http[s]" */
  178. if (strcmp(scheme, OSSL_HTTPS_NAME) == 0) {
  179. ssl = 1;
  180. if (pssl != NULL)
  181. *pssl = ssl;
  182. } else if (*scheme != '\0' && strcmp(scheme, OSSL_HTTP_NAME) != 0) {
  183. ERR_raise(ERR_LIB_HTTP, HTTP_R_INVALID_URL_SCHEME);
  184. OPENSSL_free(scheme);
  185. OPENSSL_free(port);
  186. goto err;
  187. }
  188. OPENSSL_free(scheme);
  189. if (strcmp(port, "0") == 0) {
  190. /* set default port */
  191. OPENSSL_free(port);
  192. port = ssl ? OSSL_HTTPS_PORT : OSSL_HTTP_PORT;
  193. if (!ossl_assert(sscanf(port, "%d", &portnum) == 1))
  194. goto err;
  195. if (pport_num != NULL)
  196. *pport_num = portnum;
  197. if (pport != NULL) {
  198. *pport = OPENSSL_strdup(port);
  199. if (*pport == NULL)
  200. goto err;
  201. }
  202. } else {
  203. if (pport != NULL)
  204. *pport = port;
  205. else
  206. OPENSSL_free(port);
  207. }
  208. return 1;
  209. err:
  210. free_pstring(puser);
  211. free_pstring(phost);
  212. free_pstring(ppath);
  213. free_pstring(pquery);
  214. free_pstring(pfrag);
  215. return 0;
  216. }
  217. /* Respect no_proxy, taking default value from environment variable(s) */
  218. static int use_proxy(const char *no_proxy, const char *server)
  219. {
  220. size_t sl;
  221. const char *found = NULL;
  222. if (!ossl_assert(server != NULL))
  223. return 0;
  224. sl = strlen(server);
  225. /*
  226. * using environment variable names, both lowercase and uppercase variants,
  227. * compatible with other HTTP client implementations like wget, curl and git
  228. */
  229. if (no_proxy == NULL)
  230. no_proxy = getenv("no_proxy");
  231. if (no_proxy == NULL)
  232. no_proxy = getenv(OPENSSL_NO_PROXY);
  233. if (no_proxy != NULL)
  234. found = strstr(no_proxy, server);
  235. while (found != NULL
  236. && ((found != no_proxy && found[-1] != ' ' && found[-1] != ',')
  237. || (found[sl] != '\0' && found[sl] != ' ' && found[sl] != ',')))
  238. found = strstr(found + 1, server);
  239. return found == NULL;
  240. }
  241. /* Take default value from environment variable(s), respect no_proxy */
  242. const char *OSSL_HTTP_adapt_proxy(const char *proxy, const char *no_proxy,
  243. const char *server, int use_ssl)
  244. {
  245. /*
  246. * using environment variable names, both lowercase and uppercase variants,
  247. * compatible with other HTTP client implementations like wget, curl and git
  248. */
  249. if (proxy == NULL)
  250. proxy = getenv(use_ssl ? "https_proxy" : "http_proxy");
  251. if (proxy == NULL)
  252. proxy = getenv(use_ssl ? OPENSSL_HTTP_PROXY :
  253. OPENSSL_HTTPS_PROXY);
  254. if (proxy == NULL || *proxy == '\0' || !use_proxy(no_proxy, server))
  255. return NULL;
  256. return proxy;
  257. }