diff options
-rw-r--r-- | crypto/err/openssl.txt | 2 | ||||
-rw-r--r-- | crypto/http/http_err.c | 4 | ||||
-rw-r--r-- | crypto/http/http_lib.c | 93 | ||||
-rw-r--r-- | doc/man3/OSSL_HTTP_parse_url.pod | 34 | ||||
-rw-r--r-- | include/openssl/http.h | 3 | ||||
-rw-r--r-- | include/openssl/httperr.h | 2 | ||||
-rw-r--r-- | util/libcrypto.num | 1 |
7 files changed, 105 insertions, 34 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 530e3217e4..e9a179c362 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -757,7 +757,7 @@ HTTP_R_FAILED_READING_DATA:128:failed reading data HTTP_R_INCONSISTENT_CONTENT_LENGTH:120:inconsistent content length HTTP_R_INVALID_PORT_NUMBER:123:invalid port number 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_MISSING_ASN1_ENCODING:110:missing asn1 encoding HTTP_R_MISSING_CONTENT_TYPE:121:missing content type diff --git a/crypto/http/http_err.c b/crypto/http/http_err.c index 20235ba0f8..2bb6d97290 100644 --- a/crypto/http/http_err.c +++ b/crypto/http/http_err.c @@ -32,8 +32,8 @@ static const ERR_STRING_DATA HTTP_str_reasons[] = { {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_INVALID_URL_SCHEME), + "invalid url scheme"}, {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 3c894d8629..6b8c15471e 100644 --- a/crypto/http/http_lib.c +++ b/crypto/http/http_lib.c @@ -36,21 +36,21 @@ static void free_pstring(char **pstr) } } -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) +int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost, + char **pport, int *pport_num, + char **ppath, char **pquery, char **pfrag) { const char *p, *tmp; + const char *scheme, *scheme_end; const char *user, *user_end; const char *host, *host_end; - const char *port = OSSL_HTTP_PORT, *port_end; + const char *port, *port_end; unsigned int portnum; const char *path, *path_end; const char *query, *query_end; const char *frag, *frag_end; - if (pssl != NULL) - *pssl = 0; + init_pstring(pscheme); init_pstring(puser); init_pstring(phost); init_pstring(pport); @@ -63,19 +63,15 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost, return 0; } - /* check for optional prefix "http[s]://" */ + /* check for optional prefix "<scheme>://" */ + scheme = scheme_end = url; p = strstr(url, "://"); if (p == NULL) { p = url; - } else { /* p points to end of scheme name */ - if (strncmp(url, OSSL_HTTPS_NAME, strlen(OSSL_HTTPS_NAME)) == 0) { - if (pssl != NULL) - *pssl = 1; - 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; - } + } else { + scheme_end = p; + if (scheme_end == scheme) + goto parse_err; 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 ':' */ + port = "0"; /* default */ if (*p == ':') port = ++p; /* remaining port spec handling is also done for the default values */ /* 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); goto err; } @@ -150,7 +147,8 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost, 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(puser, user, user_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: + free_pstring(pscheme); + free_pstring(puser); free_pstring(phost); free_pstring(pport); free_pstring(ppath); @@ -182,6 +182,63 @@ int OSSL_HTTP_parse_url(const char *url, int *pssl, char **puser, char **phost, 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) { size_t sl; diff --git a/doc/man3/OSSL_HTTP_parse_url.pod b/doc/man3/OSSL_HTTP_parse_url.pod index 5933e954da..60589b6bf9 100644 --- a/doc/man3/OSSL_HTTP_parse_url.pod +++ b/doc/man3/OSSL_HTTP_parse_url.pod @@ -2,6 +2,7 @@ =head1 NAME +OSSL_parse_url, OSSL_HTTP_parse_url, OCSP_parse_url - http utility functions @@ -10,6 +11,9 @@ OCSP_parse_url #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 *pssl, char **puser, char **phost, char **pport, int *pport_num, @@ -24,28 +28,34 @@ L<openssl_user_macros(7)>: =head1 DESCRIPTION -OSSL_HTTP_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 -into userinfo, host, port, path, query, and fragment components -and a flag indicating whether it begins with C<https>. +OSSL_parse_url() parses its input string I<url> as a URL of the form +C<[scheme://][userinfo@]host[:port][/path][?query][#fragment]> and splits it up +into scheme, userinfo, host, port, path, query, and fragment components. The host component may be a DNS name or an IP address 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 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</>. -If I<pssl> is not NULL, I<*pssl> is assigned 1 in case parsing was successful -and the schema part is present and is C<https>, else 0. -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. +Each non-NULL result pointer argument I<pscheme>, 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. 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. 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. + +OSSL_HTTP_parse_url() is a special form of OSSL_parse_url() +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 fucntion OCSP_parse_url(url, host, port, path, ssl) is -equivalent to OSSL_HTTP_parse_url(url, ssl, NULL, host, port, NULL, path, NULL, NULL). +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 diff --git a/include/openssl/http.h b/include/openssl/http.h index 508428a986..c39049918f 100644 --- a/include/openssl/http.h +++ b/include/openssl/http.h @@ -96,6 +96,9 @@ int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port, const char *proxyuser, const char *proxypass, 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, char **pport, int *pport_num, char **ppath, char **pquery, char **pfrag); diff --git a/include/openssl/httperr.h b/include/openssl/httperr.h index 796bc15a49..af5717d3dc 100644 --- a/include/openssl/httperr.h +++ b/include/openssl/httperr.h @@ -32,7 +32,7 @@ # define HTTP_R_INCONSISTENT_CONTENT_LENGTH 120 # define HTTP_R_INVALID_PORT_NUMBER 123 # 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_MISSING_ASN1_ENCODING 110 # define HTTP_R_MISSING_CONTENT_TYPE 121 diff --git a/util/libcrypto.num b/util/libcrypto.num index aa3071ec30..0c5318db8f 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4880,6 +4880,7 @@ ASN1_item_verify_ex ? 3_0_0 EXIST::FUNCTION: BIO_socket_wait ? 3_0_0 EXIST::FUNCTION:SOCK BIO_wait ? 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_asn1 ? 3_0_0 EXIST::FUNCTION: OSSL_HTTP_post_asn1 ? 3_0_0 EXIST::FUNCTION: |