blob: b5bdaaee7fa0eee8d777d6685f5adcf4629bea93 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#define AXIS2_WANT_STRFUNC
#include <axutil_uri.h>
typedef struct schemes_t schemes_t;
/** Structure to store various schemes and their default ports */
struct schemes_t
{
/** The name of the scheme */
const axis2_char_t *name;
/** The default port for the scheme */
axis2_port_t default_port;
};
/* Some WWW schemes and their default ports; this is basically /etc/services */
/* This will become global when the protocol abstraction comes */
/* As the schemes are searched by a linear search, */
/* they are sorted by their expected frequency */
static schemes_t schemes[] = {
{"http", AXIS2_URI_HTTP_DEFAULT_PORT},
{"ftp", AXIS2_URI_FTP_DEFAULT_PORT},
{"https", AXIS2_URI_HTTPS_DEFAULT_PORT},
{"gopher", AXIS2_URI_GOPHER_DEFAULT_PORT},
{"ldap", AXIS2_URI_LDAP_DEFAULT_PORT},
{"nntp", AXIS2_URI_NNTP_DEFAULT_PORT},
{"snews", AXIS2_URI_SNEWS_DEFAULT_PORT},
{"imap", AXIS2_URI_IMAP_DEFAULT_PORT},
{"pop", AXIS2_URI_POP_DEFAULT_PORT},
{"sip", AXIS2_URI_SIP_DEFAULT_PORT},
{"rtsp", AXIS2_URI_RTSP_DEFAULT_PORT},
{"wais", AXIS2_URI_WAIS_DEFAULT_PORT},
{"z39.50r", AXIS2_URI_WAIS_DEFAULT_PORT},
{"z39.50s", AXIS2_URI_WAIS_DEFAULT_PORT},
{"prospero", AXIS2_URI_PROSPERO_DEFAULT_PORT},
{"nfs", AXIS2_URI_NFS_DEFAULT_PORT},
{"tip", AXIS2_URI_TIP_DEFAULT_PORT},
{"acap", AXIS2_URI_ACAP_DEFAULT_PORT},
{"telnet", AXIS2_URI_TELNET_DEFAULT_PORT},
{"ssh", AXIS2_URI_SSH_DEFAULT_PORT},
{NULL, 0xFFFF} /* unknown port */
};
/* Here is the hand-optimized parse_uri_components(). There are some wild
* tricks we could pull in assembly language that we don't pull here... like we
* can do word-at-time scans for delimiter characters using the same technique
* that fast axutil_memchr()s use. But that would be way non-portable. -djg
*/
/* We have a axis2_table_t that we can index by character and it tells us if the
* character is one of the interesting delimiters. Note that we even get
* compares for NUL for free -- it's just another delimiter.
*/
#define T_COLON 0x01 /* ':' */
#define T_SLASH 0x02 /* '/' */
#define T_QUESTION 0x04 /* '?' */
#define T_HASH 0x08 /* '#' */
#define T_NUL 0x80 /* '\0' */
#if AXIS2_CHARSET_EBCDIC
/* Delimiter table for the EBCDIC character set */
static const unsigned char uri_delims[256] = {
T_NUL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, T_SLASH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, T_QUESTION,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, T_COLON, T_HASH, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#else
/* Delimiter table for the ASCII character set */
static const unsigned char uri_delims[256] = {
T_NUL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, T_HASH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, T_SLASH,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, T_COLON, 0, 0, 0, 0, T_QUESTION,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#endif
/* it works like this:
if (uri_delims[ch] & NOTEND_foobar) {
then we're not at a delimiter for foobar
}
*/
/* Note that we optimize the scheme scanning here, we cheat and let the
* compiler know that it doesn't have to do the & masking.
*/
#define NOTEND_SCHEME (0xff)
#define NOTEND_HOSTINFO (T_SLASH | T_QUESTION | T_HASH | T_NUL)
#define NOTEND_PATH (T_QUESTION | T_HASH | T_NUL)
/**
* A structure to encompass all of the fields in a uri
*/
struct axutil_uri
{
/** scheme ("http"/"ftp"/...) */
axis2_char_t *scheme;
/** combined [user[:password]\@]host[:port] */
axis2_char_t *hostinfo;
/** user name, as in http://user:passwd\@host:port/ */
axis2_char_t *user;
/** password, as in http://user:passwd\@host:port/ */
axis2_char_t *password;
/** hostname from URI (or from Host: header) */
axis2_char_t *hostname;
/** port string (integer representation is in "port") */
axis2_char_t *port_str;
/** the request path (or "/" if only scheme://host was given) */
axis2_char_t *path;
/** Everything after a '?' in the path, if present */
axis2_char_t *query;
/** Trailing "#fragment" string, if present */
axis2_char_t *fragment;
/** structure returned from gethostbyname() */
struct hostent *hostent;
/** The port number, numeric, valid only if port_str */
axis2_port_t port;
/** has the structure been initialized */
unsigned is_initialized:1;
/** has the DNS been looked up yet */
unsigned dns_looked_up:1;
/** has the dns been resolved yet */
unsigned dns_resolved:1;
/** is it an IPv6 URL */
unsigned is_ipv6:1;
};
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_uri_create(
const axutil_env_t *env)
{
axutil_uri_t *uri = NULL;
AXIS2_ENV_CHECK(env, NULL);
uri = (axutil_uri_t *)AXIS2_MALLOC(env->allocator, sizeof(axutil_uri_t));
if(!uri)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Out of memory");
return NULL;
}
uri->scheme = NULL;
uri->hostinfo = NULL;
uri->user = NULL;
uri->password = NULL;
uri->hostname = NULL;
uri->port_str = NULL;
uri->path = NULL;
uri->query = NULL;
uri->fragment = NULL;
uri->hostent = NULL;
uri->port = 0;
uri->is_ipv6 = 0;
return uri;
}
AXIS2_EXTERN void AXIS2_CALL
axutil_uri_free(
axutil_uri_t *uri,
const axutil_env_t *env)
{
AXIS2_ENV_CHECK(env, AXIS2_FAILURE);
if(uri->scheme)
{
AXIS2_FREE(env->allocator, uri->scheme);
uri->scheme = NULL;
}
if(uri->hostinfo)
{
AXIS2_FREE(env->allocator, uri->hostinfo);
uri->hostinfo = NULL;
}
if(uri->user)
{
AXIS2_FREE(env->allocator, uri->user);
uri->user = NULL;
}
if(uri->password)
{
AXIS2_FREE(env->allocator, uri->password);
uri->password = NULL;
}
if(uri->hostname)
{
AXIS2_FREE(env->allocator, uri->hostname);
uri->hostname = NULL;
}
if(uri->port_str)
{
AXIS2_FREE(env->allocator, uri->port_str);
uri->port_str = NULL;
}
if(uri->path)
{
AXIS2_FREE(env->allocator, uri->path);
uri->path = NULL;
}
if(uri->query)
{
AXIS2_FREE(env->allocator, uri->query);
uri->query = NULL;
}
if(uri->fragment)
{
AXIS2_FREE(env->allocator, uri->fragment);
uri->fragment = NULL;
}
AXIS2_FREE(env->allocator, uri);
return;
}
/* parse_uri_components():
* Parse a given URI, fill in all supplied fields of a uri_components
* structure. This eliminates the necessity of extracting host, port,
* path, query info repeatedly in the modules.
* Side effects:
* - fills in fields of uri_components *uptr
* - none on any of the r->* fields
*/
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_uri_parse_string(
const axutil_env_t *env,
const axis2_char_t *uri_str)
{
axutil_uri_t *uri = NULL;
const axis2_char_t *s;
const axis2_char_t *s1;
const axis2_char_t *hostinfo;
axis2_char_t *endstr;
int port;
int v6_offset1 = 0, v6_offset2 = 0;
AXIS2_PARAM_CHECK(env->error, uri_str, NULL);
uri = (axutil_uri_t *)axutil_uri_create(env);
/* Initialize the structure. parse_uri() and parse_uri_components()
* can be called more than once per request.
*/
uri->is_initialized = 1;
/* We assume the processor has a branch predictor like most --
* it assumes forward branches are untaken and backwards are taken. That's
* the reason for the gotos.
*/
if(uri_str[0] == '/')
{
/* RFC2396 #4.3 says that two leading slashes mean we have an
* authority component, not a path! Fixing this looks scary
* with the gotos here. But if the existing logic is valid,
* then presumably a goto pointing to deal_with_authority works.
*
* RFC2396 describes this as resolving an ambiguity. In the
* case of three or more slashes there would seem to be no
* ambiguity, so it is a path after all.
*/
if(uri_str[1] == '/' && uri_str[2] != '/')
{
s = uri_str + 2;
goto deal_with_authority;
}
deal_with_path:
/* we expect uri to point to first character of path ... remember
* that the path could be empty -- http://foobar?query for example
*/
s = uri_str;
if((!uri->hostinfo && uri_str[0] == '/' && uri_str[1] == '/') || (!uri->scheme
&& uri_str[0] == ':'))
{
if(uri)
{
axutil_uri_free(uri, env);
}
uri = NULL;
goto end;
}
while((uri_delims[*(unsigned char *)s] & NOTEND_PATH) == 0)
{
++s;
}
if(s != uri_str)
{
uri->path = axutil_strmemdup(uri_str, s - uri_str, env);
}
if(*s == 0)
{
goto end;
}
if(*s == '?')
{
++s;
s1 = strchr(s, '#');
if(s1)
{
uri->fragment = axutil_strdup(env, s1 + 1);
uri->query = axutil_strmemdup(s, s1 - s, env);
}
else
{
uri->query = axutil_strdup(env, s);
}
goto end;
}
/* otherwise it's a fragment */
uri->fragment = axutil_strdup(env, s + 1);
goto end;
}
/* find the scheme: */
s = uri_str;
while((uri_delims[*(unsigned char *)s] & NOTEND_SCHEME) == 0)
{
++s;
}
/* scheme must be non-empty and followed by :// */
if(s == uri_str || s[0] != ':' || s[1] != '/' || s[2] != '/')
{
if(uri->scheme)
{
AXIS2_FREE(env->allocator, uri->scheme);
uri->scheme = NULL;
}
s = uri_str; /* restart from beginning as the loop must have ended in
* in a wrong place. */
goto deal_with_authority;
/* backwards predicted taken! */
}
uri->scheme = axutil_strmemdup(uri_str, s - uri_str, env);
s += 3;
deal_with_authority: hostinfo = s;
while((uri_delims[*(unsigned char *)s] & NOTEND_HOSTINFO) == 0)
{
++s;
}
uri_str = s; /* whatever follows hostinfo is start of uri */
uri->hostinfo = axutil_strmemdup(hostinfo, uri_str - hostinfo, env);
/* If there's a username:password@host:port, the @ we want is the last @...
* too bad there's no memrchr()... For the C purists, note that hostinfo
* is definitely not the first character of the original uri so therefore
* &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C.
*/
do
{
--s;
}
while(s >= hostinfo && *s != '@');
if(s < hostinfo)
{
/* again we want the common case to be fall through */
deal_with_host:
/* We expect hostinfo to point to the first character of
* the hostname. If there's a port it is the first colon,
* except with IPv6.
*/
if(*hostinfo == '[')
{
if(*(hostinfo + 1) == ']')
{
if(uri)
{
axutil_uri_free(uri, env);
}
uri = NULL;
goto end;
}
if((*(hostinfo + 1) >= '0' && *(hostinfo + 1) <= '9') || (*(hostinfo + 1) >= 'a'
&& *(hostinfo + 1) <= 'z') || (*(hostinfo + 1) >= 'A' && *(hostinfo + 1) <= 'Z')
|| (*(hostinfo + 1) == ':' && *(hostinfo + 2) == ':'))
{
uri->is_ipv6 = 1;
}
else
{
if(uri)
{
axutil_uri_free(uri, env);
}
uri = NULL;
goto end;
}
v6_offset1 = 1;
v6_offset2 = 2;
s = axutil_memchr(hostinfo, ']', uri_str - hostinfo);
if(!s)
{
if(uri)
{
axutil_uri_free(uri, env);
}
uri = NULL;
goto end;
}
if(*++s != ':')
{
s = NULL; /* no port */
}
}
else if(!*hostinfo || (*hostinfo >= '0' && *hostinfo <= '9') || (*hostinfo >= 'a'
&& *hostinfo <= 'z') || (*hostinfo >= 'A' && *hostinfo <= 'Z') || *hostinfo == '?'
|| *hostinfo == '/' || *hostinfo == '#')
{
s = axutil_memchr(hostinfo, ':', uri_str - hostinfo);
}
else
{
if(uri)
{
axutil_uri_free(uri, env);
}
uri = NULL;
goto end;
}
if(!s)
{
/* we expect the common case to have no port */
uri->hostname = axutil_strmemdup(hostinfo + v6_offset1,
uri_str - hostinfo - v6_offset2, env);
goto deal_with_path;
}
uri->hostname = axutil_strmemdup(hostinfo + v6_offset1, s - hostinfo - v6_offset2, env);
++s;
uri->port_str = axutil_strmemdup(s, uri_str - s, env);
if(uri_str != s)
{
port = strtol(uri->port_str, &endstr, 10);
uri->port = (axis2_port_t)port;
/* We are sure that the conversion is safe */
if(*endstr == '\0')
{
goto deal_with_path;
}
/* Invalid characters after ':' found */
if(uri)
{
axutil_uri_free(uri, env);
}
uri = NULL;
goto end;
}
uri->port = axutil_uri_port_of_scheme(uri->scheme);
goto deal_with_path;
}
/* first colon delimits username:password */
s1 = axutil_memchr(hostinfo, ':', s - hostinfo);
if(s1)
{
uri->user = axutil_strmemdup(hostinfo, s1 - hostinfo, env);
++s1;
uri->password = axutil_strmemdup(s1, s - s1, env);
}
else
{
uri->user = axutil_strmemdup(hostinfo, s - hostinfo, env);
}
hostinfo = s + 1;
goto deal_with_host;
/* End of function call */
end: return uri;
}
/* Special case for CONNECT parsing: it comes with the hostinfo part only */
/* See the INTERNET-DRAFT document "Tunneling SSL Through a WWW Proxy"
* currently at http://muffin.doit.org/docs/rfc/tunneling_ssl.html
* for the format of the "CONNECT host:port HTTP/1.0" request
*/
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_uri_parse_hostinfo(
const axutil_env_t *env,
const axis2_char_t *hostinfo)
{
axutil_uri_t *uri = NULL;
const axis2_char_t *s;
axis2_char_t *endstr;
const axis2_char_t *rsb;
int v6_offset1 = 0;
AXIS2_PARAM_CHECK(env->error, hostinfo, NULL);
uri = (axutil_uri_t *)axutil_uri_create(env);
if(!uri)
{
return NULL;
}
/* Initialize the structure. parse_uri() and parse_uri_components()
* can be called more than once per request.
*/
memset(uri, '\0', sizeof(*uri));
uri->is_initialized = 1;
uri->hostinfo = axutil_strdup(env, hostinfo);
/* We expect hostinfo to point to the first character of
* the hostname. There must be a port, separated by a colon
*/
if(*hostinfo == '[')
{
if(*(hostinfo + 1) == ']')
{
axutil_uri_free(uri, env);
return NULL;
}
uri->is_ipv6 = 1;
rsb = strchr(hostinfo, ']');
if(!rsb || *(rsb + 1) != ':')
{
axutil_uri_free(uri, env);
return NULL;
}
/* literal IPv6 address
* Special allowances has been made according to RFC3986 for
* IPv6 addresses beginning with "::"
*/
s = rsb + 1;
if((*(hostinfo + 1) >= '0' && *(hostinfo + 1) <= '9') || (*(hostinfo + 1) >= 'a'
&& *(hostinfo + 1) <= 'z') || (*(hostinfo + 1) >= 'A' && *(hostinfo + 1) <= 'Z')
|| (*(hostinfo + 1) == ':' && *(hostinfo + 2) == ':'))
{
++hostinfo;
}
else
{
axutil_uri_free(uri, env);
return NULL;
}
v6_offset1 = 1;
}
else if((*hostinfo >= '0' && *hostinfo <= '9') || (*hostinfo >= 'a' && *hostinfo <= 'z')
|| (*hostinfo >= 'A' && *hostinfo <= 'Z'))
{
s = strchr(hostinfo, ':');
}
else
{
axutil_uri_free(uri, env);
return NULL;
}
if(!s)
{
axutil_uri_free(uri, env);
return NULL;
}
uri->hostname = axutil_strndup(env, hostinfo, (int)(s - hostinfo - v6_offset1));
/* We are sure that the difference lies within the int range */
++s;
uri->port_str = axutil_strdup(env, s);
if(*s != '\0')
{
uri->port = (unsigned short)strtol(uri->port_str, &endstr, 10);
if(*endstr == '\0')
{
return uri;
}
/* Invalid characters after ':' found */
}
axutil_uri_free(uri, env);
return NULL;
}
/* Resolve relative to a base. This means host/etc, and (crucially) path */
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_uri_resolve_relative(
const axutil_env_t *env,
const axutil_uri_t *base,
axutil_uri_t *uri)
{
AXIS2_PARAM_CHECK(env->error, base, NULL);
AXIS2_PARAM_CHECK(env->error, uri, NULL);
if(!uri || !base || !base->is_initialized || !uri->is_initialized)
{
return NULL;
}
/* The interesting bit is the path. */
if(!uri->path)
{
if(!uri->hostname)
{
/* is this compatible with is_initialised? Harmless in any case */
uri->path = base->path ? base->path : axutil_strdup(env, "/");
}
else
{
/* deal with the idiosyncracy of APR allowing path==NULL
* without risk of breaking back-compatibility
*/
uri->path = axutil_strdup(env, "/");
}
}
else if(uri->path[0] != '/')
{
size_t baselen;
const char *basepath = base->path ? base->path : "/";
char *path = uri->path;
char *temp = NULL;
const char *base_end = strrchr(basepath, '/');
temp = path;
/* if base is nonsensical, bail out */
if(basepath[0] != '/')
{
return NULL;
}
/* munch "up" components at the start, and chop them from base path */
while(!strncmp(path, "../", 3))
{
while(base_end > basepath)
{
if(*--base_end == '/')
{
break;
}
}
path += 3;
}
/* munch "here" components at the start */
while(!strncmp(path, "./", 2))
{
path += 2;
}
baselen = base_end - basepath + 1;
uri->path = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * baselen + strlen(path) + 1);
memcpy(uri->path, basepath, baselen);
strcpy(uri->path + baselen, path);
if(temp)
{
AXIS2_FREE(env->allocator, temp);
}
}
/* The trivial bits are everything-but-path */
if(!uri->scheme)
{
uri->scheme = axutil_strdup(env, base->scheme);
}
if(!uri->hostinfo)
{
uri->hostinfo = axutil_strdup(env, base->hostinfo);
}
if(!uri->user)
{
uri->user = axutil_strdup(env, base->user);
}
if(!uri->password)
{
uri->password = axutil_strdup(env, base->password);
}
if(!uri->hostname)
{
uri->hostname = axutil_strdup(env, base->hostname);
}
if(!uri->port_str)
{
uri->port_str = axutil_strdup(env, base->port_str);
}
if(!uri->hostent)
{
uri->hostent = base->hostent;
}
if(!uri->port)
{
uri->port = base->port;
}
uri->is_ipv6 = base->is_ipv6;
return uri;
}
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_uri_parse_relative(
const axutil_env_t *env,
const axutil_uri_t *base,
const char *uri)
{
axutil_uri_t *uptr = NULL;
axutil_uri_t *temp = NULL;
uptr = axutil_uri_parse_string(env, uri);
if(!uptr && AXIS2_SUCCESS != AXIS2_ERROR_GET_STATUS_CODE(env->error))
{
return uptr;
}
temp = uptr;
uptr = axutil_uri_resolve_relative(env, base, uptr);
if(!uptr)
{
axutil_uri_free(temp, env);
}
return uptr;
}
AXIS2_EXTERN axis2_port_t AXIS2_CALL
axutil_uri_port_of_scheme(
const axis2_char_t *scheme_str)
{
schemes_t *scheme;
if(scheme_str)
{
for(scheme = schemes; scheme->name; ++scheme)
{
if(axutil_strcasecmp(scheme_str, scheme->name) == 0)
{
return scheme->default_port;
}
}
}
return 0;
}
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_uri_clone(
const axutil_uri_t *uri,
const axutil_env_t *env)
{
axutil_uri_t *new_uri = NULL;
new_uri = (axutil_uri_t *)axutil_uri_create(env);
new_uri->scheme = axutil_strdup(env, uri->scheme);
new_uri->hostinfo = axutil_strdup(env, uri->hostinfo);
new_uri->user = axutil_strdup(env, uri->user);
new_uri->password = axutil_strdup(env, uri->password);
new_uri->hostname = axutil_strdup(env, uri->hostname);
new_uri->port_str = axutil_strdup(env, uri->port_str);
new_uri->path = axutil_strdup(env, uri->path);
new_uri->query = axutil_strdup(env, uri->query);
new_uri->fragment = axutil_strdup(env, uri->fragment);
new_uri->hostent = uri->hostent;
new_uri->port = uri->port;
new_uri->is_initialized = uri->is_initialized;
new_uri->dns_looked_up = uri->dns_looked_up;
new_uri->dns_resolved = uri->dns_resolved;
new_uri->is_ipv6 = uri->is_ipv6;
return new_uri;
}
/* Unparse a axutil_uri_t structure to an URI string.
* Optionally suppress the password for security reasons.
*/
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_to_string(
const axutil_uri_t *uri,
const axutil_env_t *env,
unsigned flags)
{
axis2_char_t *ret = "";
axis2_char_t *temp = NULL;
AXIS2_ENV_CHECK(env, NULL);
/* If suppressing the site part, omit both user name & scheme://hostname */
if(!(flags & AXIS2_URI_UNP_OMITSITEPART))
{
/* Construct a "user:password@" string, honoring the passed
* AXIS2_URI_UNP_ flags: */
if(uri->user || uri->password)
{
ret = axutil_strcat(env, (uri->user && !(flags & AXIS2_URI_UNP_OMITUSER)) ? uri-> user
: "", (uri->password && !(flags & AXIS2_URI_UNP_OMITPASSWORD)) ? ":" : "",
(uri->password && !(flags & AXIS2_URI_UNP_OMITPASSWORD)) ? ((flags
& AXIS2_URI_UNP_REVEALPASSWORD) ? uri-> password : "XXXXXXXX") : "",
((uri->user && !(flags & AXIS2_URI_UNP_OMITUSER)) || (uri->password && !(flags
& AXIS2_URI_UNP_OMITPASSWORD))) ? "@" : "", NULL);
temp = ret;
}
/* Construct scheme://site string */
if(uri->hostname)
{
int is_default_port;
const axis2_char_t *lbrk = "", *rbrk = "";
if(uri->is_ipv6)
{ /* v6 literal */
lbrk = "[";
rbrk = "]";
}
is_default_port = (uri->port_str == NULL || uri->port == 0 || uri->port
== axutil_uri_port_of_scheme(uri->scheme));
if(uri->scheme)
{
ret = axutil_strcat(env, uri->scheme, "://", ret, lbrk, uri->hostname, rbrk,
is_default_port ? "" : ":", is_default_port ? "" : uri->port_str, NULL);
if(temp)
{
AXIS2_FREE(env->allocator, temp);
}
temp = ret;
}
else
{
/* Fixed to support Abbreviated URLs as in RFC2396.
* Thus, if no scheme, we omit "//" too, eventhough
* it is a part of authority.
*/
ret = axutil_strcat(env, ret, lbrk, uri->hostname, rbrk,
is_default_port ? "" : ":", is_default_port ? "" : uri->port_str, NULL);
/*ret =
axutil_strcat(env, "//", ret, lbrk, uri->hostname, rbrk,
is_default_port ? "" : ":",
is_default_port ? "" : uri->port_str, NULL);*/
if(temp)
{
AXIS2_FREE(env->allocator, temp);
}
temp = ret;
}
}
}
/* Should we suppress all path info? */
if(!(flags & AXIS2_URI_UNP_OMITPATHINFO))
{
/* Append path, query and fragment strings: */
ret = axutil_strcat(env, ret, (uri->path) ? uri->path : "", (uri->query && !(flags
& AXIS2_URI_UNP_OMITQUERY_ONLY)) ? "?" : "", (uri->query && !(flags
& AXIS2_URI_UNP_OMITQUERY_ONLY)) ? uri-> query : "", (uri->fragment && !(flags
& AXIS2_URI_UNP_OMITFRAGMENT_ONLY)) ? "#" : NULL, (uri->fragment && !(flags
& AXIS2_URI_UNP_OMITFRAGMENT_ONLY)) ? uri-> fragment : NULL, NULL);
if(temp)
{
AXIS2_FREE(env->allocator, temp);
}
}
return ret;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_get_protocol(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->scheme;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_get_server(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->hostinfo;
}
AXIS2_EXTERN axis2_port_t AXIS2_CALL
axutil_uri_get_port(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->port;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_get_host(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->hostname;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_get_query(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->query;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_get_fragment(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->fragment;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_uri_get_path(
axutil_uri_t *uri,
const axutil_env_t *env)
{
return uri->path;
}