diff options
author | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2000-12-07 18:10:27 +0000 |
---|---|---|
committer | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2000-12-07 18:10:27 +0000 |
commit | fdf52cdf29edf195b5e1147047868317b7e516f6 (patch) | |
tree | 0e14b4f874cf77b49b5a0c359c36a2583779f17c | |
parent | 7b15744516297c9169556f253314926a43719d91 (diff) | |
download | libapr-fdf52cdf29edf195b5e1147047868317b7e516f6.tar.gz |
Add apr_parse_addr_port() for parsing the hostname:port portion of
URLs and similar strings.
Somebody with VC++ 6.0 needs to update the .dsp file(s) to include
inet_pton.c. The BeOS Makefile.in wasn't updated because I think
BeOS uses the unix code now.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@60916 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | aprlib.def | 1 | ||||
-rw-r--r-- | include/apr_network_io.h | 33 | ||||
-rw-r--r-- | libapr.def | 1 | ||||
-rw-r--r-- | network_io/os2/Makefile.in | 1 | ||||
-rw-r--r-- | network_io/unix/sa_common.c | 102 |
6 files changed, 140 insertions, 0 deletions
@@ -1,4 +1,6 @@ Changes with APR a9 + *) Add apr_parse_addr_port() for parsing the hostname:port portion + of URLs and similar strings. [Jeff Trawick] *) Add Win32 MMAP support [William Rowe] diff --git a/aprlib.def b/aprlib.def index 04efde19f..3ed3b2e1e 100644 --- a/aprlib.def +++ b/aprlib.def @@ -88,6 +88,7 @@ EXPORTS apr_get_port apr_set_port apr_get_inaddr + apr_parse_addr_port ; ; diff --git a/include/apr_network_io.h b/include/apr_network_io.h index 6683f555d..219fbfbde 100644 --- a/include/apr_network_io.h +++ b/include/apr_network_io.h @@ -306,6 +306,39 @@ apr_status_t apr_getaddrinfo(apr_sockaddr_t **sa, apr_pool_t *p); /** + * Parse hostname/IP address with scope id and port. + * + * Any of the following strings are accepted: + * 8080 (just the port number) + * www.apache.org (just the hostname) + * www.apache.org:8080 (hostname and port number) + * [fe80::1]:80 (IPv6 numeric address string only) + * [fe80::1%eth0] (IPv6 numeric address string and scope id) + * + * Invalid strings: + * (empty string) + * [abc] (not valid IPv6 numeric address string) + * abc:65536 (invalid port number) + * + * @param addr The new buffer containing just the hostname. On output, *addr + * will be NULL if no hostname/IP address was specfied. + * @param scope_id The new buffer containing just the scope id. On output, + * *scope_id will be NULL if no scope id was specified. + * @param port The port number. On output, *port will be 0 if no port was + * specified. + * @param str The input string to be parsed. + * @param p The pool from which *addr and *scope_id are allocated. + * @tip If scope id shouldn't be allowed, check for scope_id != NULL in addition + * to checking the return code. If addr/hostname should be required, check + * for addr == NULL in addition to checking the return code. + */ +apr_status_t apr_parse_addr_port(char **addr, + char **scope_id, + apr_port_t *port, + const char *str, + apr_pool_t *p); + +/** * Get name of the current machine * @param buf A buffer to store the hostname in. * @param len The maximum length of the hostname that can be stored in the diff --git a/libapr.def b/libapr.def index 04efde19f..3ed3b2e1e 100644 --- a/libapr.def +++ b/libapr.def @@ -88,6 +88,7 @@ EXPORTS apr_get_port apr_set_port apr_get_inaddr + apr_parse_addr_port ; ; diff --git a/network_io/os2/Makefile.in b/network_io/os2/Makefile.in index f23522533..e5077ea8a 100644 --- a/network_io/os2/Makefile.in +++ b/network_io/os2/Makefile.in @@ -17,6 +17,7 @@ OBJS=poll.o \ sockopt.o \ sockaddr.o \ inet_ntop.o \ + inet_pton.o \ os2calls.o .c.o: diff --git a/network_io/unix/sa_common.c b/network_io/unix/sa_common.c index f282df03f..3c0fa0c57 100644 --- a/network_io/unix/sa_common.c +++ b/network_io/unix/sa_common.c @@ -65,6 +65,10 @@ #include "apr.h" +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + apr_status_t apr_set_port(apr_sockaddr_t *sockaddr, apr_port_t port) { /* XXX IPv6: assumes sin_port and sin6_port at same offset */ @@ -178,6 +182,104 @@ apr_status_t apr_get_sockaddr(apr_sockaddr_t **sa, apr_interface_e which, apr_so return APR_SUCCESS; } +apr_status_t apr_parse_addr_port(char **addr, + char **scope_id, + apr_port_t *port, + const char *str, + apr_pool_t *p) +{ + const char *ch, *lastchar; + int big_port; + apr_size_t addrlen; + + *addr = NULL; /* assume not specified */ + *scope_id = NULL; /* assume not specified */ + *port = 0; /* assume not specified */ + + /* First handle the optional port number. That may be all that + * is specified in the string. + */ + ch = lastchar = str + strlen(str) - 1; + while (ch >= str && apr_isdigit(*ch)) { + --ch; + } + + if (ch < str) { /* Entire string is the port. */ + big_port = atoi(str); + if (big_port < 1 || big_port > 65535) { + return APR_EINVAL; + } + *port = big_port; + return APR_SUCCESS; + } + + if (*ch == ':' && ch < lastchar) { /* host and port number specified */ + if (ch == str) { /* string starts with ':' -- bad */ + return APR_EINVAL; + } + big_port = atoi(ch + 1); + if (big_port < 1 || big_port > 65535) { + return APR_EINVAL; + } + *port = big_port; + lastchar = ch - 1; + } + + /* now handle the hostname */ + addrlen = lastchar - str + 1; + +#if APR_HAVE_IPV6 /* XXX don't require this; would need to pass char[] for ipaddr and always define APR_INET6 */ + if (*str == '[') { + const char *end_bracket = memchr(str, ']', addrlen); + struct in6_addr ipaddr; + const char *scope_delim; + + if (!end_bracket || end_bracket != lastchar) { + *port = 0; + return APR_EINVAL; + } + + /* handle scope id; this is the only context where it is allowed */ + scope_delim = memchr(str, '%', addrlen); + if (scope_delim) { + if (scope_delim == end_bracket - 1) { /* '%' without scope identifier */ + *port = 0; + return APR_EINVAL; + } + addrlen = scope_delim - str - 1; + *scope_id = apr_palloc(p, end_bracket - scope_delim); + memcpy(*scope_id, scope_delim + 1, end_bracket - scope_delim - 1); + (*scope_id)[end_bracket - scope_delim - 1] = '\0'; + } + else { + addrlen = addrlen - 2; /* minus 2 for '[' and ']' */ + } + + *addr = apr_palloc(p, addrlen + 1); + memcpy(*addr, + str + 1, + addrlen); + (*addr)[addrlen] = '\0'; + if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) { + *addr = NULL; + *scope_id = NULL; + *port = 0; + return APR_EINVAL; + } + } + else +#endif + { + /* XXX If '%' is not a valid char in a DNS name, we *could* check + * for bogus scope ids first. + */ + *addr = apr_palloc(p, addrlen + 1); + memcpy(*addr, str, addrlen); + (*addr)[addrlen] = '\0'; + } + return APR_SUCCESS; +} + apr_status_t apr_getaddrinfo(apr_sockaddr_t **sa, const char *hostname, apr_int32_t family, apr_port_t port, apr_int32_t flags, apr_pool_t *p) |