summaryrefslogtreecommitdiffstats
path: root/crypto/http
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2020-09-03 13:32:56 +0200
committerDr. David von Oheimb <David.von.Oheimb@siemens.com>2020-09-08 15:36:24 +0200
commitd7fcee3b3b5fae674f107c736f8d53610212ce4e (patch)
treeb70c2afaf2fc49d5bd36102385584b3d0c72ae66 /crypto/http
parent8d6481f532ab8c502de2ad17e09f688abb675a71 (diff)
OSSL_HTTP_parse_url(): add optional port number return parameter and strengthen documentation
Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12786)
Diffstat (limited to 'crypto/http')
-rw-r--r--crypto/http/http_client.c3
-rw-r--r--crypto/http/http_err.c5
-rw-r--r--crypto/http/http_lib.c102
3 files changed, 70 insertions, 40 deletions
diff --git a/crypto/http/http_client.c b/crypto/http/http_client.c
index 3e1be1f569..5a78d67ca4 100644
--- a/crypto/http/http_client.c
+++ b/crypto/http/http_client.c
@@ -1005,7 +1005,8 @@ BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy,
return NULL;
for (;;) {
- if (!OSSL_HTTP_parse_url(current_url, &host, &port, &path, &use_ssl))
+ if (!OSSL_HTTP_parse_url(current_url, &host, &port, NULL /* port_num */,
+ &path, &use_ssl))
break;
new_rpath:
diff --git a/crypto/http/http_err.c b/crypto/http/http_err.c
index 7b6f295170..13779fac84 100644
--- a/crypto/http/http_err.c
+++ b/crypto/http/http_err.c
@@ -26,6 +26,11 @@ static const ERR_STRING_DATA HTTP_str_reasons[] = {
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_ERROR_SENDING), "error sending"},
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INCONSISTENT_CONTENT_LENGTH),
"inconsistent content length"},
+ {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_PORT_NUMBER),
+ "invalid port number"},
+ {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_URL_PATH), "invalid url path"},
+ {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_URL_PREFIX),
+ "invalid url prefix"},
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_MAX_RESP_LEN_EXCEEDED),
"max resp len exceeded"},
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_MISSING_ASN1_ENCODING),
diff --git a/crypto/http/http_lib.c b/crypto/http/http_lib.c
index 5da5b1e724..19b964e613 100644
--- a/crypto/http/http_lib.c
+++ b/crypto/http/http_lib.c
@@ -21,19 +21,12 @@
*/
int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport,
- char **ppath, int *pssl)
+ int *pport_num, char **ppath, int *pssl)
{
char *p, *buf;
- char *host;
- const char *port = OSSL_HTTP_PORT;
- size_t https_len = strlen(OSSL_HTTPS_NAME);
-
- if (!ossl_assert(https_len >= strlen(OSSL_HTTP_NAME)))
- return 0;
- if (url == NULL) {
- HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
+ char *host, *host_end;
+ const char *path, *port = OSSL_HTTP_PORT;
+ long portnum = 80;
if (phost != NULL)
*phost = NULL;
@@ -44,59 +37,90 @@ int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport,
if (pssl != NULL)
*pssl = 0;
+ if (url == NULL) {
+ HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
/* dup the buffer since we are going to mess with it */
if ((buf = OPENSSL_strdup(url)) == NULL)
goto err;
- /* Check for initial colon */
- p = strchr(buf, ':');
- if (p == NULL || (size_t)(p - buf) > https_len) {
+ /* check for optional prefix "http[s]://" */
+ p = strstr(buf, "://");
+ if (p == NULL) {
p = buf;
} else {
- *(p++) = '\0';
-
+ *p = '\0'; /* p points to end of scheme name */
if (strcmp(buf, OSSL_HTTPS_NAME) == 0) {
if (pssl != NULL)
*pssl = 1;
port = OSSL_HTTPS_PORT;
+ portnum = 443;
} else if (strcmp(buf, OSSL_HTTP_NAME) != 0) {
- goto parse_err;
+ HTTPerr(0, HTTP_R_INVALID_URL_PREFIX);
+ goto err;
}
-
- /* Check for double slash */
- if ((p[0] != '/') || (p[1] != '/'))
- goto parse_err;
- p += 2;
+ p += 3;
}
host = p;
- /* Check for trailing part of path */
- p = strchr(p, '/');
- if (ppath != NULL && (*ppath = OPENSSL_strdup(p == NULL ? "/" : p)) == NULL)
- goto err;
- if (p != NULL)
- *p = '\0'; /* Set start of path to 0 so hostname[:port] is valid */
-
- p = host;
+ /* parse host name/address as far as needed here */
if (host[0] == '[') {
- /* ipv6 literal */
+ /* ipv6 literal, which may include ':' */
host++;
- p = strchr(host, ']');
- if (p == NULL)
+ host_end = strchr(host, ']');
+ if (host_end == NULL)
goto parse_err;
- *p = '\0';
- p++;
+ *host_end++ = '\0';
+ } else {
+ host_end = strchr(host, ':'); /* look for start of optional port */
+ if (host_end == NULL)
+ host_end = strchr(host, '/'); /* look for start of optional path */
+ if (host_end == NULL)
+ /* the remaining string is just the hostname */
+ host_end = host + strlen(host);
}
- /* Look for optional ':' for port number */
- if ((p = strchr(p, ':'))) {
- *p = '\0';
- port = p + 1;
+ /* parse optional port specification starting with ':' */
+ p = host_end;
+ if (*p == ':') {
+ port = ++p;
+ if (pport_num == NULL) {
+ p = strchr(port, '/');
+ if (p == NULL)
+ p = p + strlen(port);
+ } else { /* make sure a numerical port value is given */
+ portnum = strtol(port, &p, 10);
+ if (p == port || (*p != '\0' && *p != '/'))
+ goto parse_err;
+ if (portnum <= 0 || portnum >= 65536) {
+ HTTPerr(0, HTTP_R_INVALID_PORT_NUMBER);
+ goto err;
+ }
+ }
+ }
+ *host_end = '\0';
+ *p = '\0'; /* terminate port string */
+
+ /* check for optional path at end of url starting with '/' */
+ path = url + (p - buf);
+ /* cannot use p + 1 because *p is '\0' and path must start with '/' */
+ if (*path == '\0') {
+ path = "/";
+ } else if (*path != '/') {
+ HTTPerr(0, HTTP_R_INVALID_URL_PATH);
+ goto parse_err;
}
+
if (phost != NULL && (*phost = OPENSSL_strdup(host)) == NULL)
goto err;
if (pport != NULL && (*pport = OPENSSL_strdup(port)) == NULL)
goto err;
+ if (pport_num != NULL)
+ *pport_num = (int)portnum;
+ if (ppath != NULL && (*ppath = OPENSSL_strdup(path)) == NULL)
+ goto err;
OPENSSL_free(buf);
return 1;