blob: 14ca4a959648fcf9c14e564c84b32c94a1952a97 [file]
#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/common/Packet.h>
#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 100
char g_buffer[SIZEOFMODULEBUFFER];
/**
* 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)
{
/*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;
ap_hard_timeout("util_read", (request_rec*)stream->str.ip_stream);
len_read = ap_get_client_block((request_rec*)stream->str.ip_stream, g_buffer, SIZEOFMODULEBUFFER);
ap_reset_timeout((request_rec*)stream->str.ip_stream);
*req = g_buffer;
*retsize = len_read;
if (len_read < SIZEOFMODULEBUFFER)
{
g_buffer[len_read] = '\0';
return TRANSPORT_FINISHED;
}
else
return TRANSPORT_IN_PROGRESS;
}
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
sstr->reserved1 = NULL;
sstr->reserved2 = NULL;
#else
sstr->reserved1 = calloc(NO_OF_SERIALIZE_BUFFERS, sizeof(sendbuffers));
sstr->reserved2 = NULL;
#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)
{
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))
{
/*ap_rputs("SOAP Engine failed to response",req_rec);*/
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);
#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 */
};