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 | |
parent | fe0baffe0dfbf369f422e175c0fcf3dda9055118 (diff) | |
download | qtlocation-mapboxgl-b29bce0936ac711b7fa6c2a43684696021dfb668.tar.gz |
add ca bundle loading back to CURL
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java | 12 | ||||
-rw-r--r-- | gyp/http-curl.gypi | 28 | ||||
-rw-r--r-- | platform/default/http_request_curl.cpp | 122 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/sprite.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/storage/default_file_source.cpp | 1 | ||||
-rw-r--r-- | test/storage/http_error.cpp | 2 |
8 files changed, 150 insertions, 24 deletions
@@ -166,6 +166,9 @@ android-lib-%: Makefile/android-% @$(ENV_android-$*) ./scripts/flock.py -v build/Android.lock $(MAKE) -C build/android-$* BUILDTYPE=$(BUILDTYPE) androidapp # Builds the selected/default Android library +android-lib: android-lib-$(ANDROID_ABI) + +# Builds the selected/default Android library android: android-lib-$(ANDROID_ABI) cd android/java && ./gradlew --parallel-threads=$(JOBS) build diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java index e8b1d578b7..a10c0206be 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java @@ -214,7 +214,7 @@ public class MainActivity extends ActionBarActivity { switch(position) { // Bright case 0: - mMapFragment.getMap().setStyleUrl("asset://styles/styles/bright-v7.json"); + mMapFragment.getMap().setStyleUrl("asset://styles/bright-v7.json"); mMapFragment.getMap().removeAllClasses(); mClassSpinner.setVisibility(View.INVISIBLE); mClassSpinner.setAdapter(null); @@ -223,7 +223,7 @@ public class MainActivity extends ActionBarActivity { // Basic case 1: - mMapFragment.getMap().setStyleUrl("asset://styles/styles/basic-v7.json"); + mMapFragment.getMap().setStyleUrl("asset://styles/basic-v7.json"); mMapFragment.getMap().removeAllClasses(); mClassSpinner.setVisibility(View.INVISIBLE); mClassSpinner.setAdapter(null); @@ -232,7 +232,7 @@ public class MainActivity extends ActionBarActivity { // Outdoors case 2: - mMapFragment.getMap().setStyleUrl("asset://styles/styles/outdoors-v7.json"); + mMapFragment.getMap().setStyleUrl("asset://styles/outdoors-v7.json"); mMapFragment.getMap().removeAllClasses(); mClassSpinner.setVisibility(View.VISIBLE); mClassSpinner.setAdapter(mOutdoorsClassAdapter); @@ -241,7 +241,7 @@ public class MainActivity extends ActionBarActivity { // Satellite case 3: - mMapFragment.getMap().setStyleUrl("asset://styles/styles/satellite-v7.json"); + mMapFragment.getMap().setStyleUrl("asset://styles/satellite-v7.json"); mMapFragment.getMap().removeAllClasses(); mClassSpinner.setVisibility(View.VISIBLE); mClassSpinner.setAdapter(mSatelliteClassAdapter); @@ -250,7 +250,7 @@ public class MainActivity extends ActionBarActivity { // Pencil case 4: - mMapFragment.getMap().setStyleUrl("asset://styles/styles/pencil-v7.json"); + mMapFragment.getMap().setStyleUrl("asset://styles/pencil-v7.json"); mMapFragment.getMap().removeAllClasses(); mClassSpinner.setVisibility(View.INVISIBLE); mClassSpinner.setAdapter(null); @@ -259,7 +259,7 @@ public class MainActivity extends ActionBarActivity { // Empty case 5: - mMapFragment.getMap().setStyleUrl("asset://styles/styles/empty-v7.json"); + mMapFragment.getMap().setStyleUrl("asset://styles/empty-v7.json"); mMapFragment.getMap().removeAllClasses(); mClassSpinner.setVisibility(View.INVISIBLE); mClassSpinner.setAdapter(null); diff --git a/gyp/http-curl.gypi b/gyp/http-curl.gypi index 87edff2492..bfb2054d55 100644 --- a/gyp/http-curl.gypi +++ b/gyp/http-curl.gypi @@ -14,6 +14,24 @@ '../include', ], + 'conditions': [ + ['host == "android"', { + 'variables': { + # Android uses libzip and openssl to set CURL's CA bundle. + 'cflags_cc': [ '<@(zip_cflags)', '<@(openssl_cflags)' ], + 'ldflags': [ '<@(zip_ldflags)', ], + 'libraries': [ '<@(zip_static_libs)', ], + }, + }], + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + }, + }, { + 'cflags_cc': [ '<@(cflags_cc)' ], + }], + ], + 'variables': { 'cflags_cc': [ '<@(uv_cflags)', @@ -30,16 +48,6 @@ ], }, - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], - }, - }, { - 'cflags_cc': [ '<@(cflags_cc)' ], - }], - ], - 'link_settings': { 'conditions': [ ['OS == "mac"', { 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 { diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index f23bcaa14a..cdf9bdd372 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -43,7 +43,7 @@ void Source::load(Map& map, FileSource& fileSource) { const std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken()); fileSource.request({ Resource::Kind::JSON, url }, **map.loop, [source, &map](const Response &res) { if (res.status != Response::Successful) { - Log::Warning(Event::General, "failed to load source TileJSON"); + Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str()); return; } @@ -51,7 +51,7 @@ void Source::load(Map& map, FileSource& fileSource) { d.Parse<0>(res.data.c_str()); if (d.HasParseError()) { - Log::Warning(Event::General, "invalid source TileJSON"); + Log::Warning(Event::General, "Invalid source TileJSON; Parse Error at %d: %s", d.GetErrorOffset(), d.GetParseError()); return; } diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index 19f7b7c8c6..9543fe083a 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -82,7 +82,7 @@ void Sprite::load(FileSource& fileSource) { sprite->parseImage(); sprite->complete(); } else { - Log::Warning(Event::Sprite, "Failed to load sprite image: Error %s", res.message.c_str()); + Log::Warning(Event::Sprite, "Failed to load sprite image: %s", res.message.c_str()); if (!sprite->future.valid()) { sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message))); } diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index 6d27adbe0e..c6b201b559 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -10,6 +10,7 @@ #include <mbgl/util/util.hpp> #include <mbgl/util/variant.hpp> +#include <mbgl/platform/log.hpp> #pragma GCC diagnostic push #ifndef __clang__ diff --git a/test/storage/http_error.cpp b/test/storage/http_error.cpp index 45c23b94b6..498f1eae6b 100644 --- a/test/storage/http_error.cpp +++ b/test/storage/http_error.cpp @@ -44,7 +44,7 @@ TEST_F(Storage, HTTPError) { EXPECT_LT(1.5, duration) << "Resource wasn't retried the correct number of times"; EXPECT_GT(1.7, duration) << "Resource wasn't retried the correct number of times"; EXPECT_EQ(Response::Error, res.status); - EXPECT_TRUE(res.message == "Couldn't connect to server" || res.message == "The operation couldn’t be completed. (NSURLErrorDomain error -1004.)"); + EXPECT_TRUE(res.message == "Couldn't connect to server: couldn't connect to host" || res.message == "The operation couldn’t be completed. (NSURLErrorDomain error -1004.)") << res.message; EXPECT_EQ("", res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); |