| /* -*- C++ -*- */ |
| /* |
| * Copyright 2003-2004 The Apache Software Foundation. |
| * |
| * Licensed 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 <apache1_3/httpd.h> |
| #include <apache1_3/http_config.h> |
| #include <apache1_3/http_core.h> |
| #include <apache1_3/http_log.h> |
| #include <apache1_3/http_protocol.h> |
| #include <apache1_3/http_main.h> |
| #include <axis/server/Packet.hpp> |
| #include <string.h> |
| #include <malloc.h> |
| |
| #define AXIS_URI_EXTENSION "/axis" |
| |
| /* Following is the character that should be used to separate the method name in |
| * the SOAPAction header value. Ex: "http://localhost:80/axis/Calculator#Add" |
| */ |
| #define SOAPACTION_METHODNAME_SEPARATOR "#" |
| |
| /* #define CHUNCKED_DATA_SUPPORTED */ |
| |
| #define xxx ap_log_rerror(APLOG_MARK,APLOG_ERR, globr,"logged here"); |
| #define yyy ap_log_rerror(APLOG_MARK, APLOG_ERR, globr,"logged here"); |
| |
| /* file: mod_axis.c */ |
| /* here's the content handler */ |
| |
| extern int process_request (Ax_soapstream* str); |
| /* extern int process(soapstream *);*/ |
| extern unsigned char chEBuf[1024]; |
| |
| //#define SIZEOFMODULEBUFFER 4096 |
| #define SIZEOFMODULEBUFFER 32 |
| |
| /* |
| * This method adds the http header to the Ax_soapstream. These headers will be |
| * dispatched later before sending the http body |
| */ |
| static void AXISCALL set_transport_information |
| (AXIS_TRANSPORT_INFORMATION_TYPE type, const char*value, |
| Ax_soapstream* stream) |
| { |
| const char* key = NULL; |
| switch (type) |
| { |
| case SOAPACTION_HEADER: /* needed only in the client side ? */ |
| break; |
| case SERVICE_URI: /* need to set ? */ |
| break; |
| case OPERATION_NAME: /* need to set ? */ |
| break; |
| case SOAP_MESSAGE_LENGTH: |
| key = "Content-Length"; /* This is apache module and transport is |
| * http so the key |
| */ |
| break; |
| default:; |
| } |
| if (key) |
| { |
| ap_table_set (((request_rec*) stream->str.op_stream)->headers_out, |
| key, value); |
| } |
| #ifdef CHUNCKED_DATA_SUPPORTED |
| ap_send_http_header ((request_rec*) hdr->str.op_stream); |
| /* Should we remove the sent headers ? Sanjaya ? */ |
| #endif |
| } |
| |
| /* Call initialize_module() [of Packet.h] from within this method */ |
| static void module_init (server_rec* svr_rec, pool* p) |
| { |
| initialize_module (1); |
| } |
| |
| /* |
| * If this module is not handling chunked data transfer, it accumulates all |
| * buffers before sending them so that the http header "Content-Length" can be |
| * sent before sending the http body |
| */ |
| |
| static AXIS_TRANSPORT_STATUS AXISCALL send_response_bytes (const char *buffer, |
| const void* bufferid, const void* pStream) |
| { |
| const Ax_soapstream* stream = (Ax_soapstream*) pStream; |
| #ifndef CHUNCKED_DATA_SUPPORTED |
| int index; |
| sendbuffers *pbuffers; |
| #endif |
| |
| if (!bufferid) /* temporary buffers should always sent immediately */ |
| { |
| ap_rputs (buffer, (request_rec*) (stream->str.op_stream)); |
| return TRANSPORT_FINISHED; |
| } |
| |
| #ifdef CHUNCKED_DATA_SUPPORTED |
| // Do we need to send any headers and length of this chunk ? Sanjaya ? |
| ap_rputs (buffer, (request_rec *) (stream->str.op_stream)); |
| /* Do we need to send any indication to mark the end of this |
| * chunk ? Sanjaya ? |
| */ |
| return TRANSPORT_FINISHED; |
| #else |
| pbuffers = (sendbuffers*) stream->reserved1; |
| for (index = 0; index < NO_OF_SERIALIZE_BUFFERS; index++) |
| { |
| if (!pbuffers[index].buffer) |
| { |
| pbuffers[index].buffer = buffer; |
| pbuffers[index].bufferid = bufferid; |
| break; |
| } |
| } |
| return TRANSPORT_IN_PROGRESS; |
| #endif |
| } |
| |
| /* Call initialize_process() [of Packet.h] from within this method */ |
| static void axis_Init (server_rec* svr_rec, pool* p) |
| { |
| } |
| |
| /*Call finalize_process() [of Packet.h] from within this method*/ |
| static void axis_Fini (server_rec* svr_rec, pool* p) |
| { |
| } |
| |
| /* |
| * This function is called by the Axis Engine whenever it needs to get bytes |
| * from the transport layer. |
| */ |
| static AXIS_TRANSPORT_STATUS AXISCALL get_request_bytes (const char **req, |
| int* retsize, const Ax_soapstream* stream) |
| { |
| #ifdef USE_XERCES_PARSER |
| int nBufSize = *retsize; |
| int len_read; |
| char* pBuffer = *req; |
| if (!(*req)) |
| return TRANSPORT_FAILED; |
| ap_hard_timeout ("util_read", (request_rec*) stream->str.ip_stream); |
| len_read = ap_get_client_block ((request_rec*) stream->str.ip_stream, *req, |
| nBufSize); |
| ap_reset_timeout ((request_rec*) stream->str.ip_stream); |
| *retsize = len_read; |
| if (len_read < nBufSize) |
| { |
| pBuffer[len_read] = '\0'; |
| return TRANSPORT_FINISHED; |
| } |
| else |
| return TRANSPORT_IN_PROGRESS; |
| #else |
| /*How can I detect an error when reading stream ? Sanjaya ? |
| * In case of an error set buffer to null, size 0 and |
| * return TRANSPORT_FAILED */ |
| int len_read; |
| char* pBuffer = stream->reserved2; |
| if (!pBuffer) |
| return TRANSPORT_FAILED; |
| ap_hard_timeout ("util_read", (request_rec*) stream->str.ip_stream); |
| len_read = ap_get_client_block ((request_rec*) stream->str.ip_stream, |
| pBuffer, SIZEOFMODULEBUFFER); |
| ap_reset_timeout ((request_rec*) stream->str.ip_stream); |
| *req = pBuffer; |
| *retsize = len_read; |
| if (len_read < SIZEOFMODULEBUFFER) |
| { |
| pBuffer[len_read] = '\0'; |
| return TRANSPORT_FINISHED; |
| } |
| else |
| return TRANSPORT_IN_PROGRESS; |
| #endif |
| } |
| |
| static void AXISCALL release_receive_buffer (const char* buffer, |
| const Ax_soapstream* stream) |
| { |
| |
| } |
| |
| static const char* AXISCALL get_transport_information |
| (AXIS_TRANSPORT_INFORMATION_TYPE type, Ax_soapstream* stream) |
| { |
| const char* ptemp; |
| switch (type) |
| { |
| case SOAPACTION_HEADER: |
| return get_property (stream, "SOAPAction"); |
| case SERVICE_URI: |
| if (strstr (stream->so.http->uri_path, AXIS_URI_EXTENSION)) |
| { |
| return strstr (stream->so.http->uri_path, AXIS_URI_EXTENSION) + |
| strlen (AXIS_URI_EXTENSION) + 1; |
| } |
| else |
| { |
| return stream->so.http->uri_path; |
| } |
| case OPERATION_NAME: |
| ptemp = get_property (stream, "SOAPAction"); |
| if (ptemp) |
| { |
| if (strstr (ptemp, SOAPACTION_METHODNAME_SEPARATOR)) |
| { |
| return strstr (ptemp, SOAPACTION_METHODNAME_SEPARATOR) + |
| strlen (SOAPACTION_METHODNAME_SEPARATOR); |
| } |
| else |
| { |
| return ptemp; |
| } |
| } |
| case SOAP_MESSAGE_LENGTH: |
| return get_property (stream, "Content-Length"); |
| /* this is apache module and transport is http so the key */ |
| default:; |
| } |
| return NULL; |
| } |
| |
| static int axis_handler (request_rec* req_rec) |
| { |
| int rc; |
| Ax_soapstream* sstr; |
| array_header* arr; |
| #ifndef CHUNCKED_DATA_SUPPORTED |
| int contentLength = 0; |
| int index; |
| sendbuffers* pbuffers; |
| char strtonum[8]; |
| #endif |
| sstr = malloc (sizeof (Ax_soapstream)); |
| /*populate Ax_soapstream struct with relevant transport function pointers */ |
| sstr->transport.pSendFunct = send_response_bytes; |
| sstr->transport.pGetFunct = get_request_bytes; |
| sstr->transport.pSetTrtFunct = set_transport_information; |
| sstr->transport.pGetTrtFunct = get_transport_information; |
| sstr->transport.pRelBufFunct = release_receive_buffer; |
| sstr->trtype = APTHTTP; |
| sstr->so.http = malloc (sizeof (Ax_stream_http)); |
| /* req_rec is used as both input and output streams */ |
| sstr->str.ip_stream = req_rec; |
| sstr->str.op_stream = req_rec; |
| /* just add some sessionid */ |
| sstr->sessionid = "this is temporary session id"; |
| #ifdef CHUNCKED_DATA_SUPPORTED |
| /* TODO */ |
| sstr->reserved1 = NULL; |
| sstr->reserved2 = NULL; |
| #else |
| sstr->reserved1 = calloc (NO_OF_SERIALIZE_BUFFERS, sizeof (sendbuffers)); |
| #ifdef USE_XERCES_PARSER |
| #else |
| sstr->reserved2 = malloc (SIZEOFMODULEBUFFER); |
| #endif |
| #endif |
| req_rec->content_type = "text/xml"; |
| /* for SOAP 1.2 this this should be "application/soap+xml" but keep this for |
| * the moment set up the read policy from the client. |
| */ |
| if ((rc = ap_setup_client_block (req_rec, REQUEST_CHUNKED_ERROR)) != OK) |
| { |
| if (sstr->reserved1) |
| free (sstr->reserved1); |
| #ifdef USE_XERCES_PARSER |
| #else |
| if (sstr->reserved2) |
| free (sstr->reserved2); |
| #endif |
| free (sstr->so.http); |
| free (sstr); |
| return rc; |
| } |
| |
| /* the member, "path" of "parsed_uri" contains the uri of the */ |
| /* request (i.e "/abc/xyz" part of http://somehost/abc/xyz) */ |
| sstr->so.http->uri_path = req_rec->parsed_uri.path; |
| |
| /* ap_table_elts returns an array_header struct. The nelts element of that |
| * struct contains the number of input header elements. Finally assigns that |
| * to the axis soap data structure. */ |
| sstr->so.http->ip_headercount = ap_table_elts (req_rec->headers_in)->nelts; |
| |
| /* casting req_rec->headers_in to axis header struct and assigning that to |
| * the axis soap structure. Hope this is ok |
| */ |
| |
| /* obtain the array_header from the headers_in table and assign it to the |
| * axis soap structure |
| */ |
| arr = ap_table_elts (req_rec->headers_in); |
| sstr->so.http->ip_headers = (Ax_header*) arr->elts; |
| |
| /*Determine the http method and assign it to the axis soap structure */ |
| switch (req_rec->method_number) |
| { |
| case M_GET: |
| sstr->so.http->ip_method = AXIS_HTTP_GET; |
| break; |
| case M_POST: |
| sstr->so.http->ip_method = AXIS_HTTP_POST; |
| break; |
| default: |
| sstr->so.http->ip_method = AXIS_HTTP_UNSUPPORTED; |
| } |
| |
| /* Tell the client that we are ready to receive content and check whether |
| * client will send content control will pass to this block only if there is |
| * body content in the request |
| */ |
| if (ap_should_client_block (req_rec)); |
| |
| if (0 != process_request (sstr)) |
| { |
| if (sstr->reserved1) |
| free (sstr->reserved1); |
| #ifdef USE_XERCES_PARSER |
| #else |
| if (sstr->reserved2) |
| free (sstr->reserved2); |
| #endif |
| free (sstr->so.http); |
| free (sstr); |
| return OK; |
| } |
| #ifdef CHUNCKED_DATA_SUPPORTED |
| /* headers have already been sent. see set_transport_information |
| * http body too have been sent |
| * Do we need to send any indication to mark end of chuncked |
| * data ? Sanjaya ? |
| */ |
| #else |
| /* Calculate Content-Length and set header */ |
| pbuffers = (sendbuffers*) sstr->reserved1; |
| for (index = 0; index < NO_OF_SERIALIZE_BUFFERS; index++) |
| { |
| if (!pbuffers[index].buffer) |
| break; |
| contentLength += strlen (pbuffers[index].buffer); |
| } |
| if (contentLength != 0) /* do only if the http body is not empty. */ |
| { |
| sprintf (strtonum, "%d", contentLength); |
| set_transport_information (SOAP_MESSAGE_LENGTH, strtonum, sstr); |
| ap_send_http_header (req_rec); |
| /* Send all buffers */ |
| pbuffers = (sendbuffers*) sstr->reserved1; |
| for (index = 0; index < NO_OF_SERIALIZE_BUFFERS; index++) |
| { |
| if (!pbuffers[index].buffer) |
| break; |
| ap_rputs (pbuffers[index].buffer, req_rec); |
| /* Let Axis know that the buffer is no longer in use */ |
| axis_buffer_release (pbuffers[index].buffer, |
| pbuffers[index].bufferid, sstr); |
| } |
| } |
| /* Free the array */ |
| if (sstr->reserved1) |
| free (sstr->reserved1); |
| #ifdef USE_XERCES_PARSER |
| #else |
| if (sstr->reserved2) |
| free (sstr->reserved2); |
| #endif |
| |
| #endif |
| free (sstr->so.http); |
| free (sstr); |
| /* free(arr); */ |
| return OK; |
| } |
| |
| /* Make the name of the content handler known to Apache */ |
| static handler_rec axis_handlers[] = { {"axis", axis_handler}, {NULL} }; |
| |
| /* Tell Apache what phases of the transaction we handle */ |
| module MODULE_VAR_EXPORT axis_module = { |
| STANDARD_MODULE_STUFF, |
| module_init, /* module initializer */ |
| NULL, /* per-directory config creator */ |
| NULL, /* dir config merger */ |
| NULL, /* server config creator */ |
| NULL, /* server config merger */ |
| NULL, /* command table */ |
| axis_handlers, /* [9] content handlers */ |
| NULL, /* [2] URI-to-filename translation */ |
| NULL, /* [5] check/validate user_id */ |
| NULL, /* [6] check user_id is valid *here* */ |
| NULL, /* [4] check access by host address */ |
| NULL, /* [7] MIME type checker/setter */ |
| NULL, /* [8] fixups */ |
| NULL, /* [10] logger */ |
| NULL, /* [3] header parser */ |
| axis_Init, /* process initialization */ |
| axis_Fini, /* process exit/cleanup */ |
| NULL /* [1] post read_request handling */ |
| }; |