You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by pr...@apache.org on 2005/09/01 14:59:50 UTC

svn commit: r265712 - in /webservices/axis/trunk/c/src/transport/axis3: HTTPTransport.cpp HTTPTransport.hpp

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