You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-commits@axis.apache.org by na...@apache.org on 2010/04/03 07:11:10 UTC

svn commit: r930475 - in /axis/axis1/c/trunk: include/axis/ include/axis/client/ src/cbindings/client/ src/engine/client/ src/soap/ src/transport/axis3/

Author: nadiramra
Date: Sat Apr  3 05:11:09 2010
New Revision: 930475

URL: http://svn.apache.org/viewvc?rev=930475&view=rev
Log:
AXISCPP-1068 - Support http redirects

Modified:
    axis/axis1/c/trunk/include/axis/AxisException.h
    axis/axis1/c/trunk/include/axis/AxisException.hpp
    axis/axis1/c/trunk/include/axis/GDefine.h
    axis/axis1/c/trunk/include/axis/GDefine.hpp
    axis/axis1/c/trunk/include/axis/client/Stub.h
    axis/axis1/c/trunk/src/cbindings/client/StubC.cpp
    axis/axis1/c/trunk/src/engine/client/Stub.cpp
    axis/axis1/c/trunk/src/soap/SoapFault.cpp
    axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.cpp
    axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.hpp

Modified: axis/axis1/c/trunk/include/axis/AxisException.h
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/include/axis/AxisException.h?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/include/axis/AxisException.h (original)
+++ axis/axis1/c/trunk/include/axis/AxisException.h Sat Apr  3 05:11:09 2010
@@ -382,12 +382,18 @@ typedef enum 
          * AxiscConfigException:configuration defaults have already been set
          */
 /*74*/    CONFIG_DEFAULTS_ALREADY_SET,
+
+    /**
+     * HTTPTransportException: Redirect received
+     */
+/*75*/   SERVER_TRANSPORT_REDIRECT_RECEIVED,
+
     /*
      * This FAULT_LAST is not used as a fault code, but instead is used 
      * internaly in the code. Developers should not use this as a fault 
      * code.
      */
-/*75*/    FAULT_LAST 
+/*76*/    FAULT_LAST
 } AXISC_AXISC_EXCEPTIONS;
 
 /**

Modified: axis/axis1/c/trunk/include/axis/AxisException.hpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/include/axis/AxisException.hpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/include/axis/AxisException.hpp (original)
+++ axis/axis1/c/trunk/include/axis/AxisException.hpp Sat Apr  3 05:11:09 2010
@@ -71,13 +71,13 @@ typedef enum 
      *    it's fault code is CLIENT
      *SERVER at the beginning means when this interpreted as a soap fault
      *    it's fault code is SERVER
-     *SOAP that comes next to CLIENT/SERVER means this is a soap releated
+     *SOAP that comes next to CLIENT/SERVER means this is a soap related
      *    exception
      *ENGINE that comes next to CLIENT/SERVER means this is a axisc++ engine
      *    related exception
-     *WSDD that comes next to CLIENT/SERVER means this is a wsdd releated
+     *WSDD that comes next to CLIENT/SERVER means this is a wsdd related
      *    exception
-     *TRANSPORT that comes next to CLIENT/SERVER means this is a transport releated
+     *TRANSPORT that comes next to CLIENT/SERVER means this is a transport related
      *    exception
      *CONFIG that comes next to CLIENT/SERVER means this is a axisc++ configuration
      *    related exception
@@ -388,18 +388,24 @@ typedef enum 
 /*73*/    AXISC_READ_CONF_EXCEPTION,
 
     /* CONFIG faults */
-    /*Following exceptions are releated to configuration faults
+    /*Following exceptions are related to configuration faults
      */
         /**
          * AxisConfigException:configuration defaults have already been set
          */
 /*74*/    CONFIG_DEFAULTS_ALREADY_SET,
+
+    /**
+     * HTTPTransportException: Redirect received
+     */
+/*75*/   SERVER_TRANSPORT_REDIRECT_RECEIVED,
+
     /*
      * This FAULT_LAST is not used as a fault code, but instead is used 
      * internaly in the code. Developers should not use this as a fault 
      * code.
      */
