SOAPonHTTP.cpp

Go to the documentation of this file.
00001 
00024 // SOAPonHTTP.cpp: implementation of the SOAPonHTTP class.
00025 //
00027 
00028 #pragma warning ( disable: 4786 )
00029 #include "SOAPonHTTP.h"
00030 #ifndef _SSTREAM_
00031     #include <sstream>
00032 #endif // _SSTREAM_
00033 #include <iostream>
00034 #if !defined(SOAPPARSER_H)
00035     #include "SOAPParser.h"
00036 #endif // !defined(SOAPPARSER_H)
00037 #if !defined(SOAPELEMENT_H)
00038     #include "SOAPElement.h"
00039 #endif // !defined(SOAPELEMENT_H)
00040 #if !defined(SOAPENCODER_H)
00041     #include "SOAPEncoder.h"
00042 #endif // SOAPENCODER_H
00043 #if !defined(SOAPMETHOD_H)
00044     #include "SOAPMethod.h"
00045 #endif // SOAPMETHOD_H
00046 #include "TcpSocket.h"
00047 #include "IpAddress.h"
00048 #include <iostream>
00049 
00050 
00051 #ifdef _MSC_VER
00052 #define sleep Sleep
00053 #define snprintf _snprintf
00054 #endif
00055 
00057 // Construction/Destruction
00059 
00060 // Constants used by the SOAP HTTP implementation.
00061 const std::string g_KszPost = "POST ";
00062 const std::string g_KszManHeader = 
00063     "\"http://schemas.xmlsoap.org.soap/envelope/\"";
00064 const std::string g_KszContentType = 
00065     "Content-type: text/xml; charset=utf-8";
00066 const std::string g_KszContentLength = "Content-Length: ";
00067 const std::string g_KszSOAPAction = "SOAPAction: ";
00068 const std::string g_KszHTTPversion = "HTTP/1.0";
00069 const std::string g_KszSOAP = "<SOAP";
00070 const std::string g_KszBody = "Body";
00071 
00072 SOAPonHTTP::SOAPonHTTP()
00073 {
00074 
00075 }
00076 
00077 SOAPonHTTP::~SOAPonHTTP()
00078 {
00079 
00080 }
00081 
00082 std::string SOAPonHTTP::getSendableMessage( 
00083     const std::string& szSOAPMessage, 
00084     const std::string& szClassName,
00085     const std::string& szMethodName )
00086 {
00087     std::ostringstream szRetval;
00088     const long KnLength = szSOAPMessage.length();
00089 
00090         // This simply puts an HTTP header in front of the actual
00091     // SOAP message.
00092     szRetval << g_KszPost << "/" << szClassName << " " 
00093         << g_KszHTTPversion << std::endl;
00094     szRetval << g_KszContentType << std::endl;
00095     szRetval << g_KszContentLength << szSOAPMessage.length() 
00096         << std::endl;
00097     szRetval << g_KszSOAPAction << "\"" << szClassName << "#" 
00098         << szMethodName << "\"" << std::endl << std::endl;
00099     szRetval << szSOAPMessage;
00100     return szRetval.str();
00101 }
00102 
00103 void SOAPonHTTP::setHostAndPort( std::string szHost, 
00104     long nPort /*= 80*/ )
00105 {
00106         // Initializes the address and port.
00107     IpAddress ipAddress( szHost );
00108     m_socketAddress.setIpAddress( ipAddress );
00109     m_socketAddress.setPort( nPort );
00110 }
00111 
00112 bool SOAPonHTTP::getMethodDetails( const std::string& KszMessage, 
00113     std::string& szObjectName, std::string& szMethodName, 
00114     SOAPElement& theCall )
00115 {
00116     bool retval = true;
00117     
00118     long nPos = KszMessage.find( g_KszPost );
00119 
00120     // Find the first "/" after the first GET.
00121     nPos = KszMessage.find( "/", nPos );
00122 
00123     // We know where the object name starts.  It ends by the first
00124     // space.
00125     long nEndPos = KszMessage.find( " ", nPos );
00126 
00127     ++nPos;
00128     szObjectName = KszMessage.substr( nPos, nEndPos - nPos );
00129 
00130     std::string szSOAPMessage;
00131 
00132         // Find the start of the SOAP message.
00133     nPos = KszMessage.find( g_KszSOAP );
00134     if ( nPos >= 0 )
00135     {
00136         szSOAPMessage = 
00137             KszMessage.substr( nPos, KszMessage.length() - nPos );
00138     }
00139 
00140         // Parse the message now that we have it.
00141     SOAPParser soapParser;
00142     retval = soapParser.parseMessage( szSOAPMessage, theCall );
00143     if ( retval )
00144     {
00145                 // If we succeeded, get the name of the 
00146                 // method being called.  This of course
00147                 // assumes only one method in the body, and
00148                 // that there are no objects outside of the
00149                 // serialization root.  This method will
00150                 // need an override if this assumption is invalid.
00151         SOAPElement* pBody = NULL;
00152         theCall.getElement( g_KszBody, &pBody );
00153         if ( NULL != pBody )
00154         {
00155             SOAPElement& aMethod = pBody->elementAt( 0 );
00156             szMethodName = aMethod.accessorName();
00157         }
00158         if ( szMethodName.length() <= 0 )
00159         {
00160             // Create a SOAP fault
00161             retval = false;
00162         }
00163     }    
00164     else
00165     {
00166         szObjectName = 
00167             SOAPEncoder().encodeFault( *(soapParser.getFault()) );
00168     }
00169     return retval;
00170 }
00171 
00172 
00173 std::string SOAPonHTTP::getSendableResponse( 
00174     const std::string& szSOAPMessage, bool bIsFault /*= false*/ )
00175 {
00176     std::string retval;
00177 
00178         // This HTTP header seems to have a definite Microsoft
00179     // feel to it.  I will need to see how well this interoperates 
00180     // with a Unix machine.
00181     
00182     retval = "HTTP/1.1 ";
00183     if ( bIsFault )
00184     {
00185         retval += "500 Internal Server Error\r\n"; // GJPC seperate out the HTTP tokens
00186     }
00187     else
00188     {
00189         retval += "200 OK\r\n"; //GJPC seperate the HTTP tokens
00190     }
00191 
00192     retval += g_KszContentType;
00193         retval += "\r\nContent-Length: ";
00194         char buffer[33];
00195     snprintf( buffer, 33, "%d", szSOAPMessage.length() );
00196     retval += buffer;
00197         retval += "\r\n\r\n";
00198     retval += szSOAPMessage;
00199     return retval;
00200 }
00201 
00202 std::string SOAPonHTTP::send( const std::string& szClassName, 
00203     SOAPMethod& aMethod )
00204 {
00205     SOAPEncoder soapEncoder;
00206 
00207         // First off, encode the bugger.
00208     std::string szCall = soapEncoder.encodeMethodCall( aMethod );
00209         
00210         // Now get the message we want to send.
00211     std::string szSend = getSendableMessage( 
00212         szCall, szClassName, aMethod.methodName() );
00213     std::cerr << szSend;
00214 
00215         // gjpc - take the buffer off the stack
00216         const int KnBuffSize = 10000;
00217     char *buffer = new char[KnBuffSize + 1];
00218     memset( buffer, 0, KnBuffSize );
00219     TcpSocket theSocket;
00220 
00221         // Connect to the server.
00222     theSocket.connectTo( m_socketAddress );
00223 
00224         // Write out the request.
00225     theSocket.write( szSend.c_str(), szSend.length() );
00226 
00227         szSend = "";
00228 
00229         // TODO find out what happens with improperly formateed messages 
00230         // Read back the response.
00231     int bytes, zcnt = 0, cnt = 0;
00232         memset( buffer, 0, KnBuffSize );
00233         do
00234         {
00235                 if ( (bytes = theSocket.read( buffer, KnBuffSize )) == 0 )
00236                 {
00237                         sleep( 100 );
00238                          ++zcnt;
00239                 }
00240 
00241                 if ( bytes )
00242                         zcnt = 0;
00243 
00244                 cnt += bytes;
00245                 buffer[bytes] = 0;
00246                 szSend += buffer;
00247         }
00248         while ( ( strstr( buffer, "</SOAP-ENV:Envelope>" ) == NULL ) && ( zcnt < 20 ) );
00249 
00250         // Close the connection to the server.
00251     theSocket.close();
00252         delete buffer;
00253 
00254         // Return the result of the call.
00255     return szSend;
00256 }

Generated on Tue Mar 28 09:10:15 2006 for Simple SOAP by  doxygen 1.4.6