/* * 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 #include #include #include #include #include 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; }