Chunk 10 of CMP contribution to OpenSSL: CMP http client and related tests
[openssl.git] / crypto / http / http_lib.c
1 /*
2  * Copyright 2001-2020 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
10 #include <openssl/http.h>
11 #include <openssl/httperr.h>
12 #include <openssl/err.h>
13 #include <string.h>
14
15 #include "http_local.h"
16
17 /*
18  * Parse a URL and split it up into host, port and path components and
19  * whether it indicates SSL/TLS. Return 1 on success, 0 on error.
20  */
21
22 int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport,
23                         char **ppath, int *pssl)
24 {
25     char *p, *buf;
26     char *host;
27     char *port = "80";
28
29     if (url == NULL) {
30         HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER);
31         return 0;
32     }
33
34     if (phost != NULL)
35         *phost = NULL;
36     if (pport != NULL)
37         *pport = NULL;
38     if (ppath != NULL)
39         *ppath = NULL;
40     if (pssl != NULL)
41         *pssl = 0;
42
43     /* dup the buffer since we are going to mess with it */
44     if ((buf = OPENSSL_strdup(url)) == NULL)
45         goto err;
46
47     /* Check for initial colon */
48     p = strchr(buf, ':');
49     if (p == NULL || p - buf > 5 /* strlen("https") */) {
50         p = buf;
51     } else {
52         *(p++) = '\0';
53
54         if (strcmp(buf, "https") == 0) {
55             if (pssl != NULL)
56                 *pssl = 1;
57             port = "443";
58         } else if (strcmp(buf, "http") != 0) {
59             goto parse_err;
60         }
61
62         /* Check for double slash */
63         if ((p[0] != '/') || (p[1] != '/'))
64             goto parse_err;
65         p += 2;
66     }
67     host = p;
68
69     /* Check for trailing part of path */
70     p = strchr(p, '/');
71     if (ppath != NULL && (*ppath = OPENSSL_strdup(p == NULL ? "/" : p)) == NULL)
72         goto err;
73     if (p != NULL)
74         *p = '\0'; /* Set start of path to 0 so hostname[:port] is valid */
75
76     p = host;
77     if (host[0] == '[') {
78         /* ipv6 literal */
79         host++;
80         p = strchr(host, ']');
81         if (p == NULL)
82             goto parse_err;
83         *p = '\0';
84         p++;
85     }
86
87     /* Look for optional ':' for port number */
88     if ((p = strchr(p, ':'))) {
89         *p = '\0';
90         port = p + 1;
91     }
92     if (phost != NULL && (*phost = OPENSSL_strdup(host)) == NULL)
93         goto err;
94     if (pport != NULL && (*pport = OPENSSL_strdup(port)) == NULL)
95         goto err;
96
97     OPENSSL_free(buf);
98     return 1;
99
100  parse_err:
101     HTTPerr(0, HTTP_R_ERROR_PARSING_URL);
102
103  err:
104     if (ppath != NULL) {
105         OPENSSL_free(*ppath);
106         *ppath = NULL;
107     }
108     if (pport != NULL) {
109         OPENSSL_free(*pport);
110         *pport = NULL;
111     }
112     if (phost != NULL) {
113         OPENSSL_free(*phost);
114         *phost = NULL;
115     }
116     OPENSSL_free(buf);
117     return 0;
118 }
119
120 int http_use_proxy(const char *no_proxy, const char *server)
121 {
122     size_t sl = strlen(server);
123     const char *found = NULL;
124
125     if (no_proxy == NULL)
126         no_proxy = getenv("no_proxy");
127     if (no_proxy == NULL)
128         no_proxy = getenv("NO_PROXY");
129     if (no_proxy != NULL)
130         found = strstr(no_proxy, server);
131     while (found != NULL
132            && ((found != no_proxy && found[-1] != ' ' && found[-1] != ',')
133                || (found[sl] != '\0' && found[sl] != ' ' && found[sl] != ',')))
134         found = strstr(found + 1, server);
135     return found == NULL;
136 }
137
138 const char *http_adapt_proxy(const char *proxy, const char *no_proxy,
139                              const char *server, int use_ssl)
140 {
141     int prefix_len = strlen(HTTP_URL_PREFIX);
142
143     if (proxy == NULL)
144         proxy = getenv(use_ssl ? "https_proxy" : "http_proxy");
145     if (proxy == NULL)
146         proxy = getenv(use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
147     if (proxy != NULL && strncmp(proxy, HTTP_URL_PREFIX, prefix_len) == 0)
148         proxy += prefix_len; /* skip any leading "http://" */
149     if (proxy != NULL && *proxy == '\0')
150         proxy = NULL;
151     if (proxy != NULL && !http_use_proxy(no_proxy, server))
152         proxy = NULL;
153     return proxy;
154 }