summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-02-06 16:13:25 +0100
committerKonstantin Käfer <mail@kkaefer.com>2015-02-17 11:42:47 -0800
commitb29bce0936ac711b7fa6c2a43684696021dfb668 (patch)
tree8515a6923421df3ef7c5b2dd660c9d11f1016b65 /platform
parentfe0baffe0dfbf369f422e175c0fcf3dda9055118 (diff)
downloadqtlocation-mapboxgl-b29bce0936ac711b7fa6c2a43684696021dfb668.tar.gz
add ca bundle loading back to CURL
Diffstat (limited to 'platform')
-rw-r--r--platform/default/http_request_curl.cpp122
1 files changed, 118 insertions, 4 deletions
diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp
index 411c5ee470..8772377a95 100644
--- a/platform/default/http_request_curl.cpp
+++ b/platform/default/http_request_curl.cpp
@@ -1,11 +1,18 @@
#include <mbgl/storage/default/http_request.hpp>
#include <mbgl/storage/default/http_context.hpp>
#include <mbgl/storage/response.hpp>
+#include <mbgl/platform/log.hpp>
#include <mbgl/util/time.hpp>
#include <curl/curl.h>
+#ifdef __ANDROID__
+#include <mbgl/android/jni.hpp>
+#include <zip.h>
+#include <openssl/ssl.h>
+#endif
+
#include <queue>
#include <map>
#include <cassert>
@@ -125,6 +132,8 @@ private:
int attempts = 0;
static const int maxAttempts = 4;
+
+ char error[CURL_ERROR_SIZE];
};
@@ -317,6 +326,104 @@ int HTTPCURLContext::startTimeout(CURLM * /* multi */, long timeout_ms, void *us
// -------------------------------------------------------------------------------------------------
+#ifdef __ANDROID__
+
+// This function is called to load the CA bundle
+// from http://curl.haxx.se/libcurl/c/cacertinmem.html¯
+static CURLcode sslctx_function(CURL * /* curl */, void *sslctx, void * /* parm */) {
+
+ int error = 0;
+ struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error);
+ if (apk == nullptr) {
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ struct zip_file *apkFile = zip_fopen(apk, "assets/ca-bundle.crt", ZIP_FL_NOCASE);
+ if (apkFile == nullptr) {
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ struct zip_stat stat;
+ if (zip_stat(apk, "assets/ca-bundle.crt", ZIP_FL_NOCASE, &stat) != 0) {
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ if (stat.size > std::numeric_limits<int>::max()) {
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ const auto pem = util::make_unique<char[]>(stat.size);
+
+ if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(pem.get()), stat.size)) != stat.size) {
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // get a pointer to the X509 certificate store (which may be empty!)
+ X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx);
+ if (store == nullptr) {
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // get a BIO
+ BIO *bio = BIO_new_mem_buf(pem.get(), static_cast<int>(stat.size));
+ if (bio == nullptr) {
+ store = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // use it to read the PEM formatted certificate from memory into an X509
+ // structure that SSL can use
+ X509 *cert = nullptr;
+ while (PEM_read_bio_X509(bio, &cert, 0, nullptr) != nullptr) {
+ if (cert == nullptr) {
+ BIO_free(bio);
+ bio = nullptr;
+ store = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // add our certificate to this store
+ if (X509_STORE_add_cert(store, cert) == 0) {
+ X509_free(cert);
+ cert = nullptr;
+ BIO_free(bio);
+ bio = nullptr;
+ store = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ X509_free(cert);
+ cert = nullptr;
+ }
+
+ // decrease reference counts
+ BIO_free(bio);
+ bio = nullptr;
+
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+
+ // all set to go
+ return CURLE_OK;
+}
+#endif
+
HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::unique_ptr<Response> response_)
: context(HTTPCURLContext::Get(loop)),
request(request_),
@@ -325,6 +432,9 @@ HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::un
assert(request);
context->addRequest(request);
+ // Zero out the error buffer.
+ memset(error, 0, sizeof(error));
+
// If there's already a response, set the correct etags/modified headers to make sure we are
// getting a 304 response if possible. This avoids redownloading unchanged data.
if (existingResponse) {
@@ -343,7 +453,13 @@ HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::un
}
handleError(curl_easy_setopt(handle, CURLOPT_PRIVATE, this));
+ handleError(curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error));
+#ifdef __ANDROID__
+ handleError(curl_easy_setopt(handle, CURLOPT_SSLCERTTYPE, "PEM"));
+ handleError(curl_easy_setopt(handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function));
+#else
handleError(curl_easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt"));
+#endif
handleError(curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1));
handleError(curl_easy_setopt(handle, CURLOPT_URL, request->resource.url.c_str()));
handleError(curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback));
@@ -550,21 +666,19 @@ void HTTPRequestImpl::handleResult(CURLcode code) {
// Add human-readable error code
if (code != CURLE_OK) {
- response->message = curl_easy_strerror(code);
+ response->status = Response::Error;
+ response->message = std::string { curl_easy_strerror(code) } + ": " + error;
switch (code) {
case CURLE_COULDNT_RESOLVE_PROXY:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_COULDNT_CONNECT:
- response->status = Response::Error;
return finish(ResponseStatus::ConnectionError);
case CURLE_OPERATION_TIMEDOUT:
- response->status = Response::Error;
return finish(ResponseStatus::TemporaryError);
default:
- response->status = Response::Error;
return finish(ResponseStatus::PermanentError);
}
} else {