blob: 9935bc7477a08cecf3a362be1ddb49c04647aac5 [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 <axutil_url.h>
#include <axutil_string.h>
#include <axutil_string.h>
#include <axutil_file_handler.h>
#include <axutil_network_handler.h>
#include <axutil_types.h>
struct axutil_url
{
axis2_char_t *protocol;
axis2_char_t *host;
int port;
axis2_char_t *path;
axis2_char_t *query;
axis2_char_t *server;
};
static int
is_safe_or_unreserve(
char c);
AXIS2_EXTERN axutil_url_t *AXIS2_CALL
axutil_url_create(
const axutil_env_t *env,
const axis2_char_t *protocol,
const axis2_char_t *host,
const int port,
const axis2_char_t *path)
{
axutil_url_t *url = NULL;
AXIS2_ENV_CHECK(env, NULL);
AXIS2_PARAM_CHECK(env->error, protocol, NULL);
if(!protocol || !*protocol || strstr(protocol, "://") || (host && strchr(host, '/')))
{
return NULL;
}
url = (axutil_url_t *)AXIS2_MALLOC(env->allocator, sizeof(axutil_url_t));
if(!url)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Out of memory");
return NULL;
}
url->protocol = axutil_strdup(env, protocol);
url->host = NULL;
url->path = NULL;
url->server = NULL;
url->query = NULL;
if(host)
{
url->host = (axis2_char_t *)axutil_strdup(env, host);
url->port = port;
}
else
{
url->port = 0;
}
/** if the path is not starting with / we have to make it so
*/
if(path)
{
axis2_char_t *params = NULL;
axis2_char_t *temp = NULL;
if(path[0] == '/')
{
temp = (axis2_char_t *)axutil_strdup(env, path);
}
else
{
temp = axutil_stracat(env, "/", path);
}
params = strchr(temp, '?');
if(!params)
{
params = strchr(temp, '#');
}
if(params)
{
url->query = (axis2_char_t *)axutil_strdup(env, params);
*params = '\0';
}
url->path = (axis2_char_t *)axutil_strdup(env, temp);
AXIS2_FREE(env->allocator, temp);
}
return url;
}
AXIS2_EXTERN axutil_url_t *AXIS2_CALL
axutil_url_parse_string(
const axutil_env_t *env,
const axis2_char_t *str_url)
{
/**
* Only accepted format is :
* protocol://host:port/path
* Added file:///path
* port is optional and the default port is assumed
* if path is not present / (root) is assumed
*/
axis2_char_t *tmp_url_str = NULL;
axutil_url_t *ret = NULL;
const axis2_char_t *protocol = NULL;
axis2_char_t *path = NULL;
axis2_char_t *port_str = NULL;
axis2_char_t *host = NULL;
int port = 0;
AXIS2_ENV_CHECK(env, NULL);
AXIS2_PARAM_CHECK(env->error, str_url, NULL);
tmp_url_str = axutil_strdup(env, str_url);
if(!tmp_url_str)
{
return NULL;
}
protocol = tmp_url_str;
host = strstr(tmp_url_str, "://");
if(!host)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_ADDRESS, AXIS2_FAILURE);
AXIS2_FREE(env->allocator, tmp_url_str);
return NULL;
}
if(axutil_strlen(host) < 3 * sizeof(axis2_char_t))
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_ADDRESS, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Invalid IP or hostname");
AXIS2_FREE(env->allocator, tmp_url_str);
return NULL;
}
*host = '\0';
host += 3 * sizeof(axis2_char_t); /* skip "://" part */
if(axutil_strlen(host) <= 0)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_ADDRESS, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Invalid IP or hostname");
AXIS2_FREE(env->allocator, tmp_url_str);
return NULL;
}
/* if the url is file:// thing we need the protocol and
* path only
*/
if(0 == axutil_strcasecmp(protocol, (const axis2_char_t *)"file"))
{
ret = axutil_url_create(env, protocol, NULL, 0, host);
AXIS2_FREE(env->allocator, tmp_url_str);
return ret;
}
port_str = strchr(host, ':');
if(!port_str)
{
path = strchr(host, '/');
if(!path)
{
path = strchr(host, '?');
}
else
{
*path++ = '\0';
}
if(!path)
{
path = strchr(host, '#');
}
if(!path)
{
/* No path - assume def path ('/') */
/* here we have protocol + host + def port + def path */
ret = axutil_url_create(env, protocol, host, port, "/");
AXIS2_FREE(env->allocator, tmp_url_str);
return ret;
}
else
{
axis2_char_t *path_temp = NULL;
path_temp = axutil_strdup(env, path);
*path = '\0';
/* here we have protocol + host + def port + path */
ret = axutil_url_create(env, protocol, host, port, path_temp);
AXIS2_FREE(env->allocator, tmp_url_str);
AXIS2_FREE(env->allocator, path_temp);
return ret;
}
}
else
{
*port_str++ = '\0';
path = strchr(port_str, '/');
if(!path)
{
path = strchr(port_str, '?');
if(path)
{
*path = '\0';
port = AXIS2_ATOI(port_str);
*path = '?';
}
}
else
{
*path++ = '\0';
port = AXIS2_ATOI(port_str);
}
if(!path)
{
path = strchr(port_str, '#');
if(path)
{
*path = '\0';
port = AXIS2_ATOI(port_str);
*path = '#';
}
}
if(!path)
{
port = AXIS2_ATOI(port_str);
/* here we have protocol + host + port + def path */
ret = axutil_url_create(env, protocol, host, port, "/");
AXIS2_FREE(env->allocator, tmp_url_str);
return ret;
}
else
{
if(axutil_strlen(path) > 0)
{
axis2_char_t *path_temp = NULL;
path_temp = axutil_strdup(env, path);
*path = '\0';
/* here we have protocol + host + port + path */
ret = axutil_url_create(env, protocol, host, port, path_temp);
AXIS2_FREE(env->allocator, tmp_url_str);
AXIS2_FREE(env->allocator, path_temp);
return ret;
}
else
{
/* here we have protocol + host + port + def path */
ret = axutil_url_create(env, protocol, host, port, "/");
AXIS2_FREE(env->allocator, tmp_url_str);
return ret;
}
}
}
}
AXIS2_EXTERN void AXIS2_CALL
axutil_url_free(
axutil_url_t *url,
const axutil_env_t *env)
{
if(url->protocol)
{
AXIS2_FREE(env->allocator, url->protocol);
url->protocol = NULL;
}
if(url->host)
{
AXIS2_FREE(env->allocator, url->host);
url->host = NULL;
}
if(url->server)
{
AXIS2_FREE(env->allocator, url->server);
url->server = NULL;
}
if(url->path)
{
AXIS2_FREE(env->allocator, url->path);
url->path = NULL;
}
if(url->query)
{
AXIS2_FREE(env->allocator, url->query);
url->query = NULL;
}
AXIS2_FREE(env->allocator, url);
return;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_to_external_form(
axutil_url_t *url,
const axutil_env_t *env)
{
axis2_char_t *external_form = NULL;
axis2_ssize_t len = 0;
axis2_char_t port_str[11];
axis2_bool_t print_port = AXIS2_FALSE;
AXIS2_PARAM_CHECK(env->error, url, NULL);
if(!url->protocol)
return NULL;
if(url->port != 0 && url->port != axutil_uri_port_of_scheme(url->protocol))
{
print_port = AXIS2_TRUE;
sprintf(port_str, "%d", url->port);
len += axutil_strlen(port_str) + 1; /* +1 is for ':' */
}
len += axutil_strlen(url->protocol) + 6;
if(url->host)
len += axutil_strlen(url->host);
if(url->path)
len += axutil_strlen(url->path);
if(url->query)
len += axutil_strlen(url->query);
external_form = (axis2_char_t *)AXIS2_MALLOC(env->allocator, len + 1);
sprintf(external_form, "%s://%s%s%s%s%s",
url->protocol,
(url->host) ? url->host : "",
(print_port) ? ":" : "",
(print_port) ? port_str : "",
(url->path) ? url->path : "",
(url->query) ? url->query : "");
return external_form;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axutil_url_set_protocol(
axutil_url_t *url,
const axutil_env_t *env,
axis2_char_t *protocol)
{
AXIS2_PARAM_CHECK(env->error, protocol, AXIS2_FAILURE);
if(url->protocol)
{
AXIS2_FREE(env->allocator, url->protocol);
url->protocol = NULL;
}
url->protocol = axutil_strdup(env, protocol);
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_get_protocol(
axutil_url_t *url,
const axutil_env_t *env)
{
return url->protocol;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axutil_url_set_host(
axutil_url_t *url,
const axutil_env_t *env,
axis2_char_t *host)
{
AXIS2_PARAM_CHECK(env->error, host, AXIS2_FAILURE);
if(url->host)
{
AXIS2_FREE(env->allocator, url->host);
}
url->host = axutil_strdup(env, host);
if(url->server)
{
AXIS2_FREE(env->allocator, url->server);
url->server = NULL;
}
if(url->host)
{
axis2_ssize_t len;
axis2_char_t port_str[11];
axis2_bool_t print_port = AXIS2_FALSE;
len = axutil_strlen(url->host);
if(url->port != 0
&& (!url->protocol || url->port != axutil_uri_port_of_scheme(url->protocol)))
{
print_port = AXIS2_TRUE;
sprintf(port_str, "%d", url->port);
len += axutil_strlen(port_str) + 1; /* +1 is for ':' */
}
url->server = (axis2_char_t *)AXIS2_MALLOC(env->allocator, len + 1);
sprintf(url->server, "%s%s%s",
url->host,
(print_port) ? ":" : "",
(print_port) ? port_str : "");
}
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_get_host(
axutil_url_t *url,
const axutil_env_t *env)
{
return url->host;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axutil_url_set_server(
axutil_url_t *url,
const axutil_env_t *env,
axis2_char_t *server)
{
axis2_char_t *temp = NULL;
axis2_char_t *port_str = NULL;
AXIS2_PARAM_CHECK(env->error, server, AXIS2_FAILURE);
if(*server == ':' || strchr(server, '/'))
return AXIS2_FAILURE;
if(url->server)
{
AXIS2_FREE(env->allocator, url->server);
url->server = NULL;
}
if(url->host)
{
AXIS2_FREE(env->allocator, url->host);
url->host = NULL;
}
url->port = 0;
url->server = axutil_strdup(env, server);
temp = axutil_strdup(env, server);
port_str = strchr(temp, ':');
if(port_str)
{
*port_str++ = '\0';
url->port = AXIS2_ATOI(port_str);
}
url->host = axutil_strdup(env, temp);
AXIS2_FREE(env->allocator, temp);
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_get_server(
axutil_url_t *url,
const axutil_env_t *env)
{
axis2_ssize_t len = 0;
axis2_char_t port_str[11];
axis2_bool_t print_port = AXIS2_FALSE;
if(!url->server && !url->host)
return NULL;
else if(!url->host)
{
AXIS2_FREE(env->allocator, url->server);
url->server = NULL;
return NULL;
}
else if(url->server)
return url->server;
len += axutil_strlen(url->host);
if(url->port != 0
&& (!url->protocol || url->port != axutil_uri_port_of_scheme(url->protocol)))
{
print_port = AXIS2_TRUE;
sprintf(port_str, "%d", url->port);
len += axutil_strlen(port_str) + 1; /* +1 is for ':' */
}
url->server = (axis2_char_t *)AXIS2_MALLOC(env->allocator, len + 1); /* +1 is for '/0' */
sprintf(url->server, "%s%s%s",
url->host,
(print_port) ? ":" : "",
(print_port) ? port_str : "");
return url->server;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axutil_url_set_port(
axutil_url_t *url,
const axutil_env_t *env,
int port)
{
axis2_ssize_t len = 0;
axis2_char_t port_str[11];
axis2_bool_t print_port = AXIS2_FALSE;
if(url->port == port)
return AXIS2_SUCCESS;
url->port = port;
if(url->server)
{
AXIS2_FREE(env->allocator, url->server);
url->server = NULL;
}
if(url->host)
{
len += axutil_strlen(url->host);
if(url->port != 0
&& (!url->protocol || url->port != axutil_uri_port_of_scheme(url->protocol)))
{
print_port = AXIS2_TRUE;
sprintf(port_str, "%d", url->port);
len += axutil_strlen(port_str) + 1; /* +1 is for ':' */
}
url->server = (axis2_char_t *)AXIS2_MALLOC(env->allocator, len + 1);
sprintf(url->server, "%s%s%s",
url->host,
(print_port) ? ":" : "",
(print_port) ? port_str : "");
}
return AXIS2_SUCCESS;
}
AXIS2_EXTERN int AXIS2_CALL
axutil_url_get_port(
axutil_url_t *url,
const axutil_env_t *env)
{
if(!url->port)
{
return axutil_uri_port_of_scheme(url->protocol);
}
return url->port;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axutil_url_set_path(
axutil_url_t *url,
const axutil_env_t *env,
axis2_char_t * path)
{
AXIS2_PARAM_CHECK(env->error, path, AXIS2_FAILURE);
if(url->path)
{
AXIS2_FREE(env->allocator, url->path);
url->path = NULL;
}
url->path = axutil_strdup(env, path);
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_get_path(
axutil_url_t *url,
const axutil_env_t *env)
{
return url->path;
}
AXIS2_EXTERN axutil_url_t *AXIS2_CALL
axutil_url_clone(
axutil_url_t *url,
const axutil_env_t *env)
{
axis2_char_t *temp = NULL;
axutil_url_t *ret = NULL;
if(url->path && url->query)
{
temp = axutil_stracat(env, url->path, url->query);
}
else if(url->path)
{
temp = axutil_strdup(env, url->path);
}
else if(url->query)
{
temp = axutil_strdup(env, url->query);
}
ret = axutil_url_create(env, url->protocol, url->host, url->port, url->path);
if(temp)
{
AXIS2_FREE(env->allocator, temp);
}
return ret;
}
AXIS2_EXTERN axutil_uri_t *AXIS2_CALL
axutil_url_to_uri(
axutil_url_t *url,
const axutil_env_t *env)
{
axis2_char_t *url_str = NULL;
axutil_uri_t *uri = NULL;
url_str = axutil_url_to_external_form(url, env);
uri = axutil_uri_parse_string(env, url_str);
return uri;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_encode(
const axutil_env_t *env,
axis2_char_t *dest,
axis2_char_t *buff,
int len)
{
axis2_char_t string[4];
axis2_char_t *expand_buffer = NULL;
axis2_char_t *temp = NULL;
int i;
for(i = 0; i < len && buff[i]; i++)
{
if(isalnum(buff[i]) || is_safe_or_unreserve(buff[i]))
{
sprintf(string, "%c", buff[i]);
}
else
{
/* %%%x is to print % mark with the hex value */
sprintf(string, "%%%x", buff[i]);
}
if(((int)strlen(dest) + 4) > len)
{
expand_buffer = (axis2_char_t *)AXIS2_MALLOC(env->allocator, len * 2);
memset(expand_buffer, 0, len * 2);
len *= 2;
temp = memmove(expand_buffer, dest, strlen(dest));
if(dest)
{
AXIS2_FREE(env->allocator, dest);
dest = NULL;
}
dest = temp;
}
strcat(dest, string);
}
return dest;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axutil_url_get_query(
axutil_url_t *url,
const axutil_env_t *env)
{
return url->query;
}
static int
is_safe_or_unreserve(
char c)
{
char safe[] = { '-', '_', '.', '~' };
char reserve[] = { ';', '/', '?', ':', '@', '&', '=', '#', '[', ']', '!', '$', '\'', '(', ')',
'*', '+', ',' };
/* These are reserved and safe charaters , got from RFC
*
* reserved = ";" | "/" | "?" | ":" | "@" | "&" | "="
* safe = "$" | "-" | "_" | "." | "+"
*/
int flag = 0;
int i = 0;
int size = sizeof(safe) / sizeof(safe[0]);
for(i = 0; i < size; i++)
{
if(c == safe[i])
{
flag = 1;
return flag;
}
}
size = sizeof(reserve) / sizeof(reserve[0]);
for(i = 0; i < size; i++)
{
if(c == reserve[i])
{
flag = 0;
return flag;
}
}
return flag;
}