diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2015-02-06 16:13:25 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2015-02-17 11:42:47 -0800 |
commit | b29bce0936ac711b7fa6c2a43684696021dfb668 (patch) | |
tree | 8515a6923421df3ef7c5b2dd660c9d11f1016b65 /platform | |
parent | fe0baffe0dfbf369f422e175c0fcf3dda9055118 (diff) | |
download | qtlocation-mapboxgl-b29bce0936ac711b7fa6c2a43684696021dfb668.tar.gz |
add ca bundle loading back to CURL
Diffstat (limited to 'platform')
-rw-r--r-- | platform/default/http_request_curl.cpp | 122 |
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 { |