-/*75*/    FAULT_LAST 
+/*76*/    FAULT_LAST
 } AXISC_EXCEPTIONS;
 
 /**

Modified: axis/axis1/c/trunk/include/axis/GDefine.h
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/include/axis/GDefine.h?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/include/axis/GDefine.h (original)
+++ axis/axis1/c/trunk/include/axis/GDefine.h Sat Apr  3 05:11:09 2010
@@ -173,7 +173,21 @@ typedef enum 
     /**
      * Content type
      */
-    AXISC_CONTENT_TYPE
+    AXISC_CONTENT_TYPE,
+
+    /**
+     * Whether redirect should be handled implicitly. Values can be "true" or "false".
+     * The default is true. Redirects will only be implicitly be handled if going from
+     * http:// to http:// or https:// to https://.
+     */
+    AXISC_ENABLE_AUTOMATIC_REDIRECT,
+
+    /**
+     * Maximum number of automatic redirects to follow.  Property should be a numeric string.
+     * Default is 1. If "0" is specified, it will be as if AXISC_ENABLE_AUTOMATIC_REDIRECT is set to
+     * false.
+     */
+    AXISC_MAX_AUTOMATIC_REDIRECT
 } AXISC_TRANSPORT_INFORMATION_TYPE;
 
 #define AXISC_SOAPACTIONHEADER "SOAPAction"

Modified: axis/axis1/c/trunk/include/axis/GDefine.hpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/include/axis/GDefine.hpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/include/axis/GDefine.hpp (original)
+++ axis/axis1/c/trunk/include/axis/GDefine.hpp Sat Apr  3 05:11:09 2010
@@ -195,7 +195,22 @@ typedef enum 
     /**
      * Content type
      */
-    CONTENT_TYPE
+    CONTENT_TYPE,
+
+    /**
+     * Whether redirect should be handled implicitly. Values can be "true" or "false".
+     * The default is false. Redirects will only be implicitly be handled if going from
+     * http:// to http:// or https:// to https://.
+     */
+    ENABLE_AUTOMATIC_REDIRECT,
+
+    /**
+     * Maximum number of automatic redirects to follow.  Property should be a numeric string.
+     * Default is 1. If "0" is specified, it will be as if ENABLE_AUTOMATIC_REDIRECT is set to
+     * false.
+     */
+    MAX_AUTOMATIC_REDIRECT
+
 } AXIS_TRANSPORT_INFORMATION_TYPE;
 
 #define SOAPACTIONHEADER "SOAPAction"

Modified: axis/axis1/c/trunk/include/axis/client/Stub.h
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/include/axis/client/Stub.h?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/include/axis/client/Stub.h (original)
+++ axis/axis1/c/trunk/include/axis/client/Stub.h Sat Apr  3 05:11:09 2010
@@ -550,6 +550,25 @@ void axiscStubSetSOAPHeaders(AXISCHANDLE
 AXISC_STORAGE_CLASS_INFO
 void axiscStubCheckForExtraneousElements(AXISCHANDLE stub);
 
+/**
+ * =============
+ * Following is not in stub C++ class but is here to make things easier for C users.
+ * =============
+ */
+
+/**
+ * Indicates whether transport is to automatically handle http redirects.
+ * By default, redirects are not handled by the transport.  If enabled,
+ * auto-redirect will only occur when going from http to http or https to https.
+ *
+ * @param handleRedirect false=no auto-redirect. true=handle redirect automatically.
+ * @param maxCount how many redirects to follow.  Default is 1.  A value less than 1
+ *                 is the same as setting handleRedirect to false.
+ *
+ * @return 0=success; non-zero is failure.
+ */
+AXISC_STORAGE_CLASS_INFO
+void axiscStubSetTransportAutoRedirect(AXISCHANDLE stub, AxiscBool handleRedirect, int maxCount);
 
 #ifdef __cplusplus
  }

Modified: axis/axis1/c/trunk/src/cbindings/client/StubC.cpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/src/cbindings/client/StubC.cpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/src/cbindings/client/StubC.cpp (original)
+++ axis/axis1/c/trunk/src/cbindings/client/StubC.cpp Sat Apr  3 05:11:09 2010
@@ -863,6 +863,39 @@ void axiscStubCheckForExtraneousElements
     }
 }
 
+/**
+ * =============
+ * Following is not in stub C++ class but is here to make things easier for C users.
+ * =============
+ */
+
+AXISC_STORAGE_CLASS_INFO
+void axiscStubSetTransportAutoRedirect(AXISCHANDLE stub, AxiscBool handleRedirect, int maxCount)
+{
+    StubC *s = (StubC*)stub;
+
+    try
+    {
+        Call *c  = s->getCallStubC();
+
+        char *propValue = handleRedirect ? "true" : "false";
+        c->setTransportProperty(ENABLE_AUTOMATIC_REDIRECT, (const char*)propValue);
+
+        char buf[100];
+        sprintf(buf, "%d", maxCount);
+        c->setTransportProperty(MAX_AUTOMATIC_REDIRECT, (const char*)buf);
+    }
+    catch ( AxisException& e  )
+    {
+
+        processException(s, e.getExceptionCode(), e.what());
+    }
+    catch ( ... )
+    {
+        processException(s, -1, "Unrecognized exception thrown.");
+    }
+}
+
 }
 
 

Modified: axis/axis1/c/trunk/src/engine/client/Stub.cpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/src/engine/client/Stub.cpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/src/engine/client/Stub.cpp (original)
+++ axis/axis1/c/trunk/src/engine/client/Stub.cpp Sat Apr  3 05:11:09 2010
@@ -561,7 +561,7 @@ Stub::checkForExtraneousElements ()
       logEntryEngine("Stub::checkForExtraneousElements")
 
     IWrapperSoapDeSerializer *pDeSerializer = m_pCall->getSOAPDeSerializer();
-    if (pDeSerializer)
+    if (pDeSerializer && m_pTransport->isThereResponseData())
     {
         const char *peekedElementName = pDeSerializer->peekNextElementName();
         if (0x00 != *peekedElementName)

Modified: axis/axis1/c/trunk/src/soap/SoapFault.cpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/src/soap/SoapFault.cpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/src/soap/SoapFault.cpp (original)
+++ axis/axis1/c/trunk/src/soap/SoapFault.cpp Sat Apr  3 05:11:09 2010
@@ -184,7 +184,12 @@ initialize()
         /*70*/    {"AXISC", "Service thrown exception", "", ""},
         /*71*/    {"AXISC", "Unknown element exception", "", ""},
         /*72*/    {"AXISC", "Node value mismatch exception", "", ""},
-        /*73*/    {"AXISC", "Configuration read exception", "", ""}
+        /*73*/    {"AXISC", "Configuration read exception", "", ""},
+
+        /*74*/    {"AXISC", "Configuration defaults already set", "", ""},
+
+        /*75*/    {"Server", "Redirect received", "", ""}
+
         };
         s_parrSoapFaultStruct = s_arrLocalFaultStruct;
         m_bInit = true;

Modified: axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.cpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.cpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.cpp (original)
+++ axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.cpp Sat Apr  3 05:11:09 2010
@@ -56,6 +56,7 @@ m_bMaintainSession (false)
     m_pReleaseBufferCallback = 0;
     m_eProtocolType = APTHTTP1_1;
     m_strBytesToSend = "";
+    m_strBytesToSendRedirect = "";
     m_strHeaderBytesToSend = "";
     m_bChannelSecure = false;
     m_pNormalChannel = 0;
@@ -72,6 +73,12 @@ m_bMaintainSession (false)
 #else
     m_lChannelTimeout = 0;
 #endif
+    m_strResponseLocationURI = "";
+    m_bPerformAutoRedirect = false;
+    m_iMaximumAutoRedirects = 1;
+    m_strMaximumAutoRedirects = "1";
+    m_iNbrOfRedirectAttempts = 0;
+    m_bHasReadBeenDone = false;
     m_pNormalChannel = m_pChannelFactory->createChannel(UnsecureChannel);
     m_pSecureChannel = m_pChannelFactory->createChannel(SecureChannel);
 
@@ -96,6 +103,31 @@ HTTPTransport::
 }
 
 void HTTPTransport::
