Generalize schmeme parsing of OSSL_HTTP_parse_url() to OSSL_parse_url()

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14009)
This commit is contained in:
Dr. David von Oheimb 2021-02-17 17:24:19 +01:00 committed by Dr. David von Oheimb
parent 7932982b88
commit d546e8e267
7 changed files with 105 additions and 34 deletions

View File

@ -757,7 +757,7 @@ HTTP_R_FAILED_READING_DATA:128:failed reading data
HTTP_R_INCONSISTENT_CONTENT_LENGTH:120:inconsistent content length HTTP_R_INCONSISTENT_CONTENT_LENGTH:120:inconsistent content length
HTTP_R_INVALID_PORT_NUMBER:123:invalid port number HTTP_R_INVALID_PORT_NUMBER:123:invalid port number
HTTP_R_INVALID_URL_PATH:125:invalid url path HTTP_R_INVALID_URL_PATH:125:invalid url path
HTTP_R_INVALID_URL_PREFIX:124:invalid url prefix HTTP_R_INVALID_URL_SCHEME:124:invalid url scheme
HTTP_R_MAX_RESP_LEN_EXCEEDED:117:max resp len exceeded HTTP_R_MAX_RESP_LEN_EXCEEDED:117:max resp len exceeded
HTTP_R_MISSING_ASN1_ENCODING:110:missing asn1 encoding HTTP_R_MISSING_ASN1_ENCODING:110:missing asn1 encoding
HTTP_R_MISSING_CONTENT_TYPE:121:missing content type HTTP_R_MISSING_CONTENT_TYPE:121:missing content type

View File

@ -32,8 +32,8 @@ static const ERR_STRING_DATA HTTP_str_reasons[] = {
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_PORT_NUMBER), {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_PORT_NUMBER),
"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_PATH), "invalid url path"},
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_URL_PREFIX), {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_INVALID_URL_SCHEME),
"invalid url prefix"}, "invalid url scheme"},
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_MAX_RESP_LEN_EXCEEDED), {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_MAX_RESP_LEN_EXCEEDED),
"max resp len exceeded"}, "max resp len exceeded"},
{ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_MISSING_ASN1_ENCODING), {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_MISSING_ASN1_ENCODING),

View File

