diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-02-15 17:35:13 -0800 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-04-14 14:18:19 -0700 |
commit | 3af3e72bb3cb3f05b33be304d59e66cc244ef4d9 (patch) | |
tree | ef1d237c3083694307081c219c9da94ae43fe540 /platform/android/src/http_file_source.cpp | |
parent | 6d88a23a60bc0a6dc9945bf09a659d15dd827192 (diff) | |
download | qtlocation-mapboxgl-3af3e72bb3cb3f05b33be304d59e66cc244ef4d9.tar.gz |
[all] Replace HTTPContextBase/HTTPRequestBase with FileSource
Diffstat (limited to 'platform/android/src/http_file_source.cpp')
-rw-r--r-- | platform/android/src/http_file_source.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/platform/android/src/http_file_source.cpp b/platform/android/src/http_file_source.cpp new file mode 100644 index 0000000000..ceb241af4e --- /dev/null +++ b/platform/android/src/http_file_source.cpp @@ -0,0 +1,180 @@ +#include <mbgl/storage/http_file_source.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> +#include <mbgl/platform/log.hpp> + +#include <mbgl/util/async_task.hpp> +#include <mbgl/util/util.hpp> +#include <mbgl/util/string.hpp> +#include <mbgl/util/http_header.hpp> + +#include <jni/jni.hpp> +#include "attach_env.hpp" + +namespace mbgl { + +class HTTPFileSource::Impl { +public: + android::UniqueEnv env { android::AttachEnv() }; +}; + +class HTTPRequest : public AsyncRequest { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/http/HTTPRequest"; }; + + HTTPRequest(jni::JNIEnv&, const Resource&, FileSource::Callback); + ~HTTPRequest(); + + void onFailure(jni::JNIEnv&, int type, jni::String message); + void onResponse(jni::JNIEnv&, int code, + jni::String etag, jni::String modified, + jni::String cacheControl, jni::String expires, + jni::Array<jni::jbyte> body); + + static jni::Class<HTTPRequest> javaClass; + jni::UniqueObject<HTTPRequest> javaRequest; + +private: + Resource resource; + FileSource::Callback callback; + Response response; + + util::AsyncTask async { [this] { + // Calling `callback` may result in deleting `this`. Copy data to temporaries first. + auto callback_ = callback; + auto response_ = response; + callback_(response_); + } }; + + static const int connectionError = 0; + static const int temporaryError = 1; + static const int permanentError = 2; +}; + +jni::Class<HTTPRequest> HTTPRequest::javaClass; + +namespace android { + +void RegisterNativeHTTPRequest(jni::JNIEnv& env) { + HTTPRequest::javaClass = *jni::Class<HTTPRequest>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + jni::RegisterNativePeer<HTTPRequest>(env, HTTPRequest::javaClass, "mNativePtr", + METHOD(&HTTPRequest::onFailure, "nativeOnFailure"), + METHOD(&HTTPRequest::onResponse, "nativeOnResponse")); +} + +} // namespace android + +HTTPRequest::HTTPRequest(jni::JNIEnv& env, const Resource& resource_, FileSource::Callback callback_) + : resource(resource_), + callback(callback_) { + std::string etagStr; + std::string modifiedStr; + + if (resource.priorEtag) { + etagStr = *resource.priorEtag; + } else if (resource.priorModified) { + modifiedStr = util::rfc1123(*resource.priorModified); + } + + jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 10); + + static auto constructor = + javaClass.GetConstructor<jni::jlong, jni::String, jni::String, jni::String, jni::String>(env); + + javaRequest = javaClass.New(env, constructor, + reinterpret_cast<jlong>(this), + jni::Make<jni::String>(env, resource.url), + jni::Make<jni::String>(env, "MapboxGL/1.0"), + jni::Make<jni::String>(env, etagStr), + jni::Make<jni::String>(env, modifiedStr)).NewGlobalRef(env); +} + +HTTPRequest::~HTTPRequest() { + android::UniqueEnv env = android::AttachEnv(); + + static auto cancel = javaClass.GetMethod<void ()>(*env, "cancel"); + + javaRequest->Call(*env, cancel); +} + +void HTTPRequest::onResponse(jni::JNIEnv& env, int code, + jni::String etag, jni::String modified, jni::String cacheControl, + jni::String expires, jni::Array<jni::jbyte> body) { + using Error = Response::Error; + + if (etag) { + response.etag = jni::Make<std::string>(env, etag); + } + + if (modified) { + response.modified = util::parseTimePoint(jni::Make<std::string>(env, modified).c_str()); + } + + if (cacheControl) { + response.expires = http::CacheControl::parse(jni::Make<std::string>(env, cacheControl).c_str()).toTimePoint(); + } + + if (expires) { + response.expires = util::parseTimePoint(jni::Make<std::string>(env, expires).c_str()); + } + + if (code == 200) { + if (body) { + auto data = std::make_shared<std::string>(body.Length(env), char()); + jni::GetArrayRegion(env, *body, 0, data->size(), reinterpret_cast<jbyte*>(&(*data)[0])); + response.data = data; + } else { + response.data = std::make_shared<std::string>(); + } + } else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) { + response.noContent = true; + } else if (code == 304) { + response.notModified = true; + } else if (code == 404) { + response.error = std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404"); + } else if (code >= 500 && code < 600) { + response.error = std::make_unique<Error>(Error::Reason::Server, std::string{ "HTTP status code " } + std::to_string(code)); + } else { + response.error = std::make_unique<Error>(Error::Reason::Other, std::string{ "HTTP status code " } + std::to_string(code)); + } + + async.send(); +} + +void HTTPRequest::onFailure(jni::JNIEnv& env, int type, jni::String message) { + std::string messageStr = jni::Make<std::string>(env, message); + + using Error = Response::Error; + + switch (type) { + case connectionError: + response.error = std::make_unique<Error>(Error::Reason::Connection, messageStr); + break; + case temporaryError: + response.error = std::make_unique<Error>(Error::Reason::Server, messageStr); + break; + default: + response.error = std::make_unique<Error>(Error::Reason::Other, messageStr); + } + + async.send(); +} + +HTTPFileSource::HTTPFileSource() + : impl(std::make_unique<Impl>()) { +} + +HTTPFileSource::~HTTPFileSource() = default; + +std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource, Callback callback) { + return std::make_unique<HTTPRequest>(*impl->env, resource, callback); +} + +uint32_t HTTPFileSource::maximumConcurrentRequests() { + return 20; +} + +} // namespace mbgl |