BinHTTPURLInputStream.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:18k
源码类别:

词法分析

开发平台:

Visual 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.4  2003/05/17 05:54:18  knoaman
  59.  * Update NetAccessors to use the memory manager.
  60.  *
  61.  * Revision 1.3  2002/12/06 16:43:55  tng
  62.  * Fix the error messages thrown from net accessor module.
  63.  *
  64.  * Revision 1.2  2002/11/04 15:11:39  tng
  65.  * C++ Namespace Support.
  66.  *
  67.  * Revision 1.1.1.1  2002/02/01 22:22:23  peiyongz
  68.  * sane_include
  69.  *
  70.  * Revision 1.12  2001/12/13 21:16:52  peiyongz
  71.  * Fix: Invalid Argument to FreeLibrary (Hint: 0x0000000)
  72.  *
  73.  * Revision 1.11  2001/10/25 16:26:39  tng
  74.  * [Bug 4213] BinHTTPURLInputStream initialisation not thread safe.  By Mark Weaver.
  75.  *
  76.  * Revision 1.10  2001/10/25 16:10:46  tng
  77.  * [Bug 4121] BinHTTPUrlInputStream needds to read entire HTTP header. By John Clayton.
  78.  *
  79.  * Revision 1.9  2001/10/24 20:17:54  tng
  80.  * [Bug 3813] BinHTTPURLInputStream has weak HTTP request capabilities.  By Kevin Philips.
  81.  *
  82.  * Revision 1.8  2001/10/24 20:03:03  tng
  83.  * [Bug 2305] Include <stdlib.h> to BinHTTPURLInputStream.cpp.  By Peter A. Volchek.
  84.  *
  85.  * Revision 1.7  2001/09/04 17:52:57  peiyongz
  86.  * Bugzilla# 3170: patch from Kevin Philips to handle Query in XMLURL.
  87.  *
  88.  * Revision 1.6  2001/01/22 16:43:38  tng
  89.  * Loads winsock dynamically.  Fixed by Curt Arnold.
  90.  * Winsock2 is not initialized unless an http URL is used.    If an http
  91.  * URL is used and the Winsock 2 DLL is not installed, then an NetAccessor
  92.  * initialization exception is thrown.
  93.  *
  94.  * Revision 1.5  2000/07/21 03:22:44  andyh
  95.  * Improved (but still weak) http access by the parser.
  96.  * Windows only.  UNIX will follow, probably tomorrow.
  97.  *
  98.  * Revision 1.4  2000/05/15 22:31:29  andyh
  99.  * Replace #include<memory.h> with <string.h> everywhere.
  100.  *
  101.  * Revision 1.3  2000/03/24 00:32:15  rahulj
  102.  * Connect to the port specified in the URL, rather than the default one.
  103.  *
  104.  * Revision 1.2  2000/03/22 00:21:10  rahulj
  105.  * Now we throw exceptions when errors occur.
  106.  * Simplified the code, based on the assumption that
  107.  * the calling function will make sure that the buffer into
  108.  * which the data has to be read is large enough.
  109.  *
  110.  * Revision 1.1  2000/03/17 02:37:54  rahulj
  111.  * First cut at adding HTTP capability via native sockets.
  112.  * Still need to add:
  113.  *   error handling capability, ports other than 80,
  114.  *   escaped URL's
  115.  * Will add options in project file only when I am done with these
  116.  * above changes.
  117.  *
  118.  */
  119. #define _WINSOCKAPI_
  120. #define INCL_WINSOCK_API_TYPEDEFS 1
  121. #include <winsock2.h>
  122. #include <windows.h>
  123. #include <tchar.h>
  124. #include <stdio.h>
  125. #include <string.h>
  126. #include <stdlib.h>
  127. #include <xercesc/util/PlatformUtils.hpp>
  128. #include <xercesc/util/XMLNetAccessor.hpp>
  129. #include <xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp>
  130. #include <xercesc/util/XMLString.hpp>
  131. #include <xercesc/util/XMLExceptMsgs.hpp>
  132. #include <xercesc/util/Janitor.hpp>
  133. #include <xercesc/util/XMLUniDefs.hpp>
  134. XERCES_CPP_NAMESPACE_BEGIN
  135. HMODULE gWinsockLib = NULL;
  136. LPFN_GETHOSTBYNAME gWSgethostbyname = NULL;
  137. LPFN_INET_ADDR gWSinet_addr = NULL;
  138. LPFN_GETHOSTBYADDR gWSgethostbyaddr = NULL;
  139. LPFN_HTONS gWShtons = NULL;
  140. LPFN_SOCKET gWSsocket = NULL;
  141. LPFN_CONNECT gWSconnect = NULL;
  142. LPFN_SEND gWSsend = NULL;
  143. LPFN_RECV gWSrecv = NULL;
  144. LPFN_SHUTDOWN gWSshutdown = NULL;
  145. LPFN_CLOSESOCKET gWSclosesocket = NULL;
  146. LPFN_WSACLEANUP gWSACleanup = NULL;
  147. bool BinHTTPURLInputStream::fInitialized = false;
  148. XMLMutex* BinHTTPURLInputStream::fInitMutex = 0;
  149. void BinHTTPURLInputStream::Initialize() {
  150.     //
  151.     // Initialize the WinSock library here.
  152.     //
  153.     WORD        wVersionRequested;
  154.     WSADATA     wsaData;
  155. LPFN_WSASTARTUP startup = NULL;
  156. if(gWinsockLib == NULL) {
  157. gWinsockLib = LoadLibrary(_T("WSOCK32"));
  158. if(gWinsockLib == NULL) {
  159. ThrowXML(NetAccessorException, XMLExcepts::NetAcc_InitFailed);
  160. }
  161. else {
  162. startup = (LPFN_WSASTARTUP) GetProcAddress(gWinsockLib,_T("WSAStartup"));
  163. gWSACleanup = (LPFN_WSACLEANUP) GetProcAddress(gWinsockLib,_T("WSACleanup"));
  164. gWSgethostbyname = (LPFN_GETHOSTBYNAME) GetProcAddress(gWinsockLib,_T("gethostbyname"));
  165. gWSinet_addr = (LPFN_INET_ADDR) GetProcAddress(gWinsockLib,_T("inet_addr"));
  166. gWSgethostbyaddr = (LPFN_GETHOSTBYADDR) GetProcAddress(gWinsockLib,_T("gethostbyaddr"));
  167. gWShtons = (LPFN_HTONS) GetProcAddress(gWinsockLib,_T("htons"));
  168. gWSsocket = (LPFN_SOCKET) GetProcAddress(gWinsockLib,_T("socket"));
  169. gWSconnect = (LPFN_CONNECT) GetProcAddress(gWinsockLib,_T("connect"));
  170. gWSsend = (LPFN_SEND) GetProcAddress(gWinsockLib,_T("send"));
  171. gWSrecv = (LPFN_RECV) GetProcAddress(gWinsockLib,_T("recv"));
  172. gWSshutdown = (LPFN_SHUTDOWN) GetProcAddress(gWinsockLib,_T("shutdown"));
  173. gWSclosesocket = (LPFN_CLOSESOCKET) GetProcAddress(gWinsockLib,_T("closesocket"));
  174. if(startup == NULL ||
  175. gWSACleanup == NULL ||
  176. gWSgethostbyname == NULL ||
  177. gWSinet_addr == NULL ||
  178. gWSgethostbyaddr == NULL ||
  179. gWShtons == NULL ||
  180. gWSsocket == NULL ||
  181. gWSconnect == NULL ||
  182. gWSsend == NULL ||
  183. gWSrecv == NULL ||
  184. gWSshutdown == NULL ||
  185. gWSclosesocket == NULL)
  186. {
  187. gWSACleanup = NULL;
  188. Cleanup();
  189. ThrowXML(NetAccessorException, XMLExcepts::NetAcc_InitFailed);
  190. }
  191. }
  192. }
  193.     wVersionRequested = MAKEWORD( 2, 2 );
  194.     int err = (*startup)(wVersionRequested, &wsaData);
  195.     if (err != 0)
  196.     {
  197.         // Call WSAGetLastError() to get the last error.
  198.         ThrowXML(NetAccessorException, XMLExcepts::NetAcc_InitFailed);
  199.     }
  200.     fInitialized = true;
  201. }
  202. void BinHTTPURLInputStream::Cleanup() {
  203. if(fInitialized)
  204. {
  205. if(gWSACleanup) (*gWSACleanup)();
  206. gWSACleanup = NULL;
  207. FreeLibrary(gWinsockLib);
  208. gWinsockLib = NULL;
  209. gWSgethostbyname = NULL;
  210. gWSinet_addr = NULL;
  211. gWSgethostbyaddr = NULL;
  212. gWShtons = NULL;
  213. gWSsocket = NULL;
  214. gWSconnect = NULL;
  215. gWSsend = NULL;
  216. gWSrecv = NULL;
  217. gWSshutdown = NULL;
  218. gWSclosesocket = NULL;
  219.       fInitialized = false;
  220.       delete fInitMutex;
  221.       fInitMutex = 0;
  222. }
  223. }
  224. hostent* BinHTTPURLInputStream::gethostbyname(const char* name)
  225. {
  226. return (*gWSgethostbyname)(name);
  227. }
  228. unsigned long BinHTTPURLInputStream::inet_addr(const char* cp)
  229. {
  230. return (*gWSinet_addr)(cp);
  231. }
  232. hostent* BinHTTPURLInputStream::gethostbyaddr(const char* addr,int len,int type)
  233. {
  234. return (*gWSgethostbyaddr)(addr,len,type);
  235. }
  236. unsigned short BinHTTPURLInputStream::htons(unsigned short hostshort)
  237. {
  238. return (*gWShtons)(hostshort);
  239. }
  240. unsigned short BinHTTPURLInputStream::socket(int af,int type,int protocol)
  241. {
  242. return (*gWSsocket)(af,type,protocol);
  243. }
  244. int BinHTTPURLInputStream::connect(unsigned short s,const sockaddr* name,int namelen)
  245. {
  246. return (*gWSconnect)(s,name,namelen);
  247. }
  248. int BinHTTPURLInputStream::send(unsigned short s,const char* buf,int len,int flags)
  249. {
  250. return (*gWSsend)(s,buf,len,flags);
  251. }
  252. int BinHTTPURLInputStream::recv(unsigned short s,char* buf,int len,int flags)
  253. {
  254. return (*gWSrecv)(s,buf,len,flags);
  255. }
  256. int BinHTTPURLInputStream::shutdown(unsigned int s,int how)
  257. {
  258. return (*gWSshutdown)(s,how);
  259. }
  260. int BinHTTPURLInputStream::closesocket(unsigned int socket)
  261. {
  262. return (*gWSclosesocket)(socket);
  263. }
  264. BinHTTPURLInputStream::BinHTTPURLInputStream(const XMLURL& urlSource)
  265.       : fSocketHandle(0)
  266.       , fBytesProcessed(0)
  267. {
  268.     if(!fInitialized)
  269.     {
  270.         if (!fInitMutex)
  271.         {
  272.             XMLMutex* tmpMutex = new XMLMutex;
  273.             if (XMLPlatformUtils::compareAndSwap((void**)&fInitMutex, tmpMutex, 0))
  274.             {
  275.                 // Someone beat us to it, so let's clean up ours
  276.                 delete tmpMutex;
  277.             }
  278.          }
  279.          XMLMutexLock lock(fInitMutex);
  280.          if (!fInitialized)
  281.          {
  282.              Initialize();
  283.          }
  284.     }
  285.     //
  286.     // Pull all of the parts of the URL out of th urlSource object, and transcode them
  287.     //   and transcode them back to ASCII.
  288.     //
  289.     const XMLCh*        hostName = urlSource.getHost();
  290.     char*               hostNameAsCharStar = XMLString::transcode(hostName, urlSource.getMemoryManager());
  291.     ArrayJanitor<char>  janBuf1(hostNameAsCharStar, urlSource.getMemoryManager());
  292.     const XMLCh*        path = urlSource.getPath();
  293.     char*               pathAsCharStar = XMLString::transcode(path, urlSource.getMemoryManager());
  294.     ArrayJanitor<char>  janBuf2(pathAsCharStar, urlSource.getMemoryManager());
  295.     const XMLCh*        fragment = urlSource.getFragment();
  296.     char*               fragmentAsCharStar = 0;
  297.     if (fragment)
  298.         fragmentAsCharStar = XMLString::transcode(fragment, urlSource.getMemoryManager());
  299.     ArrayJanitor<char>  janBuf3(fragmentAsCharStar, urlSource.getMemoryManager());
  300.     const XMLCh*        query = urlSource.getQuery();
  301.     char*               queryAsCharStar = 0;
  302.     if (query)
  303.         queryAsCharStar = XMLString::transcode(query, urlSource.getMemoryManager());
  304.     ArrayJanitor<char>  janBuf4(queryAsCharStar, urlSource.getMemoryManager());
  305.     unsigned short      portNumber = (unsigned short) urlSource.getPortNum();
  306.     //
  307.     // Set up a socket.
  308.     //
  309.     struct hostent*     hostEntPtr = 0;
  310.     struct sockaddr_in  sa;
  311.     if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL)
  312.     {
  313.         unsigned long  numAddress = inet_addr(hostNameAsCharStar);
  314.         if (numAddress == INADDR_NONE)
  315.         {
  316.             // Call WSAGetLastError() to get the error number.
  317.             ThrowXML1(NetAccessorException,
  318.                      XMLExcepts::NetAcc_TargetResolution, hostName);
  319.         }
  320.         if ((hostEntPtr =
  321.                 gethostbyaddr((const char *) &numAddress,
  322.                               sizeof(unsigned long), AF_INET)) == NULL)
  323.         {
  324.             // Call WSAGetLastError() to get the error number.
  325.             ThrowXML1(NetAccessorException,
  326.                      XMLExcepts::NetAcc_TargetResolution, hostName);
  327.         }
  328.     }
  329.     memcpy((void *) &sa.sin_addr,
  330.            (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
  331.     sa.sin_family = hostEntPtr->h_addrtype;
  332.     sa.sin_port = htons(portNumber);
  333.     SOCKET s = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
  334.     if (s == INVALID_SOCKET)
  335.     {
  336.         // Call WSAGetLastError() to get the error number.
  337.         ThrowXML1(NetAccessorException,
  338.                  XMLExcepts::NetAcc_CreateSocket, urlSource.getURLText());
  339.     }
  340.     if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) == SOCKET_ERROR)
  341.     {
  342.         // Call WSAGetLastError() to get the error number.
  343.         ThrowXML1(NetAccessorException,
  344.                  XMLExcepts::NetAcc_ConnSocket, urlSource.getURLText());
  345.     }
  346.     // Set a flag so we know that the headers have not been read yet.
  347.     bool fHeaderRead = false;
  348.     // The port is open and ready to go.
  349.     // Build up the http GET command to send to the server.
  350.     // To do:  We should really support http 1.1.  This implementation
  351.     //         is weak.
  352.     memset(fBuffer, 0, sizeof(fBuffer));
  353.     strcpy(fBuffer, "GET ");
  354.     strcat(fBuffer, pathAsCharStar);
  355.     if (queryAsCharStar != 0)
  356.     {
  357.         // Tack on a ? before the fragment
  358.         strcat(fBuffer,"?");
  359.         strcat(fBuffer, queryAsCharStar);
  360.     }
  361.     if (fragmentAsCharStar != 0)
  362.     {
  363.         strcat(fBuffer, fragmentAsCharStar);
  364.     }
  365.     strcat(fBuffer, " HTTP/1.0rn");
  366.     strcat(fBuffer, "Host: ");
  367.     strcat(fBuffer, hostNameAsCharStar);
  368.     if (portNumber != 80)
  369.     {
  370.         strcat(fBuffer, ":");
  371.         int i = strlen(fBuffer);
  372.         _itoa(portNumber, fBuffer+i, 10);
  373.     }
  374.     strcat(fBuffer, "rnrn");
  375.     // Send the http request
  376.     int lent = strlen(fBuffer);
  377.     int  aLent = 0;
  378.     if ((aLent = send(s, fBuffer, lent, 0)) != lent)
  379.     {
  380.         // Call WSAGetLastError() to get the error number.
  381.         ThrowXML1(NetAccessorException,
  382.                  XMLExcepts::NetAcc_WriteSocket, urlSource.getURLText());
  383.     }
  384.     //
  385.     // get the response, check the http header for errors from the server.
  386.     //
  387.     memset(fBuffer, 0, sizeof(fBuffer));
  388.     aLent = recv(s, fBuffer, sizeof(fBuffer)-1, 0);
  389.     if (aLent == SOCKET_ERROR || aLent == 0)
  390.     {
  391.         // Call WSAGetLastError() to get the error number.
  392.         ThrowXML1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText());
  393.     }
  394.     fBufferEnd = fBuffer+aLent;
  395.     *fBufferEnd = 0;
  396.     do {
  397.         // Find the break between the returned http header and any data.
  398.         //  (Delimited by a blank line)
  399.         // Hang on to any data for use by the first read from this BinHTTPURLInputStream.
  400.         //
  401.         fBufferPos = strstr(fBuffer, "rnrn");
  402.         if (fBufferPos != 0)
  403.         {
  404.             fBufferPos += 4;
  405.             *(fBufferPos-2) = 0;
  406.             fHeaderRead = true;
  407.         }
  408.         else
  409.         {
  410.             fBufferPos = strstr(fBuffer, "nn");
  411.             if (fBufferPos != 0)
  412.             {
  413.                 fBufferPos += 2;
  414.                 *(fBufferPos-1) = 0;
  415.                 fHeaderRead = true;
  416.             }
  417.             else
  418.             {
  419.                 //
  420.                 // Header is not yet read, do another recv() to get more data...
  421.                 aLent = recv(s, fBufferEnd, (sizeof(fBuffer) - 1) - (fBufferEnd - fBuffer), 0);
  422.                 if (aLent == SOCKET_ERROR || aLent == 0)
  423.                 {
  424.                     // Call WSAGetLastError() to get the error number.
  425.                     ThrowXML1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText());
  426.                 }
  427.                 fBufferEnd = fBufferEnd + aLent;
  428.                 *fBufferEnd = 0;
  429.             }
  430.         }
  431.     } while(fHeaderRead == false);
  432.     // Make sure the header includes an HTTP 200 OK response.
  433.     //
  434.     char *p = strstr(fBuffer, "HTTP");
  435.     if (p == 0)
  436.     {
  437.         ThrowXML1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText());
  438.     }
  439.     p = strchr(p, ' ');
  440.     if (p == 0)
  441.     {
  442.         ThrowXML1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText());
  443.     }
  444.     int httpResponse = atoi(p);
  445.     if (httpResponse != 200)
  446.     {
  447.         // Most likely a 404 Not Found error.
  448.         //   Should recognize and handle the forwarding responses.
  449.         //
  450.         ThrowXML1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, urlSource.getURLText());
  451.     }
  452.     fSocketHandle = (unsigned int) s;
  453. }
  454. BinHTTPURLInputStream::~BinHTTPURLInputStream()
  455. {
  456.     shutdown(fSocketHandle, SD_BOTH);
  457.     closesocket(fSocketHandle);
  458. }
  459. //
  460. //  readBytes
  461. //
  462. unsigned int BinHTTPURLInputStream::readBytes(XMLByte* const    toFill
  463.                                     , const unsigned int    maxToRead)
  464. {
  465.     unsigned int len = fBufferEnd - fBufferPos;
  466.     if (len > 0)
  467.     {
  468.         // If there's any data left over in the buffer into which we first
  469.         //   read from the server (to get the http header), return that.
  470.         if (len > maxToRead)
  471.             len = maxToRead;
  472.         memcpy(toFill, fBufferPos, len);
  473.         fBufferPos += len;
  474.     }
  475.     else
  476.     {
  477.         // There was no data in the local buffer.
  478.         // Read some from the socket, straight into our caller's buffer.
  479.         //
  480.         len = recv((SOCKET) fSocketHandle, (char *) toFill, maxToRead, 0);
  481.         if (len == SOCKET_ERROR)
  482.         {
  483.             // Call WSAGetLastError() to get the error number.
  484.             ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
  485.         }
  486.     }
  487.     fBytesProcessed += len;
  488.     return len;
  489. }
  490. XERCES_CPP_NAMESPACE_END