Mercurial > trustbridge
comparison ui/sslconnection_curl.cpp @ 910:eaed02defe6a
More SSLConnection refactoring. Fixes curl downloader.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 18 Aug 2014 18:51:33 +0200 |
parents | d1c951b3012d |
children | a55c6cf54365 |
comparison
equal
deleted
inserted
replaced
909:18e3ad073b38 | 910:eaed02defe6a |
---|---|
5 * and comes with ABSOLUTELY NO WARRANTY! | 5 * and comes with ABSOLUTELY NO WARRANTY! |
6 * See LICENSE.txt for details. | 6 * See LICENSE.txt for details. |
7 */ | 7 */ |
8 | 8 |
9 #include "sslconnection_curl.h" | 9 #include "sslconnection_curl.h" |
10 #include <QSaveFile> | |
10 | 11 |
11 #define CONNECTION_DEBUG | 12 #define CONNECTION_DEBUG |
13 | |
14 /**@def Wrapper macro around curl_easy_setopt invocation */ | |
15 #define CURL_SETOPT(x, y, z) \ | |
16 if (curl_easy_setopt(mCurl, x, y) != CURLE_OK) { \ | |
17 qDebug() << "Setopt failed"; \ | |
18 z; \ | |
19 } | |
12 | 20 |
13 SSLConnectionCurl::SSLConnectionCurl(const QString& url, | 21 SSLConnectionCurl::SSLConnectionCurl(const QString& url, |
14 const QByteArray& certificate): | 22 const QByteArray& certificate): |
15 SSLConnection (url, certificate), | 23 SSLConnection (url, certificate), |
16 mCurl (NULL) | 24 mCurl (NULL) |
21 if (!mCurl) { | 29 if (!mCurl) { |
22 qDebug() << "Failed to initialize curl"; | 30 qDebug() << "Failed to initialize curl"; |
23 return; | 31 return; |
24 } | 32 } |
25 | 33 |
26 if (curl_easy_setopt(mCurl, CURLOPT_URL, QUrl(url).toEncoded().constData()) != CURLE_OK) { | |
27 qDebug() << "Setting url failed"; | |
28 return; | |
29 } | |
30 | |
31 if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 1L) != CURLE_OK) { | 34 if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 1L) != CURLE_OK) { |
32 /* Should be default anyway */ | 35 /* Should be default anyway */ |
33 qDebug() << "Setting verifypeer failed"; | 36 qDebug() << "Setting verifypeer failed"; |
34 return; | 37 return; |
35 } | 38 } |
38 /* There are no limitiations for the pinned certificate */ | 41 /* There are no limitiations for the pinned certificate */ |
39 qDebug() << "Setting verifyhost failed"; | 42 qDebug() << "Setting verifyhost failed"; |
40 return; | 43 return; |
41 } | 44 } |
42 | 45 |
46 if (curl_easy_setopt(mCurl, CURLOPT_ERRORBUFFER, mErrBuf) != CURLE_OK) { | |
47 qDebug() << "Setting errorbuf failed"; | |
48 return; | |
49 } | |
50 | |
43 mCertFile.open(); | 51 mCertFile.open(); |
44 if (mCertFile.write(mPinnedCert) != mPinnedCert.size()) { | 52 if (mCertFile.write(mPinnedCert) != mPinnedCert.size()) { |
45 qDebug() << "Failed to write temporary certificate"; | 53 qDebug() << "Failed to write temporary certificate"; |
46 return; | 54 return; |
47 } | 55 } |
68 } | 76 } |
69 curl_global_cleanup(); | 77 curl_global_cleanup(); |
70 } | 78 } |
71 | 79 |
72 int SSLConnectionCurl::connect() { | 80 int SSLConnectionCurl::connect() { |
81 CURLcode retval; | |
82 | |
83 if (curl_easy_setopt(mCurl, CURLOPT_URL, mUrl.toEncoded().constData()) != CURLE_OK) { | |
84 qDebug() << "Failed to set URL"; | |
85 return -1; | |
86 } | |
87 | |
73 if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 1L) != CURLE_OK) { | 88 if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 1L) != CURLE_OK) { |
74 qDebug() << "Failed to set connect only option"; | 89 qDebug() << "Failed to set connect only option"; |
75 return -1; | 90 return -1; |
76 } | 91 } |
77 if (curl_easy_perform (mCurl) != CURLE_OK) { | 92 retval = curl_easy_perform(mCurl); |
78 qDebug() << "Failed to connect"; | 93 if (retval != CURLE_OK) { |
94 qDebug() << "Failed to connect: " << mErrBuf << " retval: " << retval; | |
95 if (retval == CURLE_PEER_FAILED_VERIFICATION) { | |
96 mErrorState = InvalidCertificate; | |
97 return -1; | |
98 } | |
99 | |
79 mErrorState = NoConnection; | 100 mErrorState = NoConnection; |
80 return -1; | 101 return -1; |
81 } | 102 } |
82 mConnected = true; | 103 mConnected = true; |
83 return 0; | 104 return 0; |
84 } | 105 } |
85 | 106 |
86 int SSLConnectionCurl::write(const QByteArray& request) { | 107 /* Globally do this as we can't pass this to the c function */ |
87 size_t written = 0; | 108 size_t ssl_curl_max_write, ssl_curl_written; |
88 | 109 |
89 if (curl_easy_send (mCurl, request.constData(), request.size(), &written) != CURLE_OK) { | 110 size_t write_data(void *ptr, size_t size, size_t nmemb, |
90 qDebug() << "Failed to send request"; | 111 QSaveFile *fp) |
91 return -1; | |
92 } | |
93 if (written != (size_t)request.size()) { | |
94 qDebug() << "Failed to write everything"; | |
95 return -1; | |
96 } | |
97 return 0; | |
98 } | |
99 | |
100 QByteArray SSLConnectionCurl::read(size_t len) | |
101 { | 112 { |
102 unsigned char buf[len]; | 113 qDebug() << "Writing size: " << size << " * " << nmemb; |
103 QByteArray retval(""); | 114 if (ssl_curl_max_write < ssl_curl_written) { |
104 CURLcode ret; | 115 qDebug() << "Aborting write. Too much data."; |
105 size_t read = 0; | 116 return 0; |
106 unsigned int tries = 0; | 117 } |
107 | 118 size_t written = fp->write((const char *)ptr, size * nmemb); |
108 do { | 119 if (written != size * nmemb) { |
109 memset (buf, 0, sizeof(buf)); | 120 qDebug() << "Failed to write data. Written: " << written |
110 ret = curl_easy_recv (mCurl, buf, len, &read); | 121 << " requested: " << size * nmemb; |
111 if (ret == CURLE_OK && read == 0) { | 122 return 0; |
112 return retval; | 123 } |
113 } | 124 ssl_curl_written += written; |
114 if (ret == CURLE_AGAIN) { | 125 return written; |
115 tries++; | 126 } |
116 continue; | 127 |
117 } | 128 bool SSLConnectionCurl::downloadFile(const QString &resource, |
118 if (ret != CURLE_OK) { | 129 const QString &fileName, |
119 qDebug() << "Read failed."; | 130 size_t maxSize) |
120 return QByteArray(); | 131 { |
121 } | 132 QSaveFile outputFile(fileName); |
122 if (len < (len - read)) { | 133 ssl_curl_written = 0; |
123 /* Should never happen if ssl_read behaves */ | 134 ssl_curl_max_write = maxSize; |
124 qDebug() << "integer overflow in polarSSLRead"; | 135 // Open / Create the file to write to. |
125 return QByteArray(); | 136 if (!outputFile.open(QIODevice::WriteOnly)) { |
126 } | 137 qDebug() << "Failed to open file"; |
127 | 138 return false; |
128 len -= read; | 139 } |
129 retval.append((const char *)buf, read); | 140 QUrl urlCopy = mUrl; |
130 } while (len > 0 && tries < 10); | 141 urlCopy.setPath(resource); |
131 | 142 |
132 return retval; | 143 if (curl_easy_setopt(mCurl, CURLOPT_URL, urlCopy.toEncoded().constData()) != CURLE_OK) { |
133 } | 144 qDebug() << "Failed to set URL"; |
145 return false; | |
146 } | |
147 | |
148 if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L) != CURLE_OK) { | |
149 qDebug() << "Failed to set connect"; | |
150 return false; | |
151 } | |
152 | |
153 if (curl_easy_setopt(mCurl, CURLOPT_HEADER, 0L) != CURLE_OK) { | |
154 qDebug() << "Failed to set header"; | |
155 return false; | |
156 } | |
157 | |
158 if (curl_easy_setopt(mCurl, CURLOPT_NOBODY, 0L) != CURLE_OK) { | |
159 qDebug() << "Failed to set no body"; | |
160 return false; | |
161 } | |
162 | |
163 if (curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, write_data) != CURLE_OK) { | |
164 qDebug() << "Failed to set write function"; | |
165 return false; | |
166 } | |
167 | |
168 if (curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, &outputFile) != CURLE_OK) { | |
169 qDebug() << "Failed to set write function"; | |
170 return false; | |
171 } | |
172 | |
173 if (curl_easy_perform (mCurl) != CURLE_OK) { | |
174 qDebug() << "Failed to perform download."; | |
175 return false; | |
176 } | |
177 | |
178 if (!outputFile.commit()) { | |
179 qDebug() << "Failed to commit data to filesystem."; | |
180 return false; | |
181 } | |
182 | |
183 return true; | |
184 } | |
185 | |
186 QDateTime SSLConnectionCurl::getLastModifiedHeader(const QString &resource) { | |
187 QUrl urlCopy = mUrl; | |
188 urlCopy.setPath(resource); | |
189 | |
190 if (curl_easy_setopt(mCurl, CURLOPT_URL, urlCopy.toEncoded().constData()) != CURLE_OK) { | |
191 qDebug() << "Failed to set URL"; | |
192 return QDateTime(); | |
193 } | |
194 | |
195 if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L) != CURLE_OK) { | |
196 qDebug() << "Failed to set connect"; | |
197 return QDateTime(); | |
198 } | |
199 | |
200 if (curl_easy_setopt(mCurl, CURLOPT_HEADER, 1L) != CURLE_OK) { | |
201 qDebug() << "Failed to set header"; | |
202 return QDateTime(); | |
203 } | |
204 | |
205 if (curl_easy_setopt(mCurl, CURLOPT_NOBODY, 1L) != CURLE_OK) { | |
206 qDebug() << "Failed to set no body"; | |
207 return QDateTime(); | |
208 } | |
209 | |
210 if (curl_easy_setopt(mCurl, CURLOPT_FILETIME, 1L) != CURLE_OK) { | |
211 qDebug() << "Failed to set filetime"; | |
212 return QDateTime(); | |
213 } | |
214 | |
215 if (curl_easy_perform (mCurl) != CURLE_OK) { | |
216 qDebug() << "Failed to perform last modified check."; | |
217 return QDateTime(); | |
218 } | |
219 long filetime = 0; | |
220 | |
221 if (curl_easy_getinfo (mCurl, CURLINFO_FILETIME, &filetime) != CURLE_OK) { | |
222 qDebug() << "Failed to get filetime"; | |
223 return QDateTime(); | |
224 } | |
225 | |
226 if (filetime == -1) { | |
227 qDebug() << "Invalid Time"; | |
228 return QDateTime(); | |
229 } | |
230 return QDateTime::fromTime_t(filetime); | |
231 } |