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 }

http://wald.intevation.org/projects/trustbridge/