/* * 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 #include #include #include #include #include #include #include "axis2_iis_out_transport_info.h" #include "axis2_iis_stream.h" #include "axis2_iis_worker.h" /* Files from iis */ #include #include #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; }