BinHTTPURLInputStream.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:17k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Log: BinHTTPURLInputStream.cpp,v $
  58.  * Revision 1.11  2001/10/25 16:26:39  tng
  59.  * [Bug 4213] BinHTTPURLInputStream initialisation not thread safe.  By Mark Weaver.
  60.  *
  61.  * Revision 1.10  2001/10/25 16:10:46  tng
  62.  * [Bug 4121] BinHTTPUrlInputStream needds to read entire HTTP header. By John Clayton.
  63.  *
  64.  * Revision 1.9  2001/10/24 20:17:54  tng
  65.  * [Bug 3813] BinHTTPURLInputStream has weak HTTP request capabilities.  By Kevin Philips.
  66.  *
  67.  * Revision 1.8  2001/10/24 20:03:03  tng
  68.  * [Bug 2305] Include <stdlib.h> to BinHTTPURLInputStream.cpp.  By Peter A. Volchek.
  69.  *
  70.  * Revision 1.7  2001/09/04 17:52:57  peiyongz
  71.  * Bugzilla# 3170: patch from Kevin Philips to handle Query in XMLURL.
  72.  *
  73.  * Revision 1.6  2001/01/22 16:43:38  tng
  74.  * Loads winsock dynamically.  Fixed by Curt Arnold.
  75.  * Winsock2 is not initialized unless an http URL is used.    If an http
  76.  * URL is used and the Winsock 2 DLL is not installed, then an NetAccessor
  77.  * initialization exception is thrown.
  78.  *
  79.  * Revision 1.5  2000/07/21 03:22:44  andyh
  80.  * Improved (but still weak) http access by the parser.
  81.  * Windows only.  UNIX will follow, probably tomorrow.
  82.  *
  83.  * Revision 1.4  2000/05/15 22:31:29  andyh
  84.  * Replace #include<memory.h> with <string.h> everywhere.
  85.  *
  86.  * Revision 1.3  2000/03/24 00:32:15  rahulj
  87.  * Connect to the port specified in the URL, rather than the default one.
  88.  *
  89.  * Revision 1.2  2000/03/22 00:21:10  rahulj
  90.  * Now we throw exceptions when errors occur.
  91.  * Simplified the code, based on the assumption that
  92.  * the calling function will make sure that the buffer into
  93.  * which the data has to be read is large enough.
  94.  *
  95.  * Revision 1.1  2000/03/17 02:37:54  rahulj
  96.  * First cut at adding HTTP capability via native sockets.
  97.  * Still need to add:
  98.  *   error handling capability, ports other than 80,
  99.  *   escaped URL's
  100.  * Will add options in project file only when I am done with these
  101.  * above changes.
  102.  *
  103.  */
  104. #define _WINSOCKAPI_
  105. #define INCL_WINSOCK_API_TYPEDEFS 1
  106. #include <winsock2.h>
  107. #include <windows.h>
  108. #include <tchar.h>
  109. #include <stdio.h>
  110. #include <string.h>
  111. #include <stdlib.h>
  112. #include <util/PlatformUtils.hpp>
  113. #include <util/XMLNetAccessor.hpp>
  114. #include <util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp>
  115. #include <util/XMLString.hpp>
  116. #include <util/XMLExceptMsgs.hpp>
  117. #include <util/Janitor.hpp>
  118. #include <util/XMLUniDefs.hpp>
  119. HMODULE gWinsockLib = NULL;
  120. LPFN_GETHOSTBYNAME gWSgethostbyname = NULL;
  121. LPFN_INET_ADDR gWSinet_addr = NULL;
  122. LPFN_GETHOSTBYADDR gWSgethostbyaddr = NULL;
  123. LPFN_HTONS gWShtons = NULL;
  124. LPFN_SOCKET gWSsocket = NULL;
  125. LPFN_CONNECT gWSconnect = NULL;
  126. LPFN_SEND gWSsend = NULL;
  127. LPFN_RECV gWSrecv = NULL;
  128. LPFN_SHUTDOWN gWSshutdown = NULL;
  129. LPFN_CLOSESOCKET gWSclosesocket = NULL;
  130. LPFN_WSACLEANUP gWSACleanup = NULL;
  131. bool BinHTTPURLInputStream::fInitialized = false;
  132. XMLMutex* BinHTTPURLInputStream::fInitMutex = 0;
  133. void BinHTTPURLInputStream::Initialize() {
  134.     //
  135.     // Initialize the WinSock library here.
  136.     //
  137.     WORD        wVersionRequested;
  138.     WSADATA     wsaData;
  139. LPFN_WSASTARTUP startup = NULL;
  140. if(gWinsockLib == NULL) {
  141. gWinsockLib = LoadLibrary(_T("WSOCK32"));
  142. if(gWinsockLib == NULL) {
  143. ThrowXML(NetAccessorException, XMLExcepts::NetAcc_InitFailed);
  144. }
  145. else {
  146. startup = (LPFN_WSASTARTUP) GetProcAddress(gWinsockLib,_T("WSAStartup"));
  147. gWSACleanup = (LPFN_WSACLEANUP) GetProcAddress(gWinsockLib,_T("WSACleanup"));
  148. gWSgethostbyname = (LPFN_GETHOSTBYNAME) GetProcAddress(gWinsockLib,_T("gethostbyname"));
  149. gWSinet_addr = (LPFN_INET_ADDR) GetProcAddress(gWinsockLib,_T("inet_addr"));
  150. gWSgethostbyaddr = (LPFN_GETHOSTBYADDR) GetProcAddress(gWinsockLib,_T("gethostbyaddr"));
  151. gWShtons = (LPFN_HTONS) GetProcAddress(gWinsockLib,_T("htons"));
  152. gWSsocket = (LPFN_SOCKET) GetProcAddress(gWinsockLib,_T("socket"));
  153. gWSconnect = (LPFN_CONNECT) GetProcAddress(gWinsockLib,_T("connect"));
  154. gWSsend = (LPFN_SEND) GetProcAddress(gWinsockLib,_T("send"));
  155. gWSrecv = (LPFN_RECV) GetProcAddress(gWinsockLib,_T("recv"));
  156. gWSshutdown = (LPFN_SHUTDOWN) GetProcAddress(gWinsockLib,_T("shutdown"));
  157. gWSclosesocket = (LPFN_CLOSESOCKET) GetProcAddress(gWinsockLib,_T("closesocket"));
  158. if(startup == NULL ||
  159. gWSACleanup == NULL ||
  160. gWSgethostbyname == NULL ||
  161. gWSinet_addr == NULL ||
  162. gWSgethostbyaddr == NULL ||
  163. gWShtons == NULL ||
  164. gWSsocket == NULL ||
  165. gWSconnect == NULL ||
  166. gWSsend == NULL ||
  167. gWSrecv == NULL ||
  168. gWSshutdown == NULL ||
  169. gWSclosesocket == NULL)
  170. {
  171. gWSACleanup = NULL;
  172. Cleanup();
  173. ThrowXML(NetAccessorException, XMLExcepts::NetAcc_InitFailed);
  174. }
  175. }
  176. }
  177.     wVersionRequested = MAKEWORD( 2, 2 );
  178.     int err = (*startup)(wVersionRequested, &wsaData);
  179.     if (err != 0)
  180.     {
  181.         // Call WSAGetLastError() to get the last error.
  182.         ThrowXML(NetAccessorException, XMLExcepts::NetAcc_InitFailed);
  183.     }
  184.     fInitialized = true;
  185. }
  186. void BinHTTPURLInputStream::Cleanup() {
  187. if(fInitialized)
  188. {
  189. if(gWSACleanup) (*gWSACleanup)();
  190. gWSACleanup = NULL;
  191. gWinsockLib = NULL;
  192. gWSgethostbyname = NULL;
  193. gWSinet_addr = NULL;
  194. gWSgethostbyaddr = NULL;
  195. gWShtons = NULL;
  196. gWSsocket = NULL;
  197. gWSconnect = NULL;
  198. gWSsend = NULL;
  199. gWSrecv = NULL;
  200. gWSshutdown = NULL;
  201. gWSclosesocket = NULL;
  202. FreeLibrary(gWinsockLib);
  203.       fInitialized = false;
  204.       delete fInitMutex;
  205.       fInitMutex = 0;
  206. }
  207. }
  208. hostent* BinHTTPURLInputStream::gethostbyname(const char* name)
  209. {
  210. return (*gWSgethostbyname)(name);
  211. }
  212. unsigned long BinHTTPURLInputStream::inet_addr(const char* cp)
  213. {
  214. return (*gWSinet_addr)(cp);
  215. }
  216. hostent* BinHTTPURLInputStream::gethostbyaddr(const char* addr,int len,int type)
  217. {
  218. return (*gWSgethostbyaddr)(addr,len,type);
  219. }
  220. unsigned short BinHTTPURLInputStream::htons(unsigned short hostshort)
  221. {
  222. return (*gWShtons)(hostshort);
  223. }
  224. unsigned short BinHTTPURLInputStream::socket(int af,int type,int protocol)
  225. {
  226. return (*gWSsocket)(af,type,protocol);
  227. }
  228. int BinHTTPURLInputStream::connect(unsigned short s,const sockaddr* name,int namelen)
  229. {
  230. return (*gWSconnect)(s,name,namelen);
  231. }
  232. int BinHTTPURLInputStream::send(unsigned short s,const char* buf,int len,int flags)
  233. {
  234. return (*gWSsend)(s,buf,len,flags);
  235. }
  236. int BinHTTPURLInputStream::recv(unsigned short s,char* buf,int len,int flags)
  237. {
  238. return (*gWSrecv)(s,buf,len,flags);
  239. }
  240. int BinHTTPURLInputStream::shutdown(unsigned int s,int how)
  241. {
  242. return (*gWSshutdown)(s,how);
  243. }
  244. int BinHTTPURLInputStream::closesocket(unsigned int socket)
  245. {
  246. return (*gWSclosesocket)(socket);
  247. }
  248. BinHTTPURLInputStream::BinHTTPURLInputStream(const XMLURL& urlSource)
  249.       : fSocketHandle(0)
  250.       , fBytesProcessed(0)
  251. {
  252.     if(!fInitialized)
  253.     {
  254.         if (!fInitMutex)
  255.         {
  256.             XMLMutex* tmpMutex = new XMLMutex;
  257.             if (XMLPlatformUtils::compareAndSwap((void**)&fInitMutex, tmpMutex, 0))
  258.             {
  259.                 // Someone beat us to it, so let's clean up ours
  260.                 delete tmpMutex;
  261.             }
  262.          }
  263.          XMLMutexLock lock(fInitMutex);
  264.          if (!fInitialized)
  265.          {
  266.              Initialize();
  267.          }
  268.     }
  269.     //
  270.     // Pull all of the parts of the URL out of th urlSource object, and transcode them
  271.     //   and transcode them back to ASCII.
  272.     //
  273.     const XMLCh*        hostName = urlSource.getHost();
  274.     char*               hostNameAsCharStar = XMLString::transcode(hostName);
  275.     ArrayJanitor<char>  janBuf1(hostNameAsCharStar);
  276.     const XMLCh*        path = urlSource.getPath();
  277.     char*               pathAsCharStar = XMLString::transcode(path);
  278.     ArrayJanitor<char>  janBuf2(pathAsCharStar);
  279.     const XMLCh*        fragment = urlSource.getFragment();
  280.     char*               fragmentAsCharStar = 0;
  281.     if (fragment)
  282.         fragmentAsCharStar = XMLString::transcode(fragment);
  283.     ArrayJanitor<char>  janBuf3(fragmentAsCharStar);
  284.     const XMLCh*        query = urlSource.getQuery();
  285.     char*               queryAsCharStar = 0;
  286.     if (query)
  287.         queryAsCharStar = XMLString::transcode(query);
  288.     ArrayJanitor<char>  janBuf4(queryAsCharStar);
  289.     unsigned short      portNumber = (unsigned short) urlSource.getPortNum();
  290.     //
  291.     // Set up a socket.
  292.     //
  293.     struct hostent*     hostEntPtr = 0;
  294.     struct sockaddr_in  sa;
  295.     if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL)
  296.     {
  297.         unsigned long  numAddress = inet_addr(hostNameAsCharStar);
  298.         if (numAddress == INADDR_NONE)
  299.         {
  300.             // Call WSAGetLastError() to get the error number.
  301.             ThrowXML(NetAccessorException,
  302.                      XMLExcepts::NetAcc_TargetResolution);
  303.         }
  304.         if ((hostEntPtr =
  305.                 gethostbyaddr((const char *) &numAddress,
  306.                               sizeof(unsigned long), AF_INET)) == NULL)
  307.         {
  308.             // Call WSAGetLastError() to get the error number.
  309.             ThrowXML(NetAccessorException,
  310.                      XMLExcepts::NetAcc_TargetResolution);
  311.         }
  312.     }
  313.     memcpy((void *) &sa.sin_addr,
  314.            (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
  315.     sa.sin_family = hostEntPtr->h_addrtype;
  316.     sa.sin_port = htons(portNumber);
  317.     SOCKET s = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
  318.     if (s == INVALID_SOCKET)
  319.     {
  320.         // Call WSAGetLastError() to get the error number.
  321.         ThrowXML(NetAccessorException,
  322.                  XMLExcepts::NetAcc_CreateSocket);
  323.     }
  324.     if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) == SOCKET_ERROR)
  325.     {
  326.         // Call WSAGetLastError() to get the error number.
  327.         ThrowXML(NetAccessorException,
  328.                  XMLExcepts::NetAcc_ConnSocket);
  329.     }
  330.     // Set a flag so we know that the headers have not been read yet.
  331.     bool fHeaderRead = false;
  332.     // The port is open and ready to go.
  333.     // Build up the http GET command to send to the server.
  334.     // To do:  We should really support http 1.1.  This implementation
  335.     //         is weak.
  336.     memset(fBuffer, 0, sizeof(fBuffer));
  337.     strcpy(fBuffer, "GET ");
  338.     strcat(fBuffer, pathAsCharStar);
  339.     if (queryAsCharStar != 0)
  340.     {
  341.         // Tack on a ? before the fragment
  342.         strcat(fBuffer,"?");
  343.         strcat(fBuffer, queryAsCharStar);
  344.     }
  345.     if (fragmentAsCharStar != 0)
  346.     {
  347.         strcat(fBuffer, fragmentAsCharStar);
  348.     }
  349.     strcat(fBuffer, " HTTP/1.0rn");
  350.     strcat(fBuffer, "Host: ");
  351.     strcat(fBuffer, hostNameAsCharStar);
  352.     if (portNumber != 80)
  353.     {
  354.         strcat(fBuffer, ":");
  355.         int i = strlen(fBuffer);
  356.         _itoa(portNumber, fBuffer+i, 10);
  357.     }
  358.     strcat(fBuffer, "rnrn");
  359.     // Send the http request
  360.     int lent = strlen(fBuffer);
  361.     int  aLent = 0;
  362.     if ((aLent = send(s, fBuffer, lent, 0)) != lent)
  363.     {
  364.         // Call WSAGetLastError() to get the error number.
  365.         ThrowXML(NetAccessorException,
  366.                  XMLExcepts::NetAcc_WriteSocket);
  367.     }
  368.     //
  369.     // get the response, check the http header for errors from the server.
  370.     //
  371.     memset(fBuffer, 0, sizeof(fBuffer));
  372.     aLent = recv(s, fBuffer, sizeof(fBuffer)-1, 0);
  373.     if (aLent == SOCKET_ERROR || aLent == 0)
  374.     {
  375.         // Call WSAGetLastError() to get the error number.
  376.         ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
  377.     }
  378.     fBufferEnd = fBuffer+aLent;
  379.     *fBufferEnd = 0;
  380.     do {
  381.         // Find the break between the returned http header and any data.
  382.         //  (Delimited by a blank line)
  383.         // Hang on to any data for use by the first read from this BinHTTPURLInputStream.
  384.         //
  385.         fBufferPos = strstr(fBuffer, "rnrn");
  386.         if (fBufferPos != 0)
  387.         {
  388.             fBufferPos += 4;
  389.             *(fBufferPos-2) = 0;
  390.             fHeaderRead = true;
  391.         }
  392.         else
  393.         {
  394.             fBufferPos = strstr(fBuffer, "nn");
  395.             if (fBufferPos != 0)
  396.             {
  397.                 fBufferPos += 2;
  398.                 *(fBufferPos-1) = 0;
  399.                 fHeaderRead = true;
  400.             }
  401.             else
  402.             {
  403.                 //
  404.                 // Header is not yet read, do another recv() to get more data...
  405.                 aLent = recv(s, fBufferEnd, (sizeof(fBuffer) - 1) - (fBufferEnd - fBuffer), 0);
  406.                 if (aLent == SOCKET_ERROR || aLent == 0)
  407.                 {
  408.                     // Call WSAGetLastError() to get the error number.
  409.                     ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
  410.                 }
  411.                 fBufferEnd = fBufferEnd + aLent;
  412.                 *fBufferEnd = 0;
  413.             }
  414.         }
  415.     } while(fHeaderRead == false);
  416.     // Make sure the header includes an HTTP 200 OK response.
  417.     //
  418.     char *p = strstr(fBuffer, "HTTP");
  419.     if (p == 0)
  420.     {
  421.         ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
  422.     }
  423.     p = strchr(p, ' ');
  424.     if (p == 0)
  425.     {
  426.         ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
  427.     }
  428.     int httpResponse = atoi(p);
  429.     if (httpResponse != 200)
  430.     {
  431.         // Most likely a 404 Not Found error.
  432.         //   Should recognize and handle the forwarding responses.
  433.         //
  434.         ThrowXML(NetAccessorException, XMLExcepts::File_CouldNotOpenFile);
  435.     }
  436.     fSocketHandle = (unsigned int) s;
  437. }
  438. BinHTTPURLInputStream::~BinHTTPURLInputStream()
  439. {
  440.     shutdown(fSocketHandle, SD_BOTH);
  441.     closesocket(fSocketHandle);
  442. }
  443. //
  444. //  readBytes
  445. //
  446. unsigned int BinHTTPURLInputStream::readBytes(XMLByte* const    toFill
  447.                                     , const unsigned int    maxToRead)
  448. {
  449.     unsigned int len = fBufferEnd - fBufferPos;
  450.     if (len > 0)
  451.     {
  452.         // If there's any data left over in the buffer into which we first
  453.         //   read from the server (to get the http header), return that.
  454.         if (len > maxToRead)
  455.             len = maxToRead;
  456.         memcpy(toFill, fBufferPos, len);
  457.         fBufferPos += len;
  458.     }
  459.     else
  460.     {
  461.         // There was no data in the local buffer.
  462.         // Read some from the socket, straight into our caller's buffer.
  463.         //
  464.         len = recv((SOCKET) fSocketHandle, (char *) toFill, maxToRead, 0);
  465.         if (len == SOCKET_ERROR)
  466.         {
  467.             // Call WSAGetLastError() to get the error number.
  468.             ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
  469.         }
  470.     }
  471.     fBytesProcessed += len;
  472.     return len;
  473. }