Xerces 3 revisions.
[shibboleth/cpp-xmltooling.git] / xmltooling / util / CurlURLInputStream.cpp
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$
20  */
21
22 #include "internal.h"
23
24 #include <curl/curl.h>
25
26 #include <xercesc/util/XercesDefs.hpp>
27 #include <xercesc/util/XMLNetAccessor.hpp>
28 #include <xercesc/util/XMLString.hpp>
29 #include <xercesc/util/XMLExceptMsgs.hpp>
30 #include <xercesc/util/Janitor.hpp>
31 #include <xercesc/util/XMLUniDefs.hpp>
32 #include <xercesc/util/TransService.hpp>
33 #include <xercesc/util/TranscodingException.hpp>
34 #include <xercesc/util/PlatformUtils.hpp>
35
36 #include <xmltooling/util/CurlURLInputStream.hpp>
37
38 using namespace xmltooling;
39 using namespace xercesc;
40
41 CurlURLInputStream::CurlURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/)
42       : fMemoryManager(urlSource.getMemoryManager())
43       , fURLSource(urlSource)
44       , fURL(0)
45       , fInputStream(NULL)
46       , m_log(logging::Category::getInstance(XMLTOOLING_LOGCAT".libcurl.NetAccessor"))
47 {
48         // Get the text of the URL we're going to use
49         fURL.reset(XMLString::transcode(fURLSource.getURLText(), fMemoryManager), fMemoryManager);
50 }
51
52
53 CurlURLInputStream::~CurlURLInputStream()
54 {
55     delete fInputStream;
56 }
57
58
59 size_t CurlURLInputStream::staticWriteCallback(void* ptr, size_t size, size_t nmemb, void* stream)
60 {
61     size_t len = size*nmemb;
62     reinterpret_cast<std::stringstream*>(stream)->write(reinterpret_cast<const char*>(ptr),len);
63     return len;
64 }
65
66
67 xsecsize_t CurlURLInputStream::readBytes(XMLByte* const toFill, const xsecsize_t maxToRead)
68 {
69     if (!fInputStream) {
70         // Allocate the curl easy handle.
71         CURL* fEasy = curl_easy_init();
72         if (!fEasy)
73             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_InternalError, "unable to allocate libcurl handle", fMemoryManager);
74
75         m_log.debug("libcurl trying to fetch %s", fURL.get());
76
77         // Set URL option
78         curl_easy_setopt(fEasy, CURLOPT_URL, fURL.get());
79         curl_easy_setopt(fEasy, CURLOPT_WRITEDATA, &fUnderlyingStream);
80         curl_easy_setopt(fEasy, CURLOPT_WRITEFUNCTION, staticWriteCallback);
81         curl_easy_setopt(fEasy, CURLOPT_CONNECTTIMEOUT, 30);
82         curl_easy_setopt(fEasy, CURLOPT_TIMEOUT, 60);
83         curl_easy_setopt(fEasy, CURLOPT_SSL_VERIFYHOST, 0);
84         curl_easy_setopt(fEasy, CURLOPT_SSL_VERIFYPEER, 0);
85         curl_easy_setopt(fEasy, CURLOPT_NOPROGRESS, 1);
86         curl_easy_setopt(fEasy, CURLOPT_NOSIGNAL, 1);
87         curl_easy_setopt(fEasy, CURLOPT_FAILONERROR, 1);
88
89         char curl_errorbuf[CURL_ERROR_SIZE];
90         curl_errorbuf[0]=0;
91         curl_easy_setopt(fEasy,CURLOPT_ERRORBUFFER,curl_errorbuf);
92
93         // Fetch the data.
94         if (curl_easy_perform(fEasy) != CURLE_OK) {
95             curl_easy_cleanup(fEasy);
96             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_InternalError, curl_errorbuf, fMemoryManager);
97         }
98
99         curl_easy_cleanup(fEasy);
100
101         /*
102         switch (msg->data.result)
103         {
104         case CURLE_OK:
105             // We completed successfully. runningHandles should have dropped to zero, so we'll bail out below...
106             break;
107
108         case CURLE_UNSUPPORTED_PROTOCOL:
109             ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_UnsupportedProto, fMemoryManager);
110             break;
111
112         case CURLE_COULDNT_RESOLVE_HOST:
113         case CURLE_COULDNT_RESOLVE_PROXY:
114             ThrowXMLwithMemMgr1(NetAccessorException,  XMLExcepts::NetAcc_TargetResolution, fURLSource.getHost(), fMemoryManager);
115             break;
116
117         case CURLE_COULDNT_CONNECT:
118             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ConnSocket, fURLSource.getURLText(), fMemoryManager);
119
120         case CURLE_RECV_ERROR:
121             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, fURLSource.getURLText(), fMemoryManager);
122             break;
123
124         default:
125             m_log.error("curl NetAccessor encountered error from libcurl (%d)", msg->data.result);
126             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_InternalError, fURLSource.getURLText(), fMemoryManager);
127             break;
128         }
129         */
130
131         fInputStream = new (fMemoryManager) StreamInputSource::StreamBinInputStream(fUnderlyingStream);
132     }
133
134     // Defer to the stream wrapper.
135     return fInputStream->readBytes(toFill, maxToRead);
136 }