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