@ -36,21 +36,21 @@ static void free_pstring(char **pstr)
} }
} }
int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost, int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
char **pport, int *pport_num, char **pport, int *pport_num,
char **ppath, char **pquery, char **pfrag) char **ppath, char **pquery, char **pfrag)
{ {
const char *p, *tmp; const char *p, *tmp;
const char *scheme, *scheme_end;
const char *user, *user_end; const char *user, *user_end;
const char *host, *host_end; const char *host, *host_end;
const char *port = OSSL_HTTP_PORT, *port_end; const char *port, *port_end;
unsigned int portnum; unsigned int portnum;
const char *path, *path_end; const char *path, *path_end;
const char *query, *query_end; const char *query, *query_end;
const char *frag, *frag_end; const char *frag, *frag_end;
if (pssl != NULL) init_pstring(pscheme);
*pssl = 0;
init_pstring(puser); init_pstring(puser);
init_pstring(phost); init_pstring(phost);
init_pstring(pport); init_pstring(pport);
@ -63,19 +63,15 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
return 0; return 0;
} }
/* check for optional prefix "http[s]://" */ /* check for optional prefix "<scheme>://" */
scheme = scheme_end = url;
p = strstr(url, "://"); p = strstr(url, "://");
if (p == NULL) { if (p == NULL) {
p = url; p = url;
} else { /* p points to end of scheme name */ } else {
if (strncmp(url, OSSL_HTTPS_NAME, strlen(OSSL_HTTPS_NAME)) == 0) { scheme_end = p;
if (pssl != NULL) if (scheme_end == scheme)
*pssl = 1; goto parse_err;
port = OSSL_HTTPS_PORT;
} else if (strncmp(url, OSSL_HTTP_NAME, strlen(OSSL_HTTP_NAME)) != 0) {
ERR_raise(ERR_LIB_HTTP, HTTP_R_INVALID_URL_PREFIX);
goto err;
}
p += strlen("://"); p += strlen("://");
} }
@ -110,11 +106,12 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
} }
/* parse optional port specification starting with ':' */ /* parse optional port specification starting with ':' */
port = "0"; /* default */
if (*p == ':') if (*p == ':')
port = ++p; port = ++p;
/* remaining port spec handling is also done for the default values */ /* remaining port spec handling is also done for the default values */
/* make sure a decimal port number is given */ /* make sure a decimal port number is given */
if (!sscanf(port, "%u", &portnum) || portnum < 1 || portnum > 65535) { if (!sscanf(port, "%u", &portnum) || portnum > 65535) {
ERR_raise(ERR_LIB_HTTP, HTTP_R_INVALID_PORT_NUMBER); ERR_raise(ERR_LIB_HTTP, HTTP_R_INVALID_PORT_NUMBER);
goto err; goto err;
} }
@ -150,7 +147,8 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
frag = tmp + 1; frag = tmp + 1;
} }
if (!copy_substring(phost, host, host_end) if (!copy_substring(pscheme, scheme, scheme_end)
|| !copy_substring(phost, host, host_end)
|| !copy_substring(pport, port, port_end) || !copy_substring(pport, port, port_end)
|| !copy_substring(puser, user, user_end) || !copy_substring(puser, user, user_end)
|| !copy_substring(pquery, query, query_end) || !copy_substring(pquery, query, query_end)
@ -174,6 +172,8 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
ERR_raise(ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_URL); ERR_raise(ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_URL);
err: err:
free_pstring(pscheme);
free_pstring(puser);
free_pstring(phost); free_pstring(phost);
free_pstring(pport); free_pstring(pport);
free_pstring(ppath); free_pstring(ppath);
@ -182,6 +182,63 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
return 0; return 0;
} }
int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
char **pport, int *pport_num,
char **ppath, char **pquery, char **pfrag)
{
char *scheme, *port;
int ssl = 0, portnum;
init_pstring(pport);
if (pssl != NULL)
*pssl = 0;
if (!OSSL_parse_url(url, &scheme, puser, phost, &port, pport_num,
ppath, pquery, pfrag))
return 0;
/* check for optional HTTP scheme "http[s]" */
if (strcmp(scheme, OSSL_HTTPS_NAME) == 0) {
ssl = 1;
if (pssl != NULL)
*pssl = ssl;
} else if (*scheme != '\0' && strcmp(scheme, OSSL_HTTP_NAME) != 0) {
ERR_raise(ERR_LIB_HTTP, HTTP_R_INVALID_URL_SCHEME);
OPENSSL_free(scheme);
OPENSSL_free(port);
goto err;
}
OPENSSL_free(scheme);
if (strcmp(port, "0") == 0) {
/* set default port */
OPENSSL_free(port);
port = ssl ? OSSL_HTTPS_PORT : OSSL_HTTP_PORT;
if (!ossl_assert(sscanf(port, "%d", &portnum) == 1))
goto err;
if (pport_num != NULL)
*pport_num = portnum;
if (pport != NULL) {
*pport = OPENSSL_strdup(port);
if (*pport == NULL)
goto err;
}
} else {
if (pport != NULL)
*pport = port;
else
OPENSSL_free(port);
}
return 1;
err:
free_pstring(puser);
free_pstring(phost);
free_pstring(ppath);
free_pstring(pquery);
free_pstring(pfrag);
return 0;
}
int http_use_proxy(const char *no_proxy, const char *server) int http_use_proxy(const char *no_proxy, const char *server)
{ {
size_t sl; size_t sl;

View File

@ -2,6 +2,7 @@
=head1 NAME =head1 NAME
OSSL_parse_url,
OSSL_HTTP_parse_url, OSSL_HTTP_parse_url,
OCSP_parse_url OCSP_parse_url
- http utility functions - http utility functions
@ -10,6 +11,9 @@ OCSP_parse_url
#include <openssl/http.h> #include <openssl/http.h>
int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
char **pport, int *pport_num,
char **ppath, char **pquery, char **pfrag);
int OSSL_HTTP_parse_url(const char *url, int OSSL_HTTP_parse_url(const char *url,
int *pssl, char **puser, char **phost, int *pssl, char **puser, char **phost,
char **pport, int *pport_num, char **pport, int *pport_num,
@ -24,28 +28,34 @@ L<openssl_user_macros(7)>:
=head1 DESCRIPTION =head1 DESCRIPTION
OSSL_HTTP_parse_url() parses its input string I<url> as a URL of the form OSSL_parse_url() parses its input string I<url> as a URL of the form
C<[http[s]://][userinfo@]host[:port][/path][?query][#fragment]> and splits it up C<[scheme://][userinfo@]host[:port][/path][?query][#fragment]> and splits it up
into userinfo, host, port, path, query, and fragment components into scheme, userinfo, host, port, path, query, and fragment components.
and a flag indicating whether it begins with C<https>.
The host component may be a DNS name or an IP address The host component may be a DNS name or an IP address
where IPv6 addresses should be enclosed in square brackets C<[> and C<]>. where IPv6 addresses should be enclosed in square brackets C<[> and C<]>.
The port component is optional and defaults to "443" for HTTPS, else "80". The port component is optional and defaults to C<0>.
If given, it must be in decimal form. If the I<pport_num> argument is not NULL If given, it must be in decimal form. If the I<pport_num> argument is not NULL
the integer value of the port number is assigned to I<*pport_num> on success. the integer value of the port number is assigned to I<*pport_num> on success.
The path component is also optional and defaults to C</>. The path component is also optional and defaults to C</>.
If I<pssl> is not NULL, I<*pssl> is assigned 1 in case parsing was successful Each non-NULL result pointer argument I<pscheme>, I<puser>, I<phost>, I<pport>,
and the schema part is present and is C<https>, else 0. I<ppath>, I<pquery>, and I<pfrag>, is assigned the respective url component.
Each non-NULL result pointer argument I<puser>, I<phost>, I<pport>, I<ppath>,
I<pquery>, and I<pfrag>, is assigned the respective url component.
On success, they are guaranteed to contain non-NULL string pointers, else NULL. On success, they are guaranteed to contain non-NULL string pointers, else NULL.
It is the reponsibility of the caller to free them using L<OPENSSL_free(3)>. It is the reponsibility of the caller to free them using L<OPENSSL_free(3)>.
If I<pquery> is NULL, any given query component is handled as part of the path. If I<pquery> is NULL, any given query component is handled as part of the path.
A string returned via I<*ppath> is guaranteed to begin with a C</> character. A string returned via I<*ppath> is guaranteed to begin with a C</> character.
For absent userinfo, query, and fragment components an empty string is given. For absent scheme, userinfo, port, query, and fragment components
an empty string is provided.
Calling the deprecated fucntion OCSP_parse_url(url, host, port, path, ssl) is OSSL_HTTP_parse_url() is a special form of OSSL_parse_url()
equivalent to OSSL_HTTP_parse_url(url, ssl, NULL, host, port, NULL, path, NULL, NULL). where the scheme, if given, must be C<http> or C<https>.
If I<pssl> is not NULL, I<*pssl> is assigned 1 in case parsing was successful
and the scheme is C<https>, else 0.
The port component is optional and defaults to C<443> if the scheme is C<https>,
else C<80>.
Calling the deprecated function OCSP_parse_url(url, host, port, path, ssl)
is equivalent to
OSSL_HTTP_parse_url(url, ssl, NULL, host, port, NULL, path, NULL, NULL).
=head1 RETURN VALUES =head1 RETURN VALUES

View File

@ -96,6 +96,9 @@ int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port,
const char *proxyuser, const char *proxypass, const char *proxyuser, const char *proxypass,
int timeout, BIO *bio_err, const char *prog); int timeout, BIO *bio_err, const char *prog);
int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
char **pport, int *pport_num,
char **ppath, char **pquery, char **pfrag);
int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost, int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost,
char **pport, int *pport_num, char **pport, int *pport_num,
char **ppath, char **pquery, char **pfrag); char **ppath, char **pquery, char **pfrag);

