Author: prestonf
Date: Thu Sep 1 05:59:41 2005
New Revision: 265712
URL: http://svn.apache.org/viewcvs?rev=265712&view=rev
Log:
This is This modification is made in conjunction with AXISCPP-609.
Modified:
webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.cpp
webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.hpp
Modified: webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.cpp
URL:
http://svn.apache.org/viewcvs/webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.cpp?rev=265712&r1=265711&r2=265712&view=diff
==============================================================================
--- webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.cpp (original)
+++ webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.cpp Thu Sep 1
05:59:41 2005
@@ -73,8 +73,6 @@
HTTPTransport::HTTPTransport ():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)
{
@@ -85,7 +83,6 @@
m_strHeaderBytesToSend = "";
m_iBytesLeft = 0;
m_iContentLength = 0;
- m_pcReceived = 0;
m_bChannelSecure = false;
m_pNormalChannel = 0;
m_pSecureChannel = 0;
@@ -101,6 +98,8 @@
#endif
m_pNormalChannel = m_pChannelFactory->createChannel(UnsecureChannel);
m_pSecureChannel = m_pChannelFactory->createChannel(SecureChannel);
+
+ m_GetBytesState = eWaitingForHTTPHeader;
}
/*
@@ -261,7 +260,7 @@
void HTTPTransport::closeConnection()
{
// get ready for a new message.
- m_bReadPastHTTPHeaders = false;
+ m_GetBytesState = eWaitingForHTTPHeader;
//clear the message buffer in preperation of the next read.
m_strReceived = "";
@@ -285,25 +284,6 @@
*/
AXIS_TRANSPORT_STATUS HTTPTransport::flushOutput() throw (AxisException,
HTTPTransportException)
{
- //Chinthana:AXISCPP-558 - Gracefully handle server side close of
persistant connection
- if( m_bReopenConnection)
- {
- m_bReopenConnection = false;
-
- if( m_pActiveChannel->open() != AXIS_SUCCESS)
- {
- int iStringLength =
m_pActiveChannel->GetLastErrorMsg().length() + 1;
- const char * pszLastError = new char[iStringLength];
-
- memcpy( (void *) pszLastError,
-
m_pActiveChannel->GetLastErrorMsg().c_str(),
- iStringLength);
-
- throw HTTPTransportException(
CLIENT_TRANSPORT_OPEN_CONNECTION_FAILED,(char *) pszLastError);
- }
- }
- //16-08-2005.................................................
-
// 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
@@ -315,78 +295,35 @@
this->setTransportProperty ("Content-Length", buff);
- //Chinthana:AXISCPP-558 - Gracefully handle server side close of
persistant connection
- bool reopenConnection;
- if (m_pActiveChannel->reopenRequired())
- {
- reopenConnection = true;
- }
- else
- {
- reopenConnection = m_bReopenConnection;
- m_bReopenConnection = false;
- }
-
- bool reopenConnectionOnFailure = true;
- bool dataSent = false;
-
- while (!dataSent)
- {
- if( reopenConnection )
- {
- m_pActiveChannel->close();
-
- if( m_pActiveChannel->open() != AXIS_SUCCESS)
- {
- int iStringLength =
m_pActiveChannel->GetLastErrorMsg().length() + 1;
- const char* pszLastError = new
char[iStringLength];
-
- memcpy( (void *) pszLastError,
-
m_pActiveChannel->GetLastErrorMsg().c_str(),
- iStringLength);
-
- throw HTTPTransportException(
CLIENT_TRANSPORT_OPEN_CONNECTION_FAILED,
- (char *)
pszLastError);
- }
-
- // Only attempt to reopen the connection one time
- reopenConnectionOnFailure = false;
- }
- //16-08-2005.................................................
-
// The header is now complete. The message header and message can now be
// transmitted.
- try
- {
- #ifndef __OS400__
- *m_pActiveChannel <<
this->getHTTPHeaders ();
- *m_pActiveChannel <<
this->m_strBytesToSend.c_str ();
- #else
- const char *buf = this->getHTTPHeaders
();
- char *utf8Buf = toUTF8((char *)buf,
strlen(buf)+1);
- *m_pActiveChannel << utf8Buf;
- free(utf8Buf);
- buf =
this->m_strBytesToSend.c_str();
- utf8Buf = toUTF8((char *)buf,
strlen(buf)+1);
- *m_pActiveChannel << utf8Buf;
- free(utf8Buf);
- #endif
- // Chinthana: We're done sending
- dataSent = true;
-
- }
- catch( HTTPTransportException & e)
- {
- throw;
- }
- catch( AxisException & e)
- {
- throw;
- }
- catch(...)
- {
- throw;
- }
+ try
+ {
+#ifndef __OS400__
+ *m_pActiveChannel << this->getHTTPHeaders ();
+ *m_pActiveChannel << this->m_strBytesToSend.c_str ();
+#else
+ const char *buf = this->getHTTPHeaders ();
+ char *utf8Buf = toUTF8((char *)buf, strlen(buf)+1);
+ *m_pActiveChannel << utf8Buf;
+ free(utf8Buf);
+ buf = this->m_strBytesToSend.c_str();
+ utf8Buf = toUTF8((char *)buf, strlen(buf)+1);
+ *m_pActiveChannel << utf8Buf;
+ free(utf8Buf);
+#endif
+ }
+ catch( HTTPTransportException & e)
+ {
+ throw;
+ }
+ catch( AxisException & e)
+ {
+ throw;
+ }
+ catch(...)
+ {
+ throw;
}
// Empty the bytes to send string.
@@ -516,454 +453,172 @@
* @return AXIS_TRANSPORT_STATUS Value to the status o message reception
* (TRANSPORT_FINISHED or TRANSPORT_IN_PROGRESS).
*/
-AXIS_TRANSPORT_STATUS HTTPTransport::getBytes( char *pcBuffer, int *pSize)
throw (AxisException, HTTPTransportException)
+AXIS_TRANSPORT_STATUS HTTPTransport::getBytes( char * pcBuffer, int * piSize)
throw (AxisException, HTTPTransportException)
{
- if (0 <= m_iBytesLeft)
- {
- int iIterationCountdown = 100;
+ std::string nextChunk = "";
- try
+// It is assumed that the constructor has initialised the following variables:-
+// Type Label Initial Value
Description
+// enum m_eMsgState eHTTP_Header
Message decode state.
+// int m_iBytesLeft 0
Size of string held in m_strReceived.
+// char * m_pszRxBuffer new char [BUF_SIZE] Local buffer
with message read from channel.
+// std::string m_strReceived <uninitialised> Contains the
concatination of all unprocessed message string parts.
+
+// The method getBytes has three distinct states. These are defined as
+// follows:-
+// eWaitingForHTTPHeader - Waiting for a 'valid' HTTP header. A header is
+// is valid when a 'HTTP' string is found that is
+// subsequently followed by a CRLFCRLF sequence.
+// The HTTP header is then read and if the message
+// number is incorrect an exception is thrown.
+// The header also contains information on whether
+// the accompanying message is or is not chunked.
+// eSOAPMessageIsChunked - When a message is chunked, it has been broken
+// into a number of blocks. Each block is
+// preceeded by a hex number. The number is the
+// chunk length. A zero length chunk represents
+// the end of the message.
+// NB: because AXIS uses a 'pull' parser, the last
+// chunk size should never be read as the
+// parser will return once it has encountered
+// '</envelope>'. If it does read the last
+// '0', this could indicate that there is a
+// problem in the message.
+// eSOAPMessageIsNotChunked - The message is read until the number of message
+// bytes read equals the HTTP header content
+// length value.
+ switch( m_GetBytesState)
+ {
+ case eWaitingForHTTPHeader:
{
- m_pszRxBuffer [0] = '\0';
- *m_pActiveChannel >> m_pszRxBuffer;
- m_strReceived = m_pszRxBuffer;
-
- if( !m_bReadPastHTTPHeaders)
- {
- unsigned long start = std::string::npos;
-
- iIterationCountdown = 100;
-
- // getBytes needs to be able to exit any of the
following loops if the expected
- // character sequence is never detected. This
is done using a simple counter.
- // If the loop has not exited on its own accord
after say 100 tries, it is safe
- // to assume that it never will... To make the
test less likely to cause
- // problems with very long messages, the
countdown is only decremented when no
- // data has been received.
-
- do
- {
- do
- {
- if (m_strReceived.find(
ASCII_S_CRLFCRLF ) == std::string::npos)
- {
- m_pszRxBuffer [0] =
'\0';
- *m_pActiveChannel >>
m_pszRxBuffer;
-
- // If data has been
received, then add the data to the received message buffer
- // and reset the
countdown. Otherwise, decrement the countdown.
- if( strlen(
m_pszRxBuffer) > 0)
- {
- m_strReceived +=
m_pszRxBuffer;
-
iIterationCountdown = 100;
- }
- else
- {
-
iIterationCountdown--;
- }
- }
- } while( m_strReceived.find(
ASCII_S_CRLFCRLF ) == std::string::npos && iIterationCountdown > 0);
-
- if( iIterationCountdown == 0)
- {
- throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
-
"Timed out waiting for HTTP header message (1).");
- }
-
- if( m_strReceived.find( ASCII_S_HTTP )
== std::string::npos)
- {
- iIterationCountdown = 100;
-
- // 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( ASCII_S_CRLFCRLF ) + 4);
-
- do
- {
- if( m_strReceived.find(
ASCII_S_CRLFCRLF ) == std::string::npos)
- {
- m_pszRxBuffer
[0] = '\0';
-
*m_pActiveChannel >> m_pszRxBuffer;
-
- // If data has
been received, then add the data to the received message buffer
- // and reset
the countdown. Otherwise, decrement the countdown.
- if( strlen(
m_pszRxBuffer) > 0)
- {
-
m_strReceived += m_pszRxBuffer;
-
iIterationCountdown = 100;
- }
- else
- {
-
iIterationCountdown--;
- }
- }
- } while( m_strReceived.find(
ASCII_S_CRLFCRLF ) == std::string::npos && iIterationCountdown > 0);
-
- if( iIterationCountdown == 0)
- {
- throw
HTTPTransportException( SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
-
"Timed out waiting for HTTP header message
(2).");
- }
-
- // now this must contain HTTP.
Else there is a content error.
- }
-
- //now we have found the end of headers
- m_bReadPastHTTPHeaders = true;
-
- unsigned long pos = 0;
-
- // Look for content lenght
- if( (pos = m_strReceived.find(
ASCII_S_CONTENT_LENGTH )) != std::string::npos)
- {
- m_iContentLength = atoi(
m_strReceived.substr( pos + strlen( "Content-Length: "),
-
m_strReceived.find(
ASCII_S_LF, pos)).c_str());
- }
-
- // Check if the message is chunked
- if( (pos = m_strReceived.find(
ASCII_S_TRANSFERENCODING_CHUNKED )) != std::string::npos)
- {
- m_bChunked = true;
- }
- else
- {
- m_bChunked = false;
- }
+// Wait for a HTTP header to be located on the input stream.
+ do
+ {
+// From the input stream, wait for a 'valid' HTTP header.
+ readHTTPHeader();
- // 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(
ASCII_S_HTTP );
+// From the header,extract such things as chunking, message length, etc.
+ processHTTPHeader();
- if( start == std::string::npos)
- {
- start = 0;
- }
+ } while( m_iResponseHTTPStatusCode == 100);
- // Extract HTTP headers and process them
- m_strResponseHTTPHeaders =
m_strReceived.substr( start,
-
m_strReceived.find( ASCII_S_CRLFCRLF ) + 2 - start);
- processResponseHTTPHeaders();
+// Check that the HTTP status code is valid.
+ checkHTTPStatusCode();
- 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_pszRxBuffer [0] = '\0';
- *m_pActiveChannel >>
m_pszRxBuffer;
- m_strReceived = m_pszRxBuffer;
- }
- } while( m_iResponseHTTPStatusCode == 100 &&
iIterationCountdown > 0);
+// Done with HTTP headers, get SOAP message.
+ int iHTTPStart = m_strReceived.find( ASCII_S_HTTP);
+ int iHTTPEnd = m_strReceived.find( ASCII_S_CRLFCRLF,
iHTTPStart);
- if( iIterationCountdown == 0)
- {
- throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
-
"Timed out waiting for HTTP header message (3).");
- }
+ m_strReceived = m_strReceived.substr( iHTTPEnd +
strlen( ASCII_S_CRLFCRLF));
- if ( m_iResponseHTTPStatusCode != 500 &&
- ( m_iResponseHTTPStatusCode < 200 ||
m_iResponseHTTPStatusCode >= 300 ))
- {
- m_strResponseHTTPStatusMessage =
std::string("\n Server sent HTTP error: '") + m_strResponseHTTPStatusMessage +
std::string("'\n");
- throw HTTPTransportException(
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( ASCII_S_CRLFCRLF, start) + 4);
- }
-
- // Read past headers. Deal with payload
+ m_iBytesLeft = m_strReceived.length();
- // make sure we have a message with some content
- if( m_strReceived.length () == 0)
+// This bit of code should not be necessary, but just in case...
+ if( m_GetBytesState == eWaitingForHTTPHeader)
{
- m_pszRxBuffer [0] = '\0';
- *m_pActiveChannel >> m_pszRxBuffer;
- m_strReceived = m_pszRxBuffer;
+ break;
}
+ }
- if( m_strReceived.length () > 0)
+// At this point it is assumed that m_strReceived contains the block of
+// unprocessed data. m_iBytesLeft is the length of text/data in m_strReceived
+// is a 'char *' type copy of the m_strReceived string.
+// NB: It is assumed that all of these variables ARE in sync at this point.
+ case eSOAPMessageIsChunked:
{
-
- 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 long endOfChunkData =
m_strReceived.find( ASCII_S_CRLF );
-
- // make sure we have read at least some part of
the message
- if( endOfChunkData == std::string::npos)
- {
- iIterationCountdown = 100;
-
- do
- {
- m_pszRxBuffer [0] = '\0';
- *m_pActiveChannel >>
m_pszRxBuffer;
-
- if( strlen( m_pszRxBuffer) == 0)
- {
- iIterationCountdown--;
- }
- else
- {
- iIterationCountdown =
100;
- }
-
- m_strReceived = m_pszRxBuffer;
- endOfChunkData =
m_strReceived.find( ASCII_S_CRLF );
- } while( endOfChunkData ==
std::string::npos && iIterationCountdown > 0);
- }
-
- if( iIterationCountdown == 0)
+ if( m_GetBytesState == eSOAPMessageIsChunked)
+ {
+ if( m_iBytesLeft == 0)
{
- throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
-
"Timed out waiting for SOAP message (1).");
+ getNextDataPacket( "No data available
for next chunk size.");
}
- unsigned long endOfChunkSize = endOfChunkData;
+ m_iContentLength = getChunkSize();
- // 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( ASCII_S_LEFTPAREN ) != string::npos)
+// If the chunk size is larger than the available data, then read in more data
+// until all of the chunk has been read.
+ while( m_iContentLength > m_iBytesLeft)
{
- endOfChunkSize = m_strReceived.find(
ASCII_S_LEFTPAREN );
+ getNextDataPacket( "No data available
for next chunk.");
}
- // 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)
+// If data read is longer than chunk size, then copy the extra data to a
+// temporary variable and process data just belonging to this chunk.
+ if( m_iBytesLeft > m_iContentLength)
{
- // 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)
+ nextChunk = m_strReceived.substr(
m_iContentLength + strlen( ASCII_S_CRLF));
+ m_strReceived = m_strReceived.substr(
0, m_iContentLength);
+ m_iBytesLeft = m_iContentLength;
+
+// Check to see if the next chunk size is zero. If it is then change the
state.
+ if( peekChunkLength( nextChunk) == 0)
{
- processRootMimeBody();
+ m_GetBytesState =
eWaitingForHTTPHeader;
}
}
else
{
- m_strReceived = "";
+ nextChunk = "";
}
- }
- 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 long endOfChunkData =
m_strReceived.find( ASCII_S_CRLF );
-
- iIterationCountdown = 100;
-
- // Make sure that we have the found the end of
previous chunk
- while( endOfChunkData ==
std::string::npos && iIterationCountdown > 0)
- {
- m_pszRxBuffer [0] = '\0';
- *m_pActiveChannel >>
m_pszRxBuffer;
-
- if( strlen( m_pszRxBuffer) > 0)
- {
- iIterationCountdown =
100;
- }
- else
- {
- iIterationCountdown--;
- }
-
- m_strReceived += m_pszRxBuffer;
- endOfChunkData =
m_strReceived.find( ASCII_S_CRLF );
- }
-
- if( iIterationCountdown == 0)
- {
- throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
-
"Timed out waiting for SOAP message (2).");
- }
-
- m_strReceived = m_strReceived.substr(
endOfChunkData + 2); // Skip end of previous chunk
-
- endOfChunkData = m_strReceived.find(
ASCII_S_CRLF ); // Locate the start of next chunk
-
- iIterationCountdown = 100;
-
- // Make sure that we have the starting line of
next chunk
- while( endOfChunkData ==
std::string::npos && iIterationCountdown > 0)
- {
- m_pszRxBuffer [0] = '\0';
- *m_pActiveChannel >>
m_pszRxBuffer;
-
- if( strlen( m_pszRxBuffer) > 0)
- {
- iIterationCountdown =
100;
- }
- else
- {
- iIterationCountdown--;
- }
- m_strReceived += m_pszRxBuffer;
- endOfChunkData =
m_strReceived.find( ASCII_S_CRLF );
- }
-
- if( iIterationCountdown == 0)
- {
- throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
-
"Timed out waiting for SOAP message (3).");
- }
+// Now have at least chunk size worth of data. The chunk may contain Mime data
+// (this depends on information in the HTTP header). If Mime data is expected,
+// process it first.
+ if( m_bMimeTrue)
+ {
+ processRootMimeBody();
- unsigned long endOfChunkSize =
endOfChunkData;
+ m_iBytesLeft = m_strReceived.length();
+ }
- // look to see if there are any extensions -
these are put in brackets so look for those
- if (m_strReceived.substr (0,
endOfChunkData).find ( ASCII_S_LEFTPAREN ) != string::npos)
- {
- endOfChunkSize =
m_strReceived.find ( ASCII_S_LEFTPAREN );
- }
+ break;
+ }
+ }
- // convert the hex String into the length of
the chunk
- int iTempContentLength = axtoi( (char *)
m_strReceived.substr( 0, endOfChunkSize).c_str());
+ case eSOAPMessageIsNotChunked:
+ {
+// Check that there is more message to read.
+ if( m_iContentLength > 0)
+ {
+ getNextDataPacket( "No data available for
message.");
- // 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;
+// Check for Mime header
+ if( m_bMimeTrue)
+ {
+ processRootMimeBody();
- // 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 = "";
- }
+ m_iBytesLeft = m_strReceived.length();
+ }
- // Append the data of new chunk to data from
previous chunk
- m_strReceived = strTemp + m_strReceived;
+// Subtract message length (so far) from expcted content length.
+ m_iContentLength -= m_iBytesLeft;
- } // End of if
(m_strReceived.length() >= m_iContentLength)
- // If we have not reached end of
current chunk, nothing to be done
- }
- else // Not chunked
+// If all of the message has been received, then reset the process state.
+ if( m_iContentLength <= 0)
{
- // We have received part of chunk data.
If received payload
- // is a mime struct, process it
- if( m_bMimeTrue)
- {
- processRootMimeBody();
- }
+ m_GetBytesState = eWaitingForHTTPHeader;
}
}
-
- m_pcReceived = m_strReceived.c_str();
-
- if( m_pcReceived)
- {
- m_iBytesLeft = strlen( m_pcReceived);
- }
- else
+ else
{
- throw HTTPTransportException(
SERVER_TRANSPORT_BUFFER_EMPTY, "Recieved null");
- }
+// Reset the process state.
+ m_GetBytesState = eWaitingForHTTPHeader;
+ }
- m_iContentLength -= m_iBytesLeft;
- }
- catch( HTTPTransportException & e)
- {
- throw;
- }
- catch( AxisException & e)
- {
- throw;
- }
- catch(...)
- {
- throw;
+ break;
}
- }
-
- if( (m_pcReceived) && (*m_pcReceived) )
- {
- int iToCopy = (*pSize < m_iBytesLeft) ? *pSize : m_iBytesLeft;
-
- strncpy( pcBuffer, m_pcReceived, iToCopy);
+ }
- m_iBytesLeft -= iToCopy;
- m_pcReceived += iToCopy;
- *pSize = iToCopy;
+// Copy as much of the message to the parser buffer as possible.
+ if( copyDataToParserBuffer( pcBuffer, piSize, m_iBytesLeft))
+ {
+ m_strReceived += nextChunk;
+ m_iBytesLeft = m_strReceived.length();
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;
- }
+ return TRANSPORT_FINISHED;
}
/* HTTPTransport::setTransportProperty( Type, Value) Is an overloaded public
@@ -1780,4 +1435,284 @@
}
return NULL;
+}
+
+void HTTPTransport::readHTTPHeader()
+{
+// The parser is expecting a SOAP message. Thus, the HTTP header must have
+// been read and processed before control is returned to the parser. It can
+// not be assumed that the HTTP header will be read in one block, thus there
+// must be processing that first identifies the beginning of the HTTP header
+// block (i.e. looks for 'HTTP') and then additional processing that identifies
+// the end of the HTTP header block (i.e. looks for CR LF CR LF). To stop the
+// search becoming 'stuck' because of an incomplete, corrupt or unexpected
+// message an iteration count has been added (this could become configurable if
+// the user needs to remove this feature if the server is particularily slow,
+// etc.).
+ bool bHTTPHeaderFound = false;
+ int iIterationCount = 100;
+
+ m_strReceived = "";
+
+ do
+ {
+// Read whatever part of the response message that has arrived at the active
+// channel socket.
+ m_pszRxBuffer[0] = '\0';
+ *m_pActiveChannel >> m_pszRxBuffer;
+
+// Add the new message part to the received string.
+ m_strReceived += m_pszRxBuffer;
+
+// Do iteration processing.
+ if( strlen( m_pszRxBuffer) > 0)
+ {
+ iIterationCount = 100;
+ }
+ else
+ {
+ iIterationCount--;
+ }
+
+// Check for beginning and end of HTTP header.
+ if( m_strReceived.find( ASCII_S_HTTP) != std::string::npos &&
+ m_strReceived.find( ASCII_S_CRLFCRLF) !=
std::string::npos)
+ {
+ bHTTPHeaderFound = true;
+ }
+ } while( !bHTTPHeaderFound && iIterationCount > 0);
+
+// If the HTTP header was not found in the given number of iterations then
+// throw an exception.
+ if( iIterationCount == 0)
+ {
+ throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
+
"Timed out waiting for HTTP header message.");
+ }
+}
+
+void HTTPTransport::processHTTPHeader()
+{
+// At this point the HTTP header has been found. It now needs to be processed.
+ int iPosContentLength = m_strReceived.find( ASCII_S_CONTENT_LENGTH);
+
+ if( iPosContentLength != std::string::npos)
+ {
+ int iEOL = m_strReceived.find( ASCII_S_LF,
iPosContentLength);
+
+ iPosContentLength += strlen( ASCII_S_CONTENT_LENGTH);
+
+ m_iContentLength = atoi( m_strReceived.substr(
iPosContentLength, iEOL).c_str());
+
+ m_GetBytesState = eSOAPMessageIsNotChunked;
+ }
+
+// Check if the message is chunked
+ int iPosChunked = m_strReceived.find(
ASCII_S_TRANSFERENCODING_CHUNKED);
+
+ if( iPosChunked != std::string::npos)
+ {
+//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
+
+ m_GetBytesState = eSOAPMessageIsChunked;
+ }
+ else
+ {
+ if( m_eProtocolType == APTHTTP1_0)
+ {
+ m_GetBytesState = eSOAPMessageIsNotChunked;
+ m_iContentLength = m_iBytesLeft;
+ }
+ else
+ {
+ m_GetBytesState = eWaitingForHTTPHeader;
+
+ throw HTTPTransportException(
SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
+
"HTTP header message must be chunked or have a content length.");
+ }
+ }
+
+ int iHTTPStart = m_strReceived.find( ASCII_S_HTTP);
+ int iHTTPEnd = m_strReceived.find( ASCII_S_CRLFCRLF);
+
+// Extract HTTP header and process it
+ m_strResponseHTTPHeaders = m_strReceived.substr( iHTTPStart, iHTTPEnd +
2 - iHTTPStart);
+
+ processResponseHTTPHeaders();
+
+// If the HTTP message is a 'continue' message then remove the HTTP header and
+// then repeat HTTP header processing.
+ if( m_iResponseHTTPStatusCode == 100)
+ {
+ m_strReceived = m_strReceived.substr( iHTTPEnd + 2);
+ }
+}
+
+void HTTPTransport::checkHTTPStatusCode()
+{
+// Now have a valid HTTP header that is not 100.
+ if ( m_iResponseHTTPStatusCode != 500 &&
+ (m_iResponseHTTPStatusCode < 200 ||
+ m_iResponseHTTPStatusCode >= 300))
+ {
+ m_GetBytesState = eWaitingForHTTPHeader;
+
+ m_strResponseHTTPStatusMessage = std::string( "\n Server sent
HTTP error: '") +
+
m_strResponseHTTPStatusMessage +
+
std::string("'\n");
+
+ throw HTTPTransportException( SERVER_TRANSPORT_HTTP_EXCEPTION,
+ const_cast
<char *> (m_strResponseHTTPStatusMessage.c_str()));
+ }
+}
+
+bool HTTPTransport::getNextDataPacket( const char * pcszExceptionMessage)
+{
+ int iIterationCount = 100;
+ bool bDataRead = false;
+
+ do
+ {
+// Read whatever part of the response message that has arrived at the active
+// channel socket.
+ m_pszRxBuffer[0] = '\0';
+ *m_pActiveChannel >> m_pszRxBuffer;
+
+// Do iteration processing.
+ if( strlen( m_pszRxBuffer) == 0)
+ {
+ iIterationCount--;
+ }
+ else
+ {
+ bDataRead = true;
+ }
+
+ } while( !bDataRead && iIterationCount > 0);
+
+ if( bDataRead)
+ {
+ m_strReceived += m_pszRxBuffer;
+
+ m_iBytesLeft = m_strReceived.length();
+ }
+ else
+ {
+ if( m_strReceived.length() == 0)
+ {
+ m_GetBytesState = eWaitingForHTTPHeader;
+
+ if( pcszExceptionMessage != NULL && strlen(
pcszExceptionMessage) > 0)
+ {
+ int iStringLength = strlen(
pcszExceptionMessage) + 1;
+ const char * pszLastError = new
char[iStringLength];
+
+ memcpy( (void *) pszLastError,
pcszExceptionMessage, iStringLength);
+
+ throw HTTPTransportException(
SERVER_TRANSPORT_HTTP_EXCEPTION,
+
(char *) pszLastError);
+ }
+ }
+ }
+
+ return bDataRead;
+}
+
+int HTTPTransport::getChunkSize()
+{
+ int iChunkSize;
+
+ while( m_strReceived.find( ASCII_S_CRLF) == std::string::npos)
+ {
+ getNextDataPacket( "Could not find delimiter for end of chunk
size.");
+ }
+
+ int iEndOfChunkData = m_strReceived.find( ASCII_S_CRLF) + strlen(
ASCII_S_CRLF);
+ int iEndOfChunkSize = m_strReceived.find( ASCII_S_CRLF);
+
+// 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, iEndOfChunkSize).find( ASCII_S_LEFTPAREN)
!= string::npos)
+ {
+ iEndOfChunkSize = m_strReceived.find( ASCII_S_LEFTPAREN);
+ }
+
+// Convert the hex string into the length of the chunk.
+ iChunkSize = axtoi( (char *) m_strReceived.substr( 0,
iEndOfChunkSize).c_str());
+
+ m_strReceived = m_strReceived.substr( iEndOfChunkData);
+
+ m_iBytesLeft = m_strReceived.length();
+
+ return iChunkSize;
+}
+
+bool HTTPTransport::copyDataToParserBuffer( char * pcBuffer, int * piSize, int
iBytesToCopy)
+{
+ bool bTransportInProgress = false;
+
+ if( iBytesToCopy > 0)
+ {
+ int iToCopy = (*piSize < iBytesToCopy) ? *piSize : iBytesToCopy;
+
+ strncpy( pcBuffer, m_strReceived.c_str(), iToCopy);
+
+ m_iBytesLeft -= iToCopy;
+ *piSize = iToCopy;
+
+ if( m_iBytesLeft > 0)
+ {
+ m_strReceived = m_strReceived.substr( iToCopy);
+ }
+ else
+ {
+ m_strReceived = "";
+ }
+
+ bTransportInProgress = true;
+ }
+
+ return bTransportInProgress;
+}
+
+int HTTPTransport::peekChunkLength( std::string& strNextChunk)
+{
+ if( strNextChunk.length() == 0)
+ {
+ return -1;
+ }
+
+ int iEndOfChunkSize = strNextChunk.find( ASCII_S_CRLF);
+
+ if( iEndOfChunkSize == std::string::npos)
+ {
+ return -1;
+ }
+
+// 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( strNextChunk.substr( iEndOfChunkSize).find( ASCII_S_LEFTPAREN) !=
std::string::npos)
+ {
+ iEndOfChunkSize = strNextChunk.find( ASCII_S_LEFTPAREN);
+ }
+
+// Convert the hex string into the length of the chunk.
+ return axtoi( (char *) strNextChunk.substr( 0,
iEndOfChunkSize).c_str());
}
Modified: webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.hpp
URL:
http://svn.apache.org/viewcvs/webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.hpp?rev=265712&r1=265711&r2=265712&view=diff
==============================================================================
--- webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.hpp (original)
+++ webservices/axis/trunk/c/src/transport/axis3/HTTPTransport.hpp Thu Sep 1
05:59:41 2005
@@ -34,6 +34,13 @@
int axtoi (char *hexStg);
+typedef enum
+{
+ eWaitingForHTTPHeader,
+ eSOAPMessageIsChunked,
+ eSOAPMessageIsNotChunked
+} EGETBYTESSTATE;
+
class HTTPTransport:public SOAPTransport
{
public:
@@ -102,6 +109,13 @@
void processMimeBody();
void getAttachment( char*
pStrAttachment, int* pIntSize, int intAttachmentId);
int
FindTransportPropertyIndex( std::string);
+ void readHTTPHeader();
+ void processHTTPHeader();
+ void checkHTTPStatusCode();
+ bool getNextDataPacket( const char *
pcszExceptionMessage);
+ int getChunkSize();
+ bool copyDataToParserBuffer( char *
pcBuffer, int * piSize, int iBytesToCopy);
+ int peekChunkLength(
std::string& strNextChunk);
/**
* Keeps track of if we need to reopen connection.
@@ -150,27 +164,12 @@
*/
unsigned int m_iContentLength;
- /**
- * Is the message chunked
- */
- int m_bChunked;
-
/**
* String holding what we received over the channel
*/
std::string m_strReceived;
/**
- * Have we read past HTTP headers?
- */
- bool m_bReadPastHTTPHeaders;
-
- /**
- * Payload buffer
- */
- const char *m_pcReceived;
-
- /**
* Proxy server name.
*/
std::string m_strProxyHost;
@@ -263,6 +262,13 @@
char * m_pszRxBuffer;
long m_lChannelTimeout;
+
+ std::string m_strBuffered;
+
+ /**
+ * New getBytes variables
+ */
+ EGETBYTESSTATE m_GetBytesState;
};
#endif