blob: a8723089d8a9165b5e20d18a473743075e61ed09 [file] [log] [blame]
/* -*- 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 */
};