blob: 326b3c0bc2b82cf19af2114a2fa329efe3166284 [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
// (c) Copyright IBM Corp. 2004, 2005 All Rights Reserved
*
* 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.
*/
/*
* @author Samisa Abeysinghe (sabeysinghe@virtusa.com)
*
*/
#ifdef WIN32
#pragma warning (disable : 4786)
#pragma warning (disable : 4101)
#endif
#include "Axis2Transport.h"
#include <stdio.h>
#include <iostream>
/*
* Axis2Transport constuctor
*/
Axis2Transport::Axis2Transport ():m_bReopenConnection (false),
m_strHTTPProtocol ("HTTP/1.1"),
m_strHTTPMethod ("POST"),
m_bChunked (false),
m_bReadPastHTTPHeaders (false),
m_strProxyHost (""), m_uiProxyPort (0), m_bUseProxy (false),
m_bMaintainSession (false)
{
m_pcEndpointUri = NULL;
m_pReleaseBufferCallback = 0;
m_eProtocolType = APTHTTP1_1;
m_strBytesToSend = "";
m_strHeaderBytesToSend = "";
m_iBytesLeft = 0;
m_iContentLength = 0;
m_pcReceived = 0;
m_pChannel = new Channel ();
m_pFactory = new ChannelFactory ();
m_bChannelSecure = false;
m_bMimeTrue = false;
m_viCurrentHeader = m_vHTTPHeaders.begin ();
}
/*
* Axis2Transport destuctor
*/
Axis2Transport::~Axis2Transport ()
{
if (m_pcEndpointUri)
{
delete[]m_pcEndpointUri;
}
if (m_pChannel)
delete m_pChannel;
if (m_pFactory)
delete m_pFactory;
}
/*
* Axis2Transport::setEndpointUri( EndpointURI) sets the URI for the message.
* Everytime the endpoint changes then currently connected channel is closed
* and a new channel connection is opened.
*
* @param EndpointURI - char * to a null terminated string that holds the
* new URI.
*/
void
Axis2Transport::setEndpointUri (const char *pcEndpointUri)
throw (AxisTransportException)
{
bool bUpdateURL = false;
// Get the current channel URI
if (m_pChannel->getURL ())
{
// Does the new URI equal the existing channel URI?
if (strcmp (m_pChannel->getURL (), pcEndpointUri) != 0)
{
// There is a new URI.
bUpdateURL = true;
}
}
else
{
bUpdateURL = true;
}
// If there is a new URI, then this flag will be set. Depending on whether
// GSKit is available, if the new URI is a secure connection, a secure
// channel will be opened. If GSKit is not available and the URL requires
// a secure connection then an exeption will be thrown.
if (bUpdateURL)
{
m_pChannel->setURL (pcEndpointUri);
m_bReopenConnection = true;
// Check if the new URI requires SSL (denoted by the https prefix).
if ((m_pChannel->getURLObject ()).getProtocol () == URL::https)
{
m_bChannelSecure = false;
// URI requires a secure channel. Delete the existing channel
// (as it may not be secure) and create a new secure channel.
delete m_pChannel;
//m_pChannel = (Channel *) new SecureChannel ();
m_pChannel = m_pFactory->getSecureChannelObject ();
m_pChannel->setURL (pcEndpointUri);
m_bChannelSecure = true;
if (!m_bChannelSecure)
{
throw
AxisTransportException
(CLIENT_TRANSPORT_HAS_NO_SECURE_TRANSPORT_LAYER);
}
}
else
{
// URI does not require a secure channel. Delete the existing
// channel if it is secure and create a new unsecure
// channel.
if (m_bChannelSecure)
{
delete m_pChannel;
m_pChannel = new Channel ();
m_pChannel->setURL (pcEndpointUri);
m_bChannelSecure = false;
}
}
}
}
/*
* Axis2Transport::openConnection().
*/
int
Axis2Transport::openConnection ()
{
//Samisa: I wonder whether this should be a SOAPTransport API call.
//It should not be the job of the upper layers to tell the transport
//to open and close connections. Rather the transport should determine
//when to do that, when sendBytes is called.
return AXIS_SUCCESS;
}
/*
* Axis2Transport::closeConnection().
*/
void
Axis2Transport::closeConnection ()
{
// get ready for a new message.
m_bReadPastHTTPHeaders = false;
//clear the message buffer in preperation of the next read.
m_strReceived = "";
m_iContentLength = 0;
}
/*
* Axis2Transport::flushOutput() Is called when the message construction is
* complete. The message is ready to be 'flushed out' onto the network.
* Check if the URI has changed. If it has, then need to open a new Channel
* instance before transmitting the message.
*
* @return AXIS_TRANSPORT_STATUS If the method completes successfully, then
* this will be set to TRANSPORT_FINISHED. Otherwise, an exception will have
* been thrown.
*/
AXIS_TRANSPORT_STATUS
Axis2Transport::flushOutput ()throw (AxisTransportException)
{
if (m_bReopenConnection)
{
m_bReopenConnection = false;
if (!m_pChannel->open ())
{
int iStringLength = m_pChannel->GetLastErrorMsg ().length () + 1;
const char *pszLastError = new char[iStringLength];
memcpy ((void *) pszLastError,
m_pChannel->GetLastErrorMsg ().c_str (), iStringLength);
;
throw
AxisTransportException
(CLIENT_TRANSPORT_OPEN_CONNECTION_FAILED,
(char *) pszLastError);
}
}
// In preperation for sending the message, calculate the size of the message
// by using the string length method.
// NB: This calculation may not necessarily be correct when dealing with SSL
// messages as the length of the encoded message is not necessarily the
// same as the length of the uncoded message.
char buff[8];
sprintf (buff, "%d", m_strBytesToSend.length ());
this->setTransportProperty ("Content-Length", buff);
// The header is now complete. The message header and message can now be
// transmitted.
try
{
*m_pChannel << this->getHTTPHeaders ();
*m_pChannel << this->m_strBytesToSend.c_str ();
}
catch (AxisTransportException & e)
{
throw;
}
catch (AxisException & e)
{
throw;
}
catch (...)
{
throw;
}
// Empty the bytes to send string.
m_strBytesToSend = "";
m_strHeaderBytesToSend = "";
return TRANSPORT_FINISHED;
}
/* Axis2Transport::getHTTPHeaders() Called to retreive the current HTTP header
* information block that will preceed the SOAP message.
*
* @return const char* Pointer to a NULL terminated character string containing
* the HTTP header block of information.
*/
const char *
Axis2Transport::getHTTPHeaders ()
{
URL & url = m_pChannel->getURLObject ();
m_strHeaderBytesToSend = m_strHTTPMethod + " ";
if (m_bUseProxy)
m_strHeaderBytesToSend += std::string (url.getURL ()) + " ";
else
m_strHeaderBytesToSend += std::string (url.getResource ()) + " ";
m_strHeaderBytesToSend += m_strHTTPProtocol + "\r\n";
if (m_bUseProxy)
m_strHeaderBytesToSend += std::string ("Host: ") + m_strProxyHost;
else
m_strHeaderBytesToSend += std::string ("Host: ") + url.getHostName ();
unsigned short uiPort = url.getPort ();
if (m_bUseProxy)
uiPort = m_uiProxyPort;
char buff[8];
sprintf (buff, "%u", uiPort);
m_strHeaderBytesToSend += ":";
m_strHeaderBytesToSend += buff;
m_strHeaderBytesToSend += "\r\n";
m_strHeaderBytesToSend += "Content-Type: text/xml; charset=UTF-8\r\n";
// Set other HTTP headers
for (unsigned int i = 0; i < m_vHTTPHeaders.size (); i++)
{
m_strHeaderBytesToSend += m_vHTTPHeaders[i].first;
m_strHeaderBytesToSend += ": ";
m_strHeaderBytesToSend += m_vHTTPHeaders[i].second;
m_strHeaderBytesToSend += "\r\n";
}
// Set session cookie
if (m_bMaintainSession && (m_strSessionKey.size () > 0))
{
m_strHeaderBytesToSend += "Cookie";
m_strHeaderBytesToSend += ": ";
m_strHeaderBytesToSend += m_strSessionKey;
m_strHeaderBytesToSend += "\r\n";
}
m_strHeaderBytesToSend += "\r\n";
return m_strHeaderBytesToSend.c_str ();
}
/* Axis2Transport::getHTTPMethod() Is a public method that gets the HTTP method
* (i.e. GET or POST) that will be part of the HTTP header block.
*
* @return const char* Pointer to a NULL terminated character string containing
* the HTTP method.
*/
const char *
Axis2Transport::getHTTPMethod ()
{
return m_strHTTPMethod.c_str ();
}
/* Axis2Transport::setHTTPMethod( Method) Is a public method that sets the HTTP
* method (i.e. POST or GET) that will be part of the HTTP header block.
*
* @param const char* Pointer to a NULL terminated character string containing
* the new HTTP method.
*/
void
Axis2Transport::setHTTPMethod (const char *cpMethod)
{
m_strHTTPMethod = std::string (cpMethod);
}
/* Axis2Transport::sendBytes( SendBuffer, BufferId) Is a public method that
* concatinates the new send buffer to the bytes to send string. This message
* will only be sent when a flush buffer is received.
*
* @param const char* SendBufer - Pointer to a NULL terminated character string
* containing all or some of the transmission message.
* @param const void* BufferId - Pointer. This parameter is ignored.
*
* @return AXIS_TRANSPORT_STATUS Value to a status value (currently it will
* always be TRANSPORT_IN_PROGRESS).
*/
AXIS_TRANSPORT_STATUS
Axis2Transport::sendBytes (const char *pcSendBuffer,
const void *pBufferId)
{
m_strBytesToSend += std::string (pcSendBuffer);
return TRANSPORT_IN_PROGRESS;
}
/* Axis2Transport::getBytes( ReceiveBuffer, Size) Is a public method that will
* receive the synchronous reply to the sent message.
*
* @param const char* ReceiveBuffer - Pointer to a character string that on
* return will containing all or part of the received message.
* @param int* Size - Pointer to an integer value that on return will contain
* the length of the received message.
*
* @return AXIS_TRANSPORT_STATUS Value to the status o message reception
* (TRANSPORT_FINISHED or TRANSPORT_IN_PROGRESS).
*/
AXIS_TRANSPORT_STATUS
Axis2Transport::getBytes (char *pcBuffer, int *pSize)
throw (AxisException, AxisTransportException)
{
if (0 <= m_iBytesLeft)
{
try
{
*m_pChannel >> m_strReceived;
if (!m_bReadPastHTTPHeaders)
{
unsigned int start = std::string::npos;
do
{
do
{
if (m_strReceived.find ("\r\n\r\n") ==
std::string::npos)
{
std::string strTempReceived = "";
*m_pChannel >> strTempReceived; // Assume non blocking here
m_strReceived += strTempReceived;
}
}
while (m_strReceived.find ("\r\n\r\n") ==
std::string::npos);
if (m_strReceived.find ("HTTP") == std::string::npos)
{
// Most probably what we read was left overs from earlier reads
// Skip this \r\n\r\n
m_strReceived =
m_strReceived.substr (m_strReceived.
find ("\r\n\r\n") + 4);
do
{
if (m_strReceived.find ("\r\n\r\n") ==
std::string::npos)
{
std::string strTempReceived = "";
*m_pChannel >> strTempReceived; // Assume non blocking here
m_strReceived += strTempReceived;
}
}
while (m_strReceived.find ("\r\n\r\n") ==
std::string::npos);
// now this must contain HTTP. Else there is a conent error.
}
//now we have found the end of headers
m_bReadPastHTTPHeaders = true;
unsigned int pos = 0;
// Look for content lenght
if ((pos =
m_strReceived.find ("Content-Length: ")) !=
std::string::npos)
{
m_iContentLength =
atoi (m_strReceived.
substr (pos + strlen ("Content-Length: "),
m_strReceived.find ("\n",
pos)).c_str ());
}
// Check if the message is chunked
if ((pos =
m_strReceived.find ("Transfer-Encoding: chunked")) !=
std::string::npos)
{
m_bChunked = true;
}
else
{
m_bChunked = false;
}
// check if there is HTTP header. If not, there must be an error and
// will be detected by processResponseHTTPHeaders()
// However, must make sure that the left overs from eatlier reads
// do not appear before HTTP/1.x
start = m_strReceived.find ("HTTP");
if (start == std::string::npos)
start = 0;
// Extract HTTP headers and process them
m_strResponseHTTPHeaders = m_strReceived.substr (start,
m_strReceived.
find
("\r\n\r\n")
+ 2 -
start);
processResponseHTTPHeaders ();
if (m_iResponseHTTPStatusCode == 100)
{
// Samisa: We found Continue. Keep on reading and processing headers
// till we get a HTTP code other than 100
// Here it is assumed that the whole of the request is already sent
*m_pChannel >> m_strReceived;
}
}
while (m_iResponseHTTPStatusCode == 100);
if ( m_iResponseHTTPStatusCode != 500 &&
( m_iResponseHTTPStatusCode < 200 || m_iResponseHTTPStatusCode >= 300 ))
{
throw
AxisTransportException
(SERVER_TRANSPORT_HTTP_EXCEPTION,
const_cast <
char *>(m_strResponseHTTPStatusMessage.c_str ()));
}
// Done with HTTP headers, get payload
m_strReceived =
m_strReceived.substr (m_strReceived.
find ("\r\n\r\n", start) + 4);
}
// Read past headers. Deal with payload
// make sure we have a message with some content
if (m_strReceived.length () == 0)
{
*m_pChannel >> m_strReceived;
}
if (m_bChunked && m_iContentLength < 1) // Read first chunk
{
/*
*Chunked data looks like ->
* Chunked-Body = *chunk
* "0" CRLF
* footer
* CRLF
*
* chunk = chunk-size [ chunk-ext ] CRLF
* chunk-data CRLF
*
* hex-no-zero = <HEX excluding "0">
*
* chunk-size = hex-no-zero *HEX
* chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-value ] )
* chunk-ext-name = token
* chunk-ext-val = token | quoted-string
* chunk-data = chunk-size(OCTET)
*
* footer = *entity-header
*/
// firstly read in the chunk size line.
//There might be chunk extensions in there too but we may not need them
unsigned int endOfChunkData = m_strReceived.find ("\r\n");
// make sure we have read at least some part of the message
if (endOfChunkData == std::string::npos)
{
do
{
*m_pChannel >> m_strReceived;
endOfChunkData = m_strReceived.find ("\r\n");
}
while (endOfChunkData == std::string::npos);
}
int endOfChunkSize = endOfChunkData;
// now get the size of the chunk from the data
// look to see if there are any extensions - these are put in brackets so look for those
if (m_strReceived.substr (0, endOfChunkData).find ("(") !=
string::npos)
{
endOfChunkSize = m_strReceived.find ("(");
}
// convert the hex String into the length of the chunk
m_iContentLength = axtoi ((char *) m_strReceived.substr (0,
endOfChunkSize).
c_str ());
// if the chunk size is zero then we have reached the footer
// If we have reached the footer then we can throw it away because we don't need it
if (m_iContentLength > 0)
{
// now get the chunk without the CRLF
// check if we have read past chunk length
if (m_strReceived.length () >=
(endOfChunkData + 2 + m_iContentLength))
{
m_strReceived =
m_strReceived.substr (endOfChunkData + 2,
m_iContentLength);
}
else // we have read lesser than chunk length
{
m_strReceived =
m_strReceived.substr (endOfChunkData + 2);
}
/* We have received part of chunk data. If received payload
* is a mime struct, process it
*/
if (m_bMimeTrue)
processRootMimeBody ();
}
else
{
m_strReceived = "";
}
}
else if (m_bChunked) // read continued portions of a chunk
{
// Samisa - NOTE: It looks as if there is some logic duplication
// in this block, where we read continued chunks and the block
// above, where we read the first chunk. However, there are slight
// logical differences here, and that is necessary to enable the
// pull model used by the parser - this logic makes pulling more
// efficient (30th Sept 2004)
if (m_strReceived.length () >= m_iContentLength) // We have reached end of current chunk
{
// Get remainder of current chunk
std::string strTemp =
m_strReceived.substr (0, m_iContentLength);
// Start looking for the next chunk
// The format we are expecting here is:
// <previous chunk>\r\n<chunk size>\r\n<next chunk>
unsigned int endOfChunkData = m_strReceived.find ("\r\n");
// Make sure that we have the found the end of previous chunk
while (endOfChunkData == std::string::npos)
{
std::string strTempRecv = "";
*m_pChannel >> strTempRecv;
m_strReceived += strTempRecv;
endOfChunkData = m_strReceived.find ("\r\n");
}
m_strReceived = m_strReceived.substr (endOfChunkData + 2); // Skip end of previous chunk
endOfChunkData = m_strReceived.find ("\r\n"); // Locate the start of next chunk
// Make sure that we have the starting line of next chunk
while (endOfChunkData == std::string::npos)
{
std::string strTempRecv = "";
*m_pChannel >> strTempRecv;
m_strReceived += strTempRecv;
endOfChunkData = m_strReceived.find ("\r\n");
}
int endOfChunkSize = endOfChunkData;
// look to see if there are any extensions - these are put in brackets so look for those
if (m_strReceived.substr (0, endOfChunkData).find ("(") !=
string::npos)
{
endOfChunkSize = m_strReceived.find ("(");
}
// convert the hex String into the length of the chunk
int iTempContentLength =
axtoi ((char *) m_strReceived.substr (0,
endOfChunkSize).
c_str ());
// if the chunk size is zero then we have reached the footer
// If we have reached the footer then we can throw it away because we don't need it
if (iTempContentLength > 0)
{
// Update the content lenght to be remainde of previous chunk and lenght of new chunk
m_iContentLength += iTempContentLength;
// now get the chunk without the CRLF
// check if we have read past chunk length
if (m_strReceived.length () >=
(endOfChunkData + 2 + iTempContentLength))
{
m_strReceived =
m_strReceived.substr (endOfChunkData + 2,
iTempContentLength);
}
else
{
m_strReceived =
m_strReceived.substr (endOfChunkData + 2);
}
/* We have received part of chunk data. If received payload
* is a mime struct, process it
*/
if (m_bMimeTrue)
processRootMimeBody ();
}
else
{
m_strReceived = "";
}
// Append the data of new chunk to data from previous chunk
m_strReceived = strTemp + m_strReceived;
} // End of if (m_strReceived.length() >= m_iContentLength)
// If we have not reached end of current chunk, nothing to be done
}
else // Not chunked
{
//nothing to do here
/* We have received part of chunk data. If received payload
* is a mime struct, process it
*/
if (m_bMimeTrue)
processRootMimeBody ();
}
m_pcReceived = m_strReceived.c_str ();
if (m_pcReceived)
{
m_iBytesLeft = strlen (m_pcReceived);
}
else
{
throw AxisTransportException (SERVER_TRANSPORT_BUFFER_EMPTY,
"Reveved null");
}
m_iContentLength -= m_iBytesLeft;
}
catch (AxisTransportException & e)
{
throw;
}
catch (AxisException & e)
{
throw;
}
catch (...)
{
throw;
}
}
if (m_pcReceived)
{
int iToCopy = (*pSize < m_iBytesLeft) ? *pSize : m_iBytesLeft;
strncpy (pcBuffer, m_pcReceived, iToCopy);
m_iBytesLeft -= iToCopy;
m_pcReceived += iToCopy;
*pSize = iToCopy;
return TRANSPORT_IN_PROGRESS;
}
else
{
m_bReadPastHTTPHeaders = false; // get ready for a new message
m_strReceived = ""; //clear the message buffer in preperation of the next read
return TRANSPORT_FINISHED;
}
}
/* Axis2Transport::setTransportProperty( Type, Value) Is an overloaded public
* method used to set a HTTP transport or GSKit property.
*
* @param AXIS_TRANSPORT_INFORMATION_TYPE Type is an enumerated type containing
* the type of information to be stored in either the HTTP Header or GSKit
* settings.
* @param const char* Value is a NULL terminated character string containing
* the value associated with the type.
*/
int
Axis2Transport::setTransportProperty (AXIS_TRANSPORT_INFORMATION_TYPE type,
const char *value)
throw (AxisTransportException)
{
const char *key = NULL;
switch (type)
{
case SOAPACTION_HEADER:
{
key = "SOAPAction";
break;
}
case SERVICE_URI: // need to set ?
{
break;
}
case OPERATION_NAME: // need to set ?
{
break;
}
case SOAP_MESSAGE_LENGTH:
{
key = "Content-Length"; // this Axis transport handles only HTTP
break;
}
case SECURE_PROPERTIES:
{
if (m_bChannelSecure)
{
((SecureChannel *) m_pChannel)->setSecureProperties (value);
}
break;
}
case DLL_NAME:
{
if (m_bChannelSecure)
{
//((SecureChannel *) m_pChannel)->setTransportProperty (type, value);
m_pFactory->initialize (value);
}
break;
}
default:
{
break;
}
}
if (key)
{
setTransportProperty (key, value);
}
return 0;
}
/* Axis2Transport::setTransportProperty( Key, Value) Is an overloaded public
* method used to set a HTTP transport or GSKit property.
*
* @param const char* Key is a NULL terminated character string containing
* the type of information to be stored in either the HTTP Header or GSKit
* settings.
* @param const char* Value is a NULL terminated character string containing
* the value associated with the type.
*/
int
Axis2Transport::setTransportProperty (const char *pcKey, const char *pcValue)
throw (AxisTransportException)
{
if (!pcKey || !pcValue) // Samisa - fix for AXISCPP-295. We must check for valid values here.
return 0;
bool b_KeyFound = false;
if (strcmp (pcKey, "SOAPAction") == 0
|| strcmp (pcKey, "Content-Length") == 0)
{
std::string strKeyToFind = std::string (pcKey);
for (unsigned int i = 0; i < m_vHTTPHeaders.size (); i++)
{
if (m_vHTTPHeaders[i].first == strKeyToFind)
{
m_vHTTPHeaders[i].second = (string) pcValue;
b_KeyFound = true;
break;
}
}
}
if (!b_KeyFound)
{
m_vHTTPHeaders.
push_back (std::make_pair ((string) pcKey, (string) pcValue));
}
return 0;
}
/* Axis2Transport::getTransportProperty( Type) Is a public method that will
* return the HTTP Header/GSKit value associated with type.
*
* @param AXIS_TRANSPORT_INFORMATION_TYPE Type is an enumerated type containing
* the type of information to be retrieved in either the HTTP Header or GSKit
* settings.
*
* @return const char* Value is a NULL terminated character string containing
* the value associated with the type.
*/
const char *
Axis2Transport::getTransportProperty (AXIS_TRANSPORT_INFORMATION_TYPE eType)
throw (AxisTransportException)
{
const char *pszPropValue = NULL;
switch (eType)
{
case SOAPACTION_HEADER:
{
int iIndex = FindTransportPropertyIndex ("SOAPAction");
if (iIndex > -1)
{
pszPropValue = m_vHTTPHeaders[iIndex].second.c_str ();
}
break;
}
case SERVICE_URI:
break;
case OPERATION_NAME:
break;
case SOAP_MESSAGE_LENGTH:
{
int iIndex = FindTransportPropertyIndex ("Content-Length");
if (iIndex > -1)
{
pszPropValue = m_vHTTPHeaders[iIndex].second.c_str ();
}
break;
}
case SECURE_PROPERTIES:
{
if (m_bChannelSecure)
{
pszPropValue =
((SecureChannel *) m_pChannel)->getSecureProperties ();
}
break;
}
}
return pszPropValue;
}
/* Axis2Transport::FindTransportPropertyIndex( Key) Is a private method that will
* return the HTTP Header index associated with Key.
*
* @param AXIS_TRANSPORT_INFORMATION_TYPE Key is an enumerated type containing
* the type of information to be retrieved in either the HTTP Header settings.
*
* @return int Index is an index to the key within the HTTP Header list. If
* the return value is -1, then the key was not found.
*/
int
Axis2Transport::FindTransportPropertyIndex (string sKey)
{
bool bKeyFound = false;
int iIndex = 0;
do
{
if (!m_vHTTPHeaders[iIndex].first.compare (sKey))
{
bKeyFound = true;
}
else
{
iIndex++;
}
}
while ((unsigned int) iIndex < m_vHTTPHeaders.size () && !bKeyFound);
if (!bKeyFound)
{
iIndex = -1;
}
return iIndex;
}
/* Axis2Transport::getServiceName() Is a public method to return the HTTP
* Header service name.
*
* @return const char* Value is a NULL terminated character string containing
* the value associated with the service name.
*/
const char *
Axis2Transport::getServiceName ()
{
//Assume SOAPAction header to contain service name
int iIndex = FindTransportPropertyIndex ("SOAPAction");
if (iIndex > -1)
{
return m_vHTTPHeaders[iIndex].second.c_str ();
}
return NULL;
}
/* Axis2Transport::getProtocol() Is a public method to return the HTTP protocol
* type.
*
* @return AXIS_PROTOCOL_TYPE Type is an enumerated type for valid HTTP
* protocols (currently this method will always return APTHTTP1_1).
*/
AXIS_PROTOCOL_TYPE Axis2Transport::getProtocol ()
{
return m_eProtocolType;
}
int
Axis2Transport::setProtocol (AXIS_PROTOCOL_TYPE eProtocol)
{
if (eProtocol == APTHTTP1_1 || eProtocol == APTHTTP1_0)
{
m_eProtocolType = eProtocol;
m_strHTTPProtocol =
(m_eProtocolType == APTHTTP1_1) ? "HTTP/1.1" : "HTTP/1.0";
return AXIS_SUCCESS;
}
else
return AXIS_FAIL;
}
/**
* Axis2Transport::getSubProtocol() is a public method that is supposed to
* return the sub protocol (currently this method always return 0).
* This method is supposed to return whether it is http GET or POST
*/
int
Axis2Transport::getSubProtocol ()
{
//TODO
// for SimpleAxisServer assume POST
return AXIS_HTTP_POST;
//return 0;
}
/* Axis2Transport::setProxy( Host, Port) Is a public method for setting or
* updating the proxy for the connection.
*
* @param const char* Host is a NULL terminated character string containing the new
* proxy host.
* @param unsigned int Port is the new proxy port number.
*/
void
Axis2Transport::setProxy (const char *pcProxyHost, unsigned int uiProxyPort)
{
m_pChannel->setProxy(pcProxyHost, uiProxyPort);
m_strProxyHost = pcProxyHost;
m_uiProxyPort = uiProxyPort;
m_bUseProxy = true;
}
/* Axis2Transport::setTimeout( Timeout) Is a public method for setting the
* current maximum timeout period between that can elapse between receiving
* message parts.
*
* @param const long Timeout is a long value in seconds.
*/
void
Axis2Transport::setTimeout (const long lSeconds)
{
m_pChannel->setTimeout (lSeconds);
}
/* Axis2Transport::getHTTPProtocol() Is a public method for retrieving the
* current HTTP protocol settings.
*
* @return const char* HTTPProtocol is a NULL terminated character string
* containing the HTTP protocol.
*/
const char *
Axis2Transport::getHTTPProtocol ()
{
return m_strHTTPProtocol.c_str ();
}
/* axtoi( Hex) Is a private method to convert an ascii hex string to an integer.
*/
int
axtoi (char *hexStg)
{
int n = 0; // position in string
int m = 0; // position in digit[] to shift
int count; // loop index
int intValue = 0; // integer value of hex string
int digit[32]; // hold values to convert
while (n < 32)
{
if (hexStg[n] == '\0')
break;
if (hexStg[n] > 0x29 && hexStg[n] < 0x40) //if 0 to 9
digit[n] = hexStg[n] & 0x0f; //convert to int
else if (hexStg[n] >= 'a' && hexStg[n] <= 'f') //if a to f
digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
else if (hexStg[n] >= 'A' && hexStg[n] <= 'F') //if A to F
digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
else
break;
n++;
}
count = n;
m = n - 1;
n = 0;
while (n < count)
{
// digit[n] is value of hex digit at position n
// (m << 2) is the number of positions to shift
// OR the bits into return value
intValue = intValue | (digit[n] << (m << 2));
m--; // adjust the position to set
n++; // next digit to process
}
return (intValue);
}
/* Axis2Transport::processResponseHTTPHeaders() Is a public method used to
* parse the HTTP header of the response message.
*/
void
Axis2Transport::processResponseHTTPHeaders ()
{
unsigned int iPosition = std::string::npos;
unsigned int iStartPosition = iPosition;
if ((iPosition =
m_strResponseHTTPHeaders.find ("HTTP")) != std::string::npos)
{
m_strResponseHTTPProtocol =
m_strResponseHTTPHeaders.substr (iPosition, strlen ("HTTP/1.x"));
iPosition += strlen ("HTTP/1.x");
while (m_strResponseHTTPHeaders.substr ()[iPosition] == ' ')
{
iPosition++;
}
iStartPosition = iPosition;
while (m_strResponseHTTPHeaders.substr ()[iPosition] != ' ')
{
iPosition++;
}
std::string strResponseHTTPStatusCode =
m_strResponseHTTPHeaders.substr (iStartPosition,
iPosition - iStartPosition);
m_iResponseHTTPStatusCode = atoi (strResponseHTTPStatusCode.c_str ());
iStartPosition = ++iPosition;
iPosition = m_strResponseHTTPHeaders.find ("\n");
m_strResponseHTTPStatusMessage =
m_strResponseHTTPHeaders.substr (iStartPosition,
iPosition - iStartPosition - 1);
// reached the end of the first line
iStartPosition = m_strResponseHTTPHeaders.find ("\n");
iStartPosition++;
// read header fields and add to vector
do
{
m_strResponseHTTPHeaders =
m_strResponseHTTPHeaders.substr (iStartPosition);
iPosition = m_strResponseHTTPHeaders.find ("\n");
if (iPosition == std::string::npos)
{
break;
}
std::string strHeaderLine =
m_strResponseHTTPHeaders.substr (0, iPosition);
unsigned int iSeperator = strHeaderLine.find (":");
if (iSeperator == std::string::npos)
{
break;
}
iStartPosition = iPosition + 1;
string key = strHeaderLine.substr (0, iSeperator);
string value = strHeaderLine.substr (iSeperator + 1,
strHeaderLine.
length () -
iSeperator - 1 - 1);
m_vResponseHTTPHeaders.push_back (std::make_pair (key, value));
// if HTTP/1.0 we have to always close the connection by default
if (m_eProtocolType == APTHTTP1_0)
m_bReopenConnection = true;
// if HTTP/1.1 we have to assume persistant connection by default
// We need to close the connection and open a new one if we have 'Connection: close'
if (key == "Connection" && value == " close")
m_bReopenConnection = true;
// We need to close the connection and open a new one if we have 'Proxy-Connection: close'
if (key == "Proxy-Connection" && value == " close")
m_bReopenConnection = true;
// For both HTTP/1.0 and HTTP/1.1,
// We need to keep the connection if we have 'Connection: Keep-Alive'
if (key == "Connection" && value == " Keep-Alive")
m_bReopenConnection = false;
// Look for cookies
if (m_bMaintainSession && !(m_strSessionKey.size () > 0))
{
if (key == "Set-Cookie")
{
m_strSessionKey = value;
// Spec syntax : Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
// This code assumes it to be : Set-Cookie: NAME=VALUE; Anything_else
// And discards stuff after first ';'
// This is the same assumption used in Axis Java
unsigned long ulKeyEndsAt = m_strSessionKey.find (";");
if (ulKeyEndsAt != std::string::npos)
{
m_strSessionKey =
m_strSessionKey.substr (0, ulKeyEndsAt);
}
}
}
/* If Content-Type: Multipart/Related; boundary=<MIME_boundary>; type=text/xml;
start="<content id>" */
if (key == "Content-Type")
{
m_strContentType = value;
unsigned long ulMimePos = m_strContentType.find (";");
std::string strTypePart;
if (ulMimePos != std::string::npos)
{
strTypePart = m_strContentType.substr (1, ulMimePos - 1);
}
if ("Multipart/Related" == strTypePart)
{
m_bMimeTrue = true;
m_strContentType = m_strContentType.substr (ulMimePos + 1,
m_strContentType.
length ());
ulMimePos = m_strContentType.find ("boundary=");
m_strMimeBoundary = m_strContentType.substr (ulMimePos);
ulMimePos = m_strMimeBoundary.find (";");
m_strMimeBoundary =
m_strMimeBoundary.substr (9, ulMimePos - 9);
ulMimePos = m_strContentType.find ("type=");
m_strMimeType = m_strContentType.substr (ulMimePos);
ulMimePos = m_strMimeType.find (";");
m_strMimeType = m_strMimeType.substr (5, ulMimePos - 5);
ulMimePos = m_strContentType.find ("start=");
m_strMimeStart = m_strContentType.substr (ulMimePos);
ulMimePos = m_strMimeStart.find (";");
m_strMimeStart = m_strMimeStart.substr (6, ulMimePos - 6);
}
}
}
while (iPosition != std::string::npos);
}
else
{
throw AxisTransportException (SERVER_TRANSPORT_UNKNOWN_HTTP_RESPONSE,
"Protocol is not HTTP.");
}
}
/* Axis2Transport::processRootMimeBody() Is a public method used to
* parse the mime attachments.
*/
void
Axis2Transport::processRootMimeBody ()
{
if (false == m_bReadPastRootMimeHeader)
{
do
{
if (m_strReceived.find ("\r\n\r\n") == std::string::npos)
{
std::string strTempReceived = "";
*m_pChannel >> strTempReceived; // Assume non blocking here
m_strReceived += strTempReceived;
}
}
while (m_strReceived.find ("\r\n\r\n") == std::string::npos);
//now we have found the end of root mime header
m_bReadPastRootMimeHeader = true;
//processMimeHeader(); For the time being we don't process this
// Done with root mime body headers, get rest of the payload
// which contain the soap message
m_strReceived =
m_strReceived.substr (m_strReceived.find ("\r\n\r\n") + 4);
unsigned int intMimeTemp = m_strReceived.find (m_strMimeBoundary);
if (intMimeTemp != std::string::npos)
{
m_strReceived = m_strReceived.substr (0, intMimeTemp);
m_strMimeReceived = m_strReceived.substr (intMimeTemp);
/* Using m_strMimeReceived will be
* continued when getAttachment is called.
*/
m_bMimeTrue = false;
}
}
else
{
unsigned int intMimeTemp = m_strReceived.find (m_strMimeBoundary);
if (intMimeTemp != std::string::npos)
{
m_strReceived = m_strReceived.substr (0, intMimeTemp);
m_strMimeReceived = m_strReceived.substr (intMimeTemp);
/* Using m_strMimeReceived will be
* continued when getAttachment is called.
*/
m_bMimeTrue = false;
}
return;
}
}
/* Axis2Transport::processMimeHeaders() Is a public method used to
* parse the Mime headers of the response message.
*/
void
Axis2Transport::processMimeHeader ()
{
unsigned int pos = 0;
unsigned int temppos = 0;
// Look for content lenght
if ((pos =
m_strMimeReceived.find ("Content-Type: ")) != std::string::npos)
{
m_strMimeContentType =
m_strMimeReceived.
substr (pos + strlen ("Content-Type: "),
m_strMimeReceived.find ("\n", pos));
pos = m_strMimeContentType.find (";");
temppos = m_strMimeContentType.find ("\r\n");
if (pos < temppos)
m_strMimeContentType = m_strMimeContentType.substr (0, pos);
else
m_strMimeContentType = m_strMimeContentType.substr (0, temppos);
}
// Look for mime root body's content transfer encoding
if ((pos =
m_strMimeReceived.find ("Content-Transfer-Encoding: ")) !=
std::string::npos)
{
m_strMimeContentTransferEncoding =
m_strMimeReceived.
substr (pos + strlen ("Content-Transfer-Encoding: "),
m_strMimeReceived.find ("\n", pos));
temppos = m_strMimeContentTransferEncoding.find ("\r\n");
m_strMimeContentTransferEncoding =
m_strMimeContentTransferEncoding.substr (0, temppos);
}
// Look for mime root body's content id
if ((pos = m_strMimeReceived.find ("Content-ID: ")) != std::string::npos)
{
m_strMimeContentID =
m_strMimeReceived.
substr (pos + strlen ("Content-ID: "),
m_strMimeReceived.find ("\n", pos));
temppos = m_strMimeContentID.find ("\r\n");
m_strMimeContentID = m_strMimeContentID.substr (0, temppos);
}
// Look for mime root body's content location
if ((pos =
m_strMimeReceived.find ("Content-Location: ")) != std::string::npos)
{
m_strMimeContentLocation =
atoi (m_strMimeReceived.
substr (pos + strlen ("Content-Location: "),
m_strMimeReceived.find ("\n", pos)).c_str ());
temppos = m_strMimeContentLocation.find ("\r\n");
m_strMimeContentLocation =
m_strMimeContentLocation.substr (0, temppos);
}
}
void
Axis2Transport::processMimeBody ()
{
}
void
Axis2Transport::getAttachment (char *pStrAttachment, int *pIntSize,
int intAttachmentId)
{
std::string strTempReceived = "";
*m_pChannel >> strTempReceived; // Assume non blocking here
m_strMimeReceived += strTempReceived;
do
{
if (m_strMimeReceived.find ("\r\n\r\n") == std::string::npos)
{
strTempReceived = "";
*m_pChannel >> strTempReceived; // Assume non blocking here
m_strMimeReceived += strTempReceived;
}
}
while (m_strMimeReceived.find ("\r\n\r\n") == std::string::npos);
//now we have found the end of next mime header
processMimeHeader ();
m_strMimeReceived = m_strMimeReceived.substr (m_strMimeReceived.
find ("\r\n\r\n"));
processMimeBody ();
}
void
Axis2Transport::setSocket (unsigned int uiNewSocket)
{
m_pChannel->setSocket (uiNewSocket);
}
const char *
Axis2Transport::getTransportProperty (const char *pcKey, bool response)
throw (AxisTransportException)
{
std::string strKeyToFind = std::string (pcKey);
for (unsigned int i = 0; i < m_vResponseHTTPHeaders.size (); i++)
{
if (m_vResponseHTTPHeaders[i].first == strKeyToFind)
{
return ((string) m_vResponseHTTPHeaders[i].second).c_str ();
}
}
return NULL;
}
const char *
Axis2Transport::getFirstTransportPropertyKey ()
{
m_viCurrentHeader = m_vHTTPHeaders.begin ();
if (m_viCurrentHeader == m_vHTTPHeaders.end ())
return NULL;
else
return (*m_viCurrentHeader).first.c_str ();
}
const char *
Axis2Transport::getNextTransportPropertyKey ()
{
//already at the end?
if (m_viCurrentHeader == m_vHTTPHeaders.end ())
return NULL;
m_viCurrentHeader++;
if (m_viCurrentHeader == m_vHTTPHeaders.end ())
return NULL;
else
return (*m_viCurrentHeader).first.c_str ();
}
const char *
Axis2Transport::getCurrentTransportPropertyKey ()
{
if (m_viCurrentHeader == m_vHTTPHeaders.end ())
return NULL;
else
return (*m_viCurrentHeader).first.c_str ();
}
const char *
Axis2Transport::getCurrentTransportPropertyValue ()
{
if (m_viCurrentHeader == m_vHTTPHeaders.end ())
return NULL;
else
return (*m_viCurrentHeader).second.c_str ();
}
void
Axis2Transport::deleteCurrentTransportProperty ()
{
if (m_viCurrentHeader != m_vHTTPHeaders.end ())
{
m_vHTTPHeaders.erase (m_viCurrentHeader);
}
}
void
Axis2Transport::deleteTransportProperty (char *pcKey,
unsigned int uiOccurance)
{
vector < std::pair < std::string,
std::string > >::iterator currentHeader = m_vHTTPHeaders.begin ();
unsigned int uiCount = 1;
while (currentHeader != m_vHTTPHeaders.end () && uiCount <= uiOccurance)
{
if (strcmp (pcKey, (*currentHeader).first.c_str ()) == 0)
{
if (uiCount == uiOccurance)
{
m_vHTTPHeaders.erase (currentHeader);
break;
}
uiCount++;
}
currentHeader++;
}
}
void
Axis2Transport::setMaintainSession (bool bSession)
{
m_bMaintainSession = bSession;
}
void
Axis2Transport::setSessionId (const char *pcSessionId)
{
m_strSessionKey = std::string (pcSessionId);
}
const char *
Axis2Transport::getSessionId ()
{
return m_strSessionKey.c_str ();
}