View File

@ -32,7 +32,7 @@
# define HTTP_R_INCONSISTENT_CONTENT_LENGTH 120 # define HTTP_R_INCONSISTENT_CONTENT_LENGTH 120
# define HTTP_R_INVALID_PORT_NUMBER 123 # define HTTP_R_INVALID_PORT_NUMBER 123
# define HTTP_R_INVALID_URL_PATH 125 # define HTTP_R_INVALID_URL_PATH 125
# define HTTP_R_INVALID_URL_PREFIX 124 # define HTTP_R_INVALID_URL_SCHEME 124
# define HTTP_R_MAX_RESP_LEN_EXCEEDED 117 # define HTTP_R_MAX_RESP_LEN_EXCEEDED 117
# define HTTP_R_MISSING_ASN1_ENCODING 110 # define HTTP_R_MISSING_ASN1_ENCODING 110
# define HTTP_R_MISSING_CONTENT_TYPE 121 # define HTTP_R_MISSING_CONTENT_TYPE 121

View File

@ -4880,6 +4880,7 @@ ASN1_item_verify_ex ? 3_0_0 EXIST::FUNCTION:
BIO_socket_wait ? 3_0_0 EXIST::FUNCTION:SOCK BIO_socket_wait ? 3_0_0 EXIST::FUNCTION:SOCK
BIO_wait ? 3_0_0 EXIST::FUNCTION: BIO_wait ? 3_0_0 EXIST::FUNCTION:
BIO_do_connect_retry ? 3_0_0 EXIST::FUNCTION: BIO_do_connect_retry ? 3_0_0 EXIST::FUNCTION:
OSSL_parse_url ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_get ? 3_0_0 EXIST::FUNCTION: OSSL_HTTP_get ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_get_asn1 ? 3_0_0 EXIST::FUNCTION: OSSL_HTTP_get_asn1 ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_post_asn1 ? 3_0_0 EXIST::FUNCTION: OSSL_HTTP_post_asn1 ? 3_0_0 EXIST::FUNCTION: