blob: 51a6cc8327207e0b3b501186a057b80e3f14bf4b [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 <axis2_http_transport.h>
#include <axis2_conf.h>
#include <axutil_string.h>
#include <axis2_msg_ctx.h>
#include <axis2_http_out_transport_info.h>
#include <axis2_http_transport_utils.h>
#include <axis2_op_ctx.h>
#include <axis2_engine.h>
#include <axutil_uuid_gen.h>
#include <axis2_conf_init.h>
#include <axutil_url.h>
#include <axiom_soap.h>
#include "axis2_iis_out_transport_info.h"
#include "axis2_iis_stream.h"
#include "axis2_iis_worker.h"
/* Files from iis */
#include <httpfilt.h>
#include <httpext.h>
#include "axis2_iis_constants.h"
#define READ_SIZE 2048
axis2_status_t AXIS2_CALL
axis2_worker_get_original_url(
char url[],
char ret_url[]);
axis2_char_t * AXIS2_CALL
axis2_iis_worker_get_bytes(
const axutil_env_t * env,
axutil_stream_t * stream);
axis2_status_t AXIS2_CALL
start_response(
const axutil_env_t * env,
LPEXTENSION_CONTROL_BLOCK lpECB,
int status,
const char *reason,
axutil_array_list_t *headers);
axis2_status_t
write_response(
LPEXTENSION_CONTROL_BLOCK lpECB,
const void *b,
unsigned int l);
axutil_hash_t *
axis2_iis_worker_read_http_headers(
const axutil_env_t * env,
LPEXTENSION_CONTROL_BLOCK lpECB);
AXIS2_IMPORT extern axis2_char_t *axis2_request_url_prefix;
static struct reasons
{
axis2_char_t * status_code;
int status_len;
} reasons[] = { { "200 OK", 6 }, { "202 Accepted", 12 }, { "500 Internal Server Error", 25 } };
struct axis2_iis_worker
{
axis2_conf_ctx_t * conf_ctx;
};
char *
status_reason(
int status);
axis2_iis_worker_t * AXIS2_CALL
axis2_iis_worker_create(
const axutil_env_t * env,
axis2_char_t * repo_path)
{
axis2_iis_worker_t * iis_worker = NULL;
iis_worker = (axis2_iis_worker_t *)AXIS2_MALLOC(env->allocator, sizeof(axis2_iis_worker_t));
if(!iis_worker)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
return NULL;
}
iis_worker->conf_ctx = axis2_build_conf_ctx(env, repo_path);
if(!iis_worker->conf_ctx)
{
axis2_iis_worker_free((axis2_iis_worker_t *)iis_worker, env);
return NULL;
}
return iis_worker;
}
void AXIS2_CALL
axis2_iis_worker_free(
axis2_iis_worker_t * iis_worker,
const axutil_env_t * env)
{
if(iis_worker->conf_ctx)
{
axis2_conf_ctx_free(iis_worker->conf_ctx, env);
iis_worker->conf_ctx = NULL;
}
AXIS2_FREE(env->allocator, iis_worker);
return;
}
int AXIS2_CALL
axis2_iis_worker_process_request(
axis2_iis_worker_t * iis_worker,
const axutil_env_t * env,
LPEXTENSION_CONTROL_BLOCK lpECB)
{
axis2_conf_ctx_t * conf_ctx = NULL;
axutil_stream_t * out_stream = NULL;
axis2_transport_out_desc_t * out_desc = NULL;
axis2_transport_in_desc_t * in_desc = NULL;
axis2_char_t soap_action[INTERNET_MAX_URL_LENGTH];
axis2_char_t original_url[INTERNET_MAX_URL_LENGTH];
axis2_char_t req_url[INTERNET_MAX_URL_LENGTH];
DWORD cbSize = 0;
CHAR server_name[MAX_SERVERNAME];
axis2_char_t port[MAX_TCP_PORT_LEN];
axis2_char_t redirect_url[INTERNET_MAX_PATH_LENGTH];
axis2_char_t accept_language[INTERNET_MAX_PATH_LENGTH];
axutil_hash_t *headers = NULL;
axis2_char_t peer_ip[50];
axis2_char_t accept_header[INTERNET_MAX_URL_LENGTH];
axis2_char_t accept_charset[INTERNET_MAX_URL_LENGTH];
/*axutil_property_t *peer_property = NULL;*/
axis2_http_header_t *content_type_header = NULL;
axis2_http_header_t *content_length_header = NULL;
/* New Code variables */
axis2_http_transport_in_t request;
axis2_http_transport_out_t response;
/* initialize tranport in structure */
axis2_http_transport_utils_transport_in_init(&request, env);
/* initialize tranport out structure */
axis2_http_transport_utils_transport_out_init(&response, env);
soap_action[0] = '\0';
/*Check the parameters*/
if(!lpECB)
{
AXIS2_ERROR_SET_ERROR_NUMBER(env->error, AXIS2_ERROR_INVALID_NULL_PARAM);
return AXIS2_FAILURE;
}
conf_ctx = iis_worker->conf_ctx;
if(!conf_ctx)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NULL_CONFIGURATION_CONTEXT, AXIS2_FAILURE);
return AXIS2_FAILURE;
}
cbSize = INTERNET_MAX_PATH_LENGTH;
if(lpECB->GetServerVariable(lpECB->ConnID, "SERVER_NAME", server_name, &cbSize) == FALSE)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot get server name from IIS.");
return AXIS2_FAILURE;
}
cbSize = MAX_TCP_PORT_LEN;
if(lpECB->GetServerVariable(lpECB->ConnID, "SERVER_PORT", port, &cbSize) == FALSE)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot get server port from IIS.");
return AXIS2_FAILURE;
}
request.svr_port = port;
cbSize = INTERNET_MAX_PATH_LENGTH;
if(lpECB->GetServerVariable(lpECB->ConnID, "HTTP_URL", redirect_url, &cbSize) == FALSE)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot get server port from IIS.");
return AXIS2_FAILURE;
}
/* We have a mapped URL only when the server version is 5 or less than that. */
if(server_version <= 5)
{
axis2_worker_get_original_url(redirect_url, original_url);
/* create the url using the above variables */
sprintf(req_url, "%s%s%s%s%s", "http://", server_name, ":", port, original_url);
}
else
{
sprintf(req_url, "%s%s%s%s%s", "http://", server_name, ":", port, redirect_url);
}
/* Set the request url */
request.request_uri = req_url;
out_stream = axutil_stream_create_basic(env);
out_desc = axis2_conf_get_transport_out(axis2_conf_ctx_get_conf(iis_worker->conf_ctx, env),
env, AXIS2_TRANSPORT_ENUM_HTTP);
in_desc = axis2_conf_get_transport_in(axis2_conf_ctx_get_conf(iis_worker->conf_ctx, env), env,
AXIS2_TRANSPORT_ENUM_HTTP);
/* Create the in message context */
request.msg_ctx = axis2_msg_ctx_create(env, conf_ctx, in_desc, out_desc);
axis2_msg_ctx_set_server_side(request.msg_ctx, env, AXIS2_TRUE);
axis2_msg_ctx_set_transport_out_stream(request.msg_ctx, env, out_stream);
/* Get the SOAPAction Header */
cbSize = INTERNET_MAX_URL_LENGTH;
if(lpECB->GetServerVariable(lpECB->ConnID, "HTTP_SOAPAction", soap_action, &cbSize))
{
request.soap_action = soap_action;
}
/* Create the in stream */
request.in_stream = axutil_stream_create_iis(env, lpECB);
if(!request.in_stream)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error occured in creating input stream.");
return AXIS2_FAILURE;
}
/* Get the Remote Adrress */
if(lpECB->GetServerVariable(lpECB->ConnID, "REMOTE_ADDR", peer_ip, &cbSize))
{
request.remote_ip = peer_ip;
}
/* Set the http headers into the message context */
headers = axis2_iis_worker_read_http_headers(env, lpECB);
if(axis2_msg_ctx_set_transport_headers(request.msg_ctx, env, headers) == AXIS2_FAILURE)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "IIS: Error occured in setting transport headers.");
}
/* Set the content length */
request.content_length = lpECB->cbTotalBytes;
/* Set the HTTP method */
if(axutil_strcasecmp(lpECB->lpszMethod, "POST") == 0)
{
request.request_method = AXIS2_HTTP_METHOD_POST;
}
else if(axutil_strcasecmp(lpECB->lpszMethod, "GET") == 0)
{
request.request_method = AXIS2_HTTP_METHOD_GET;
}
else if(axutil_strcasecmp(lpECB->lpszMethod, "HEAD") == 0)
{
request.request_method = AXIS2_HTTP_METHOD_HEAD;
}
else if(axutil_strcasecmp(lpECB->lpszMethod, "PUT") == 0)
{
request.request_method = AXIS2_HTTP_METHOD_PUT;
}
else if(axutil_strcasecmp(lpECB->lpszMethod, "DELETE") == 0)
{
request.request_method = AXIS2_HTTP_METHOD_DELETE;
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "IIS: Unsupported HTTP Method.");
return AXIS2_FAILURE;
}
/* Set the URL prefix. axis2_request_url_prefix is a global variable set at the init time */
request.request_url_prefix = axis2_request_url_prefix;
/* Create the transport out info */
request.out_transport_info = axis2_iis_out_transport_info_create(env, lpECB);
/* Set the content type */
request.content_type = lpECB->lpszContentType;
/* Get accept headaer */
cbSize = INTERNET_MAX_PATH_LENGTH;
if(lpECB->GetServerVariable(lpECB->ConnID, "HTTP_Accept", accept_header, &cbSize))
{
request.accept_header = accept_header;
}
/* Get the accept langauge */
cbSize = INTERNET_MAX_PATH_LENGTH;
if(lpECB->GetServerVariable(lpECB->ConnID, "HTTP_Accept-Language", accept_language, &cbSize))
{
request.accept_language_header = accept_language;
}
cbSize = INTERNET_MAX_PATH_LENGTH;
if(lpECB->GetServerVariable(lpECB->ConnID, "HTTP_Accept-Charset", accept_charset, &cbSize))
{
request.accept_charset_header = accept_charset;
}
/* Now we have set everything. We can call process method to process the request */
if(axis2_http_transport_utils_process_request(env, conf_ctx, &request, &response)
== AXIS2_FAILURE)
{
return AXIS2_FAILURE;
}
/* Write the response */
if(response.response_data && response.response_data_length > 0)
{
axis2_char_t content_length_str[16] = { 0 };
axis2_bool_t is_out_headers_created = AXIS2_FALSE;
if(!response.output_headers)
{
response.output_headers = axutil_array_list_create(env, 2);
is_out_headers_created = AXIS2_TRUE;
}
sprintf(content_length_str, "%d", response.response_data_length);
if(!response.content_type)
{
content_type_header = axis2_http_header_create(env, "Content-Type",
axis2_iis_out_transport_get_content(request.out_transport_info));
}
else
{
content_type_header = axis2_http_header_create(env, "Content-Type",
response.content_type);
}
content_length_header = axis2_http_header_create(env, "Content-Length", content_length_str);
axutil_array_list_add(response.output_headers, env, content_length_header);
axutil_array_list_add(response.output_headers, env, content_type_header);
/* Write the headers */
start_response(env, lpECB, response.http_status_code, response.http_status_code_name,
response.output_headers);
/* Write the response body */
if(write_response(lpECB, response.response_data, response.response_data_length)
== AXIS2_FAILURE)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "IIS: Writing data to IIS");
return AXIS2_FAILURE;
}
if(is_out_headers_created)
{
if(content_length_header)
{
axis2_http_header_free(content_length_header, env);
}
if(content_type_header)
{
axis2_http_header_free(content_type_header, env);
}
axutil_array_list_free(response.output_headers, env);
}
}
else
{
/* If we don't have a body we should write the HTTP headers */
start_response(env, lpECB, response.http_status_code, response.http_status_code_name,
response.output_headers);
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "Response is NULL");
}
/* Do some cleaning */
axis2_http_transport_utils_transport_in_uninit(&request, env);
axis2_http_transport_utils_transport_out_uninit(&response, env);
return AXIS2_SUCCESS;
}
axis2_status_t
write_response(
LPEXTENSION_CONTROL_BLOCK lpECB,
const void *b,
unsigned int l)
{
if(lpECB && b)
{
if(l)
{
unsigned int written = 0;
char *buf = (char *)b;
/* If couldn't write the data at onece try again until all the data is written.*/
while(written < l)
{
DWORD try_to_write = l - written;
if(!lpECB-> WriteClient(lpECB->ConnID, buf + written, &try_to_write, 0))
{
return AXIS2_FAILURE;
}
written += try_to_write;
}
}
return AXIS2_SUCCESS;
}
return AXIS2_FAILURE;
}
axis2_status_t AXIS2_CALL
start_response(
const axutil_env_t *env,
LPEXTENSION_CONTROL_BLOCK lpECB,
int status,
const char *reason,
axutil_array_list_t *headers)
{
static char crlf[3] = { (char)13, (char)10, '\0' };
unsigned int num_of_headers = 0;
if(status < 100 || status > 1000)
{
return AXIS2_FAILURE;
}
if(lpECB)
{
size_t len_of_status;
char *status_str;
char *headers_str;
/*
* Create the status line
*/
if(reason)
{
status_str = (char *)_alloca((6 + strlen(reason)) * sizeof(char));
sprintf(status_str, "%d %s", status, reason);
len_of_status = strlen(status_str);
}
else
{
switch(status)
{
case 200:
status_str = reasons[0].status_code;
len_of_status = reasons[0].status_len;
break;
case 202:
status_str = reasons[1].status_code;
len_of_status = reasons[1].status_len;
break;
case 500:
status_str = reasons[2].status_code;
len_of_status = reasons[2].status_len;
break;
default:
status_str = reasons[0].status_code;
len_of_status = reasons[0].status_len;
break;
}
}
/*
* Create response headers string
*/
if(headers && (num_of_headers = axutil_array_list_size(headers, env)) > 0)
{
size_t i, len_of_headers;
axis2_http_header_t *header = NULL;
for(i = 0, len_of_headers = 0; i < num_of_headers; i++)
{
header = axutil_array_list_get(headers, env, (int)i);
len_of_headers += strlen(axis2_http_header_get_name(header, env));
len_of_headers += strlen(axis2_http_header_get_value(header, env));
len_of_headers += 4; /* extra for colon, space and crlf */
}
len_of_headers += 3; /* crlf and terminating null char */
headers_str = (char *)_alloca(len_of_headers * sizeof(char));
headers_str[0] = '\0';
for(i = 0; i < num_of_headers; i++)
{
header = axutil_array_list_get(headers, env, (int)i);
strcat(headers_str, axis2_http_header_get_name(header, env));
strcat(headers_str, ": ");
strcat(headers_str, axis2_http_header_get_value(header, env));
strcat(headers_str, "\r\n");
}
strcat(headers_str, "\r\n");
}
else
{
headers_str = crlf;
}
if(!lpECB-> ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, status_str,
(LPDWORD) & len_of_status, (LPDWORD)headers_str))
{
return AXIS2_FAILURE;
}
return AXIS2_SUCCESS;
}
return AXIS2_FAILURE;
}
axis2_status_t AXIS2_CALL
axis2_worker_get_original_url(
char url[],
char ret_url[])
{
extern axis2_char_t *axis2_location;
strcpy(ret_url, axis2_location);
strcat(ret_url, &url[25]);
return URI_MATCHED;
}
axis2_char_t * AXIS2_CALL
axis2_iis_worker_get_bytes(
const axutil_env_t * env,
axutil_stream_t * stream)
{
axutil_stream_t * tmp_stream = NULL;
int return_size = -1;
axis2_char_t * buffer = NULL;
axis2_bool_t loop_state = AXIS2_TRUE;
AXIS2_ENV_CHECK(env, NULL);
AXIS2_PARAM_CHECK(env->error, stream, NULL);
tmp_stream = axutil_stream_create_basic(env);
while(loop_state)
{
int read = 0;
int write = 0;
char buf[READ_SIZE];
read = axutil_stream_read(stream, env, buf, READ_SIZE);
if(read < 0)
{
break;
}
write = axutil_stream_write(tmp_stream, env, buf, read);
if(read < (READ_SIZE - 1))
{
break;
}
}
return_size = axutil_stream_get_len(tmp_stream, env);
if(return_size > 0)
{
buffer = (char *)AXIS2_MALLOC(env->allocator, sizeof(char) * (return_size + 2));
return_size = axutil_stream_read(tmp_stream, env, buffer, return_size + 1);
buffer[return_size + 1] = '\0';
}
axutil_stream_free(tmp_stream, env);
return buffer;
}
/** Read all HTTP headers.
*/
axutil_hash_t *
axis2_iis_worker_read_http_headers(
const axutil_env_t * env,
LPEXTENSION_CONTROL_BLOCK lpECB)
{
const char szHTTP_[] = "HTTP_";
char szBuffer[4096];
DWORD dwBufferSize = sizeof szBuffer;
axutil_hash_t *headers = NULL;
axis2_http_header_t* http_header = NULL;
BOOL bGet = lpECB->GetServerVariable(lpECB->ConnID, "ALL_HTTP", szBuffer, &dwBufferSize);
if(bGet)
{
/* Find lines, split key/data pair and write them as output */
LPTSTR pOpts = NULL;
LPTSTR pEnd = NULL;
LPTSTR pChar = NULL;
char szTmpBuf[512];
char szTmpName[256];
headers = axutil_hash_make(env);
szTmpBuf[0] = 0;
for(pChar = szBuffer; '\0' != *pChar;)
{
if(*pChar == '\r' || *pChar == '\n')
{
pChar++;
continue;
}
pOpts = strchr(pChar, ':');/* findseparator */
if(pOpts && *pOpts)
{
pEnd = pOpts;
while(*pEnd && *pEnd != '\r' && *pEnd != '\n')
{
pEnd++;
}
*pOpts = '\0'; /* split the strings */
*pEnd = '\0';
if(0 == strncmp(pChar, szHTTP_, strlen(szHTTP_)))
{
pChar += strlen(szHTTP_);
}
strcpy(szTmpName, pChar);
axutil_string_replace(szTmpName, '_', '-');
http_header = axis2_http_header_create(env, szTmpName, pOpts + 1);
axutil_hash_set(headers, axutil_strdup(env, szTmpName), AXIS2_HASH_KEY_STRING,
http_header);
pChar = pEnd + 1;
}
}
}
else
{
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
"axis2_iis_worker_read_http_headers: no http headers");
}
return headers;
}