graveyard/src/transport/axis2/Axis2Transport.cpp (1,001 lines of code) (raw):

/* * 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 (); }