GME  13
UnixHTTPURLInputStream.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: UnixHTTPURLInputStream.cpp 936316 2010-04-21 14:19:58Z borisk $
00020  */
00021 
00022 #if HAVE_CONFIG_H
00023 #  include <config.h>
00024 #endif
00025 
00026 #include <string.h>
00027 
00028 #if HAVE_UNISTD_H
00029 #  include <unistd.h>
00030 #endif
00031 #if HAVE_SYS_TYPES_H
00032 #  include <sys/types.h>
00033 #endif
00034 #if HAVE_SYS_SOCKET_H
00035 #  include <sys/socket.h>
00036 #endif
00037 #if HAVE_NETINET_IN_H
00038 #  include <netinet/in.h>
00039 #endif
00040 #if HAVE_ARPA_INET_H
00041 #  include <arpa/inet.h>
00042 #endif
00043 #if HAVE_NETDB_H
00044 #  include <netdb.h>
00045 #endif
00046 #include <errno.h>
00047 
00048 #include <xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp>
00049 #include <xercesc/util/XMLString.hpp>
00050 #include <xercesc/util/XMLExceptMsgs.hpp>
00051 #include <xercesc/util/Janitor.hpp>
00052 
00053 XERCES_CPP_NAMESPACE_BEGIN
00054 
00055 class SocketJanitor
00056 {
00057 public:
00058     // -----------------------------------------------------------------------
00059     //  Constructors and Destructor
00060     // -----------------------------------------------------------------------
00061     SocketJanitor(int* toDelete) : fData(toDelete) {}
00062     ~SocketJanitor() { reset(); }
00063 
00064     int* get() const { return fData; }
00065     int* release() { int* p = fData; fData = 0; return p; }
00066 
00067     void reset(int* p = 0)
00068     {
00069         if(fData) {
00070             shutdown(*fData, 2);
00071             close(*fData);
00072         }
00073         fData = p;
00074     }
00075     bool isDataNull() { return (fData == 0); }
00076 
00077 private :
00078     // -----------------------------------------------------------------------
00079     //  Unimplemented constructors and operators
00080     // -----------------------------------------------------------------------
00081     SocketJanitor();
00082     SocketJanitor(const SocketJanitor&);
00083     SocketJanitor& operator=(const SocketJanitor&);
00084 
00085     // -----------------------------------------------------------------------
00086     //  Private data members
00087     //
00088     //  fData
00089     //      This is the pointer to the socket that must be closed when
00090     //      this object is destroyed.
00091     // -----------------------------------------------------------------------
00092     int*  fData;
00093 };
00094 
00095 UnixHTTPURLInputStream::UnixHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/)
00096     : BinHTTPInputStreamCommon(urlSource.getMemoryManager()),
00097       fSocket(0)
00098 {
00099     //
00100     //  Convert the hostName to the platform's code page for gethostbyname and
00101     //  inet_addr functions.
00102     //
00103 
00104     MemoryManager *memoryManager = urlSource.getMemoryManager();
00105 
00106     const XMLCh*        hostName = urlSource.getHost();
00107 
00108     if (hostName == 0)
00109       ThrowXMLwithMemMgr1(NetAccessorException,
00110                           XMLExcepts::File_CouldNotOpenFile,
00111                           urlSource.getURLText(),
00112                           memoryManager);
00113 
00114     char*               hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
00115     ArrayJanitor<char>  janHostNameAsCharStar(hostNameAsCharStar, memoryManager);
00116 
00117     XMLURL url(urlSource);
00118     int redirectCount = 0;
00119     SocketJanitor janSock(0);
00120 
00121     do {
00122         //
00123         // Set up a socket.
00124         //
00125 
00126 #if HAVE_GETADDRINFO
00127         struct addrinfo hints, *res, *ai;
00128 
00129         CharBuffer portBuffer(10, memoryManager);
00130         portBuffer.appendDecimalNumber(url.getPortNum());
00131 
00132         memset(&hints, 0, sizeof(struct addrinfo));
00133         hints.ai_family = PF_UNSPEC;
00134         hints.ai_socktype = SOCK_STREAM;
00135         int n = getaddrinfo(hostNameAsCharStar,portBuffer.getRawBuffer(),&hints, &res);
00136         if(n != 0)
00137         {
00138             hints.ai_flags = AI_NUMERICHOST;
00139             n = getaddrinfo(hostNameAsCharStar,portBuffer.getRawBuffer(),&hints, &res);
00140             if(n != 0)
00141                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
00142         }
00143         janSock.reset();
00144         for (ai = res; ai != NULL; ai = ai->ai_next) {
00145             // Open a socket with the correct address family for this address.
00146             fSocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
00147             if (fSocket < 0)
00148                 continue;
00149             janSock.reset(&fSocket);
00150             if (connect(fSocket, ai->ai_addr, ai->ai_addrlen) < 0)
00151             {
00152                 freeaddrinfo(res);
00153                 ThrowXMLwithMemMgr1(NetAccessorException,
00154                          XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
00155             }
00156             break;
00157         }
00158         freeaddrinfo(res);
00159         if (fSocket < 0)
00160         {
00161             ThrowXMLwithMemMgr1(NetAccessorException,
00162                      XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
00163         }
00164 #else
00165         struct hostent *hostEntPtr = 0;
00166         struct sockaddr_in sa;
00167 
00168         // Use the hostName in the local code page ....
00169         if((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL)
00170         {
00171             unsigned long  numAddress = inet_addr(hostNameAsCharStar);
00172             if ((hostEntPtr =
00173                     gethostbyaddr((char *) &numAddress,
00174                         sizeof(unsigned long), AF_INET)) == NULL)
00175             {
00176                 ThrowXMLwithMemMgr1(NetAccessorException,
00177                     XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
00178             }
00179         }
00180 
00181         memset(&sa, '\0', sizeof(sockaddr_in));  // iSeries fix ??
00182         memcpy((void *) &sa.sin_addr,
00183             (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
00184         sa.sin_family = hostEntPtr->h_addrtype;
00185         sa.sin_port = htons((unsigned short)url.getPortNum());
00186 
00187         janSock.reset();
00188         fSocket = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
00189         if(fSocket < 0)
00190         {
00191             ThrowXMLwithMemMgr1(NetAccessorException,
00192                 XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
00193         }
00194         janSock.reset(&fSocket);
00195 
00196         if(connect(fSocket, (struct sockaddr *) &sa, sizeof(sa)) < 0)
00197         {
00198             ThrowXMLwithMemMgr1(NetAccessorException,
00199                 XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
00200         }
00201 #endif
00202 
00203         int status = sendRequest(url, httpInfo);
00204 
00205         if(status == 200) {
00206             // HTTP 200 OK response means we're done.
00207             break;
00208         }
00209         // a 3xx response means there was an HTTP redirect
00210         else if(status >= 300 && status <= 307) {
00211             redirectCount++;
00212 
00213             XMLCh *newURLString = findHeader("Location");
00214             ArrayJanitor<XMLCh> janNewURLString(newURLString, memoryManager);
00215 
00216             if(newURLString == 0 || *newURLString == 0) {
00217                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
00218             }
00219 
00220             XMLURL newURL(memoryManager);
00221             newURL.setURL(url, newURLString);
00222             if(newURL.getProtocol() != XMLURL::HTTP) {
00223                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, newURL.getURLText(), memoryManager);
00224             }
00225 
00226             url = newURL;
00227             hostName = newURL.getHost();
00228 
00229             if (hostName == 0)
00230               ThrowXMLwithMemMgr1(NetAccessorException,
00231                                   XMLExcepts::File_CouldNotOpenFile,
00232                                   newURL.getURLText(),
00233                                   memoryManager);
00234 
00235             janHostNameAsCharStar.release();
00236             hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
00237             janHostNameAsCharStar.reset(hostNameAsCharStar, memoryManager);
00238         }
00239         else {
00240             // Most likely a 404 Not Found error.
00241             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
00242         }
00243     } while(redirectCount < 6);
00244 
00245     janSock.release();
00246 }
00247 
00248 
00249 UnixHTTPURLInputStream::~UnixHTTPURLInputStream()
00250 {
00251     shutdown(fSocket, 2);
00252     close(fSocket);
00253 }
00254 
00255 bool UnixHTTPURLInputStream::send(const char *buf, XMLSize_t len)
00256 {
00257     XMLSize_t done = 0;
00258     int ret;
00259 
00260     while(done < len) {
00261         ret = ::send(fSocket, buf + done, len - done, 0);
00262         if(ret == -1) return false;
00263         done += ret;
00264     }
00265 
00266     return true;
00267 }
00268 
00269 int UnixHTTPURLInputStream::receive(char *buf, XMLSize_t len)
00270 {
00271     return ::recv(fSocket, buf, len, 0);
00272 }
00273 
00274 XERCES_CPP_NAMESPACE_END