+resetOutputStateMachine()
+{
+    logEntryTransport("HTTPTransport::resetOutputStateMachine")
+
+    // Empty the bytes to send string. Note that the payload is saved in the case
+    // we need to handle redirect.
+    if (m_bPerformAutoRedirect && m_iMaximumAutoRedirects > 0 && m_strBytesToSend.length() > 0)
+        m_strBytesToSendRedirect = m_strBytesToSend;
+
+    m_strBytesToSend = "";
+    m_strHeaderBytesToSend = "";
+
+    // Also empty the response headers as there aren't any yet until the response comes back !
+    m_vResponseHTTPHeaders.clear();
+    // TODO: Possible memory leak here - does the clear op clean out the memory too?
+
+    // Empty other variables set from response received
+    m_strResponseHTTPStatusMessage = "";
+    m_strResponseContentType = "";
+    m_strResponseLocationURI = "";
+
+    logExit()
+}
+
+void HTTPTransport::
 resetInputStateMachine()
 {
     logEntryTransport("HTTPTransport::resetInputStateMachine")
@@ -114,7 +146,7 @@ resetInputStateMachine()
 
 /*
  * HTTPTransport::setEndpointUri( EndpointURI) sets the URI for the message.
- * Everytime the endpoint changes then currently connected channel is closed
+ * Every time 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
@@ -257,26 +289,39 @@ flushOutput() throw (AxisException, HTTP
 {
     logEntryTransport("HTTPTransport::flushOutput")
 
+    // since we are writing...we need to reset flag indicating a read has been done.
+    m_bHasReadBeenDone = false;
+
     char *utf8BufHeader  = NULL; // buffer for HTTP header when converting to utf8.
     char *utf8BufPayload = NULL; // buffer for HTTP payload when converting to utf8.
     char buff[24];
 
+    // Handle re-sending payload in case of redirect.
+    int payLoadLength   = m_strBytesToSend.length();
+    const char *payLoad = m_strBytesToSend.c_str();
+
+    if (payLoadLength == 0 && m_bPerformAutoRedirect && m_iMaximumAutoRedirects > 0)
+    {
+        payLoadLength   = m_strBytesToSendRedirect.length();
+        payLoad         = m_strBytesToSendRedirect.c_str();
+    }
+
     // Send HTTP headers and body
     try
     {
 #ifndef __OS400__
         // Generate HTTP header string - need to set content-length before generating headers.
-        sprintf( buff, "%d", m_strBytesToSend.length ());
+        sprintf( buff, "%d", payLoadLength);
         this->setTransportProperty ("Content-Length", buff);
         generateHTTPHeaders ();
 
         m_pActiveChannel->writeBytes(m_strHeaderBytesToSend.c_str(), m_strHeaderBytesToSend.length());
-        m_pActiveChannel->writeBytes(m_strBytesToSend.c_str(), m_strBytesToSend.length());
+        m_pActiveChannel->writeBytes(payLoad, payLoadLength);
 #else
         // Generate HTTP header string - need to set content-length before generating headers.
         // We need to convert payload to UTF-8 first to get accurate length of payload.
-        utf8BufPayload    = PlatformLanguage::toUTF8((const char *)m_strBytesToSend.c_str(), m_strBytesToSend.length()+1);
-        int payLoadLength = strlen(utf8BufPayload);
+        utf8BufPayload    = PlatformLanguage::toUTF8(payLoad, payLoadLength+1);
+        payLoadLength = strlen(utf8BufPayload);
 
         sprintf( buff, "%d", payLoadLength);
         this->setTransportProperty ("Content-Length", buff);
@@ -299,21 +344,15 @@ flushOutput() throw (AxisException, HTTP
     {
         delete utf8BufHeader;
         delete utf8BufPayload;
-        m_strBytesToSend = "";
-        m_strHeaderBytesToSend = "";
+
+        resetOutputStateMachine();
         
         logRethrowException()
         
         throw;
     }
 
-    // Empty the bytes to send string.
-    m_strBytesToSend = "";
-    m_strHeaderBytesToSend = "";
-
-    // Also empty the response headers as there aren't any yet until the response comes back !
-    m_vResponseHTTPHeaders.clear();
-    // TODO: Possible memory leak here - does the clear op clean out the memory too?
+    resetOutputStateMachine();
 
     logExit()
     
@@ -501,6 +540,13 @@ sendBytes( const char *pcSendBuffer, con
 {
     m_strBytesToSend += std::string (pcSendBuffer);
 
+    // Since we are sending new data, ensure nothing in redirect buffer.
+    if (m_strBytesToSendRedirect.length() > 0)
+    {
+        m_iNbrOfRedirectAttempts = 0;
+        m_strBytesToSendRedirect = "";
+    }
+
     return TRANSPORT_IN_PROGRESS;
 }
 
@@ -511,7 +557,8 @@ isThereResponseData()
 
     // We do not want to consume any SOAP data, just find out if there is any data.
     int bufLen = 0;
-    getBytes(NULL, &bufLen);
+    if (!m_bHasReadBeenDone)
+        getBytes(NULL, &bufLen);
     bool returnValue = (m_GetBytesState != eWaitingForHTTPHeader || m_iBytesLeft != 0);
     
     logExitWithBoolean(returnValue)
@@ -922,6 +969,30 @@ setTransportProperty( AXIS_TRANSPORT_INF
             break;
         }
 
+        case ENABLE_AUTOMATIC_REDIRECT:
+        {
+            if (value && strcmp(value, "true") == 0)
+                m_bPerformAutoRedirect = true;
+            else
+                m_bPerformAutoRedirect = false;
+            break;
+        }
+
+        case MAX_AUTOMATIC_REDIRECT:
+        {
+            if (value)
+                m_iMaximumAutoRedirects = atoi(value);
+
+            if (m_iMaximumAutoRedirects < 1)
+                m_iMaximumAutoRedirects = 0;
+
+            char buffer[100];
+            sprintf(buffer, "%d", m_iMaximumAutoRedirects);
+            m_strMaximumAutoRedirects = (const char *)buffer;
+
+            break;
+        }
+
         default:
         {
             break;
@@ -1051,6 +1122,18 @@ getTransportProperty( AXIS_TRANSPORT_INF
         {
             break;
         }
+
+        case ENABLE_AUTOMATIC_REDIRECT:
+        {
+            pszPropValue = m_bPerformAutoRedirect ? "true" : "false";
+            break;
+        }
+
+        case MAX_AUTOMATIC_REDIRECT:
+        {
+            pszPropValue = m_strMaximumAutoRedirects.c_str();
+            break;
+        }
     }
 
     logExitWithString(pszPropValue)
@@ -1327,6 +1410,8 @@ processHTTPHeader()
         // Store as key-value pairs 
         string key   = strHeaderLine.substr( 0, iSeperator);
         string value = strHeaderLine.substr( iSeperator + 1, strHeaderLine.length() - iSeperator - 2);
+        trim(value);
+        trim(key);
         m_vResponseHTTPHeaders.push_back( std::make_pair( key, value));
 
         // Content length set? Chunked overrides Content-length. It should be noted
@@ -1337,30 +1422,34 @@ processHTTPHeader()
                 m_iContentLength = atoi(value.c_str());
                 m_GetBytesState = eSOAPMessageHasContentLength;
             }
-            
+
+        // Redirect?
+        if (key == "Location")
+            m_strResponseLocationURI = value;
+
         // Is chunked? 
-        if (key == "Transfer-Encoding" && value == " chunked")
+        if (key == "Transfer-Encoding" && value == "chunked")
             m_GetBytesState = eSOAPMessageIsChunked;
 
         // Now handle whether we are going to close connection after processing 
         // request. If HTTP/1.0 we have to always close the connection by default; otherwise,
-        // we assume persistant connection by default.
+        // we assume persistent connection by default.
         if( m_eProtocolType == APTHTTP1_0)
             m_bReopenConnection = true;
 
         // We need to close the connection and open a new one if we have 'Connection: close'
-        if( key == "Connection" && (value == " close" || value == " Close"))
+        if( key == "Connection" && (value == "close" || value == "Close"))
         {
             m_bReopenConnection = true;
             m_pActiveChannel->closeQuietly( true);
         }
 
         // We need to close the connection and open a new one if we have 'Proxy-Connection: close'
-        if (key == "Proxy-Connection" && (value == " close" || value == " Close"))
+        if (key == "Proxy-Connection" && (value == "close" || 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")
+        if( key == "Connection" && value == "Keep-Alive")
             m_bReopenConnection = false;
 
         // Look for cookies
@@ -1371,31 +1460,31 @@ processHTTPHeader()
         /* If Content-Type: Multipart/Related; boundary=<MIME_boundary>; type=text/xml; start="<content id>" */
         if( key == "Content-Type")
         {
-            m_strContentType = value;
+            m_strResponseContentType = value;
 
-            string::size_type   ulMimePos = m_strContentType.find( ";");
+            string::size_type   ulMimePos = m_strResponseContentType.find( ";");
             std::string      strTypePart;
 
             if( ulMimePos != std::string::npos)
-                strTypePart = m_strContentType.substr( 1, ulMimePos - 1);
+                strTypePart = m_strResponseContentType.substr( 1, ulMimePos - 1);
 
             if( "Multipart/Related" == strTypePart)
             {
                 m_bMimeTrue = true;
-                m_strContentType = m_strContentType.substr( ulMimePos + 1, m_strContentType.length());
+                m_strResponseContentType = m_strResponseContentType.substr( ulMimePos + 1, m_strResponseContentType.length());
 
-                ulMimePos = m_strContentType.find( "boundary=");
-                m_strMimeBoundary = m_strContentType.substr( ulMimePos);
+                ulMimePos = m_strResponseContentType.find( "boundary=");
+                m_strMimeBoundary = m_strResponseContentType.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_strResponseContentType.find( "type=");
+                m_strMimeType = m_strResponseContentType.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_strResponseContentType.find( "start=");
+                m_strMimeStart = m_strResponseContentType.substr( ulMimePos);
                 ulMimePos = m_strMimeStart.find( ";");
                 m_strMimeStart = m_strMimeStart.substr( 6, ulMimePos - 6);
             }
@@ -1774,6 +1863,8 @@ readHTTPHeader()
        
     resetInputStateMachine();
     
+    m_bHasReadBeenDone = true;
+
     do
     {
         while (m_strReceived.find( ASCII_S_HTTP) == std::string::npos 
@@ -1814,11 +1905,32 @@ readHTTPHeader()
     }
     while( m_iResponseHTTPStatusCode == 100); 
     
-    // Now have a valid HTTP header that is not 100. Throw an exception if some unexpected error.
-    // Note that error 500 are for for SOAP faults.
-    if ( m_iResponseHTTPStatusCode != 500 
-            && (m_iResponseHTTPStatusCode < 200 || m_iResponseHTTPStatusCode >= 300))
+    // Now have a valid HTTP header that is not 100. Interrogate status code.
+    const char *contentType = m_strResponseContentType.c_str();
+    if (m_iResponseHTTPStatusCode > 199 && m_iResponseHTTPStatusCode < 300)
+    {
+        // SOAP return is OK - so fall through
+    }
+    else if ((contentType != NULL) && (strncmp(contentType, "text/html", 9) != 0)
+            && ((m_iResponseHTTPStatusCode > 499) && (m_iResponseHTTPStatusCode < 600)))
+    {
+        // SOAP Fault should be in here - so fall through
+    }
+    else if ((m_strResponseLocationURI.length() != 0)
+            && ((m_iResponseHTTPStatusCode == 301)
+                    || (m_iResponseHTTPStatusCode == 302)
+                    || (m_iResponseHTTPStatusCode == 307)))
     {
+        // Redirect (HTTP: 301/302/307)
+        handleRedirect();
+    }
+    else
+    {
+        m_iNbrOfRedirectAttempts = 0;
+        m_strBytesToSendRedirect = "";
+
+        // Unknown return code - so wrap up the content into a SOAP fault TODO
+
         m_strResponseHTTPStatusMessage = std::string( "Server sent HTTP error: '") +
           m_strResponseHTTPStatusMessage +  std::string("'\n");
 
@@ -1830,6 +1942,9 @@ readHTTPHeader()
         throw HTTPTransportException( SERVER_TRANSPORT_HTTP_EXCEPTION, m_strResponseHTTPStatusMessage.c_str());
     }  
     
+    m_iNbrOfRedirectAttempts = 0;
+    m_strBytesToSendRedirect = "";
+
     logExit()
 }
 
@@ -1988,3 +2103,48 @@ enableTrace(const char* logFilePath, con
     if (m_pSecureChannel)
         m_pSecureChannel->enableTrace(logFilePath, filters);
 }
+
+void HTTPTransport::
+handleRedirect()
+{
+    logEntryTransport("HTTPTransport::handleRedirect")
+
+    // close old connection
+    closeConnection(true);
+
+    // Setup exception data with redirect location.
+    m_strResponseHTTPStatusMessage = std::string( "Redirect: ") +  m_strResponseLocationURI +  std::string("'\n");
+
+    m_GetBytesState = eWaitingForHTTPHeader;
+
+    // See if we can process redirect seamlessly.
+    // We only do so if we are going from http -> http or https -> https.
+    const char *location = m_strResponseLocationURI.c_str();
+    bool throwException = true;
+    if (location
+            && m_bPerformAutoRedirect
+            && m_iNbrOfRedirectAttempts < m_iMaximumAutoRedirects
+            && ((m_bChannelSecure && strncmp("https:", location, 6) == 0)
+                   || (!m_bChannelSecure && strncmp("http:", location, 5) == 0)))
+    {
+        throwException = false;
+        m_iNbrOfRedirectAttempts++;
+        setEndpointUri(location);
+        openConnection();
+        flushOutput();
+        readHTTPHeader();
+    }
+
+    if (throwException)
+    {
+        m_iNbrOfRedirectAttempts = 0;
+        m_strBytesToSendRedirect = "";
+
+        logThrowExceptionWithData("HTTPTransportException - SERVER_TRANSPORT_REDIRECT_RECEIVED",
+                                  m_strResponseHTTPStatusMessage.c_str())
+
+        throw HTTPTransportException( SERVER_TRANSPORT_REDIRECT_RECEIVED, m_strResponseHTTPStatusMessage.c_str());
+    }
+
+    logExit()
+}

Modified: axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.hpp
URL: http://svn.apache.org/viewvc/axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.hpp?rev=930475&r1=930474&r2=930475&view=diff
==============================================================================
--- axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.hpp (original)
+++ axis/axis1/c/trunk/src/transport/axis3/HTTPTransport.hpp Sat Apr  3 05:11:09 2010
@@ -125,6 +125,8 @@ class HTTPTransport:public SOAPTransport
     int                     getChunkSize(string::size_type pos=0);
     
     void                    resetInputStateMachine();
+    void                    resetOutputStateMachine();
+    void                    handleRedirect();
     
     unsigned int            m_iChunkedDataLeftToConsume;
     unsigned int            m_iNextChunkedDataSize;
@@ -168,7 +170,7 @@ class HTTPTransport:public SOAPTransport
   /**
     * Keeps track of if we need to reopen connection.
     * Set true by setEndpointUri.
-    * Set false when a socket connection is established with the enpoint and 
+    * Set false when a socket connection is established with the endpoint and 
     * when there is no need renew (that is close and open again) an existing connection.
     */
     bool m_bReopenConnection;
@@ -286,7 +288,7 @@ class HTTPTransport:public SOAPTransport
   /** 
     * Content-Type holder
     */
-    std::string m_strContentType;
+    std::string m_strResponseContentType;
 
   /**
     * Mime Boundary value
@@ -326,6 +328,15 @@ class HTTPTransport:public SOAPTransport
     * New getBytes variables
     */
     EGETBYTESSTATE    m_GetBytesState;
+
+	bool m_bHasReadBeenDone;
+
+	std::string m_strMaximumAutoRedirects;
+    int  m_iNbrOfRedirectAttempts;
+    bool m_bPerformAutoRedirect;
+    int  m_iMaximumAutoRedirects;
+    std::string m_strBytesToSendRedirect;
+    std::string m_strResponseLocationURI;
 };
 
 #endif