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