source: icXML/icXML-devel/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 8.8 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: UnixHTTPURLInputStream.cpp 936316 2010-04-21 14:19:58Z borisk $
20 */
21
22#if HAVE_CONFIG_H
23#  include <config.h>
24#endif
25
26#include <string.h>
27
28#if HAVE_UNISTD_H
29#  include <unistd.h>
30#endif
31#if HAVE_SYS_TYPES_H
32#  include <sys/types.h>
33#endif
34#if HAVE_SYS_SOCKET_H
35#  include <sys/socket.h>
36#endif
37#if HAVE_NETINET_IN_H
38#  include <netinet/in.h>
39#endif
40#if HAVE_ARPA_INET_H
41#  include <arpa/inet.h>
42#endif
43#if HAVE_NETDB_H
44#  include <netdb.h>
45#endif
46#include <errno.h>
47
48#include <xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp>
49#include <icxercesc/util/XMLString.hpp>
50#include <xercesc/util/XMLExceptMsgs.hpp>
51#include <xercesc/util/Janitor.hpp>
52
53XERCES_CPP_NAMESPACE_BEGIN
54
55class SocketJanitor
56{
57public:
58    // -----------------------------------------------------------------------
59    //  Constructors and Destructor
60    // -----------------------------------------------------------------------
61    SocketJanitor(int* toDelete) : fData(toDelete) {}
62    ~SocketJanitor() { reset(); }
63
64    int* get() const { return fData; }
65    int* release() { int* p = fData; fData = 0; return p; }
66
67    void reset(int* p = 0)
68    {
69        if(fData) {
70            shutdown(*fData, 2);
71            close(*fData);
72        }
73        fData = p;
74    }
75    bool isDataNull() { return (fData == 0); }
76
77private :
78    // -----------------------------------------------------------------------
79    //  Unimplemented constructors and operators
80    // -----------------------------------------------------------------------
81    SocketJanitor();
82    SocketJanitor(const SocketJanitor&);
83    SocketJanitor& operator=(const SocketJanitor&);
84
85    // -----------------------------------------------------------------------
86    //  Private data members
87    //
88    //  fData
89    //      This is the pointer to the socket that must be closed when
90    //      this object is destroyed.
91    // -----------------------------------------------------------------------
92    int*  fData;
93};
94
95UnixHTTPURLInputStream::UnixHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/)
96    : BinHTTPInputStreamCommon(urlSource.getMemoryManager()),
97      fSocket(0)
98{
99    //
100    //  Convert the hostName to the platform's code page for gethostbyname and
101    //  inet_addr functions.
102    //
103
104    MemoryManager *memoryManager = urlSource.getMemoryManager();
105
106    const XMLCh*        hostName = urlSource.getHost();
107
108    if (hostName == 0)
109      ThrowXMLwithMemMgr1(NetAccessorException,
110                          XMLExcepts::File_CouldNotOpenFile,
111                          urlSource.getURLText(),
112                          memoryManager);
113
114    char*               hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
115    ArrayJanitor<char>  janHostNameAsCharStar(hostNameAsCharStar, memoryManager);
116
117    XMLURL url(urlSource);
118    int redirectCount = 0;
119    SocketJanitor janSock(0);
120
121    do {
122        //
123        // Set up a socket.
124        //
125
126#if HAVE_GETADDRINFO
127        struct addrinfo hints, *res, *ai;
128
129        CharBuffer portBuffer(10, memoryManager);
130        portBuffer.appendDecimalNumber(url.getPortNum());
131
132        memset(&hints, 0, sizeof(struct addrinfo));
133        hints.ai_family = PF_UNSPEC;
134        hints.ai_socktype = SOCK_STREAM;
135        int n = getaddrinfo(hostNameAsCharStar,portBuffer.getRawBuffer(),&hints, &res);
136        if(n != 0)
137        {
138            hints.ai_flags = AI_NUMERICHOST;
139            n = getaddrinfo(hostNameAsCharStar,portBuffer.getRawBuffer(),&hints, &res);
140            if(n != 0)
141                ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
142        }
143        janSock.reset();
144        for (ai = res; ai != NULL; ai = ai->ai_next) {
145            // Open a socket with the correct address family for this address.
146            fSocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
147            if (fSocket < 0)
148                continue;
149            janSock.reset(&fSocket);
150            if (connect(fSocket, ai->ai_addr, ai->ai_addrlen) < 0)
151            {
152                freeaddrinfo(res);
153                ThrowXMLwithMemMgr1(NetAccessorException,
154                         XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
155            }
156            break;
157        }
158        freeaddrinfo(res);
159        if (fSocket < 0)
160        {
161            ThrowXMLwithMemMgr1(NetAccessorException,
162                     XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
163        }
164#else
165        struct hostent *hostEntPtr = 0;
166        struct sockaddr_in sa;
167
168        // Use the hostName in the local code page ....
169        if((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL)
170        {
171            unsigned long  numAddress = inet_addr(hostNameAsCharStar);
172            if ((hostEntPtr =
173                    gethostbyaddr((char *) &numAddress,
174                        sizeof(unsigned long), AF_INET)) == NULL)
175            {
176                ThrowXMLwithMemMgr1(NetAccessorException,
177                    XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
178            }
179        }
180
181        memset(&sa, '\0', sizeof(sockaddr_in));  // iSeries fix ??
182        memcpy((void *) &sa.sin_addr,
183            (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
184        sa.sin_family = hostEntPtr->h_addrtype;
185        sa.sin_port = htons((unsigned short)url.getPortNum());
186
187        janSock.reset();
188        fSocket = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
189        if(fSocket < 0)
190        {
191            ThrowXMLwithMemMgr1(NetAccessorException,
192                XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
193        }
194        janSock.reset(&fSocket);
195
196        if(connect(fSocket, (struct sockaddr *) &sa, sizeof(sa)) < 0)
197        {
198            ThrowXMLwithMemMgr1(NetAccessorException,
199                XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
200        }
201#endif
202
203        int status = sendRequest(url, httpInfo);
204
205        if(status == 200) {
206            // HTTP 200 OK response means we're done.
207            break;
208        }
209        // a 3xx response means there was an HTTP redirect
210        else if(status >= 300 && status <= 307) {
211            redirectCount++;
212
213            XMLCh *newURLString = findHeader("Location");
214            ArrayJanitor<XMLCh> janNewURLString(newURLString, memoryManager);
215
216            if(newURLString == 0 || *newURLString == 0) {
217                ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
218            }
219
220            XMLURL newURL(memoryManager);
221            newURL.setURL(url, newURLString);
222            if(newURL.getProtocol() != XMLURL::HTTP) {
223                ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, newURL.getURLText(), memoryManager);
224            }
225
226            url = newURL;
227            hostName = newURL.getHost();
228
229            if (hostName == 0)
230              ThrowXMLwithMemMgr1(NetAccessorException,
231                                  XMLExcepts::File_CouldNotOpenFile,
232                                  newURL.getURLText(),
233                                  memoryManager);
234
235            janHostNameAsCharStar.release();
236            hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
237            janHostNameAsCharStar.reset(hostNameAsCharStar, memoryManager);
238        }
239        else {
240            // Most likely a 404 Not Found error.
241            ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
242        }
243    } while(redirectCount < 6);
244
245    janSock.release();
246}
247
248
249UnixHTTPURLInputStream::~UnixHTTPURLInputStream()
250{
251    shutdown(fSocket, 2);
252    close(fSocket);
253}
254
255bool UnixHTTPURLInputStream::send(const char *buf, XMLSize_t len)
256{
257    XMLSize_t done = 0;
258    int ret;
259
260    while(done < len) {
261        ret = ::send(fSocket, buf + done, len - done, 0);
262        if(ret == -1) return false;
263        done += ret;
264    }
265
266    return true;
267}
268
269int UnixHTTPURLInputStream::receive(char *buf, XMLSize_t len)
270{
271    return ::recv(fSocket, buf, len, 0);
272}
273
274XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.