summaryrefslogtreecommitdiff
path: root/platform/android/src/http_file_source.cpp
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-02-15 17:35:13 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-04-14 14:18:19 -0700
commit3af3e72bb3cb3f05b33be304d59e66cc244ef4d9 (patch)
treeef1d237c3083694307081c219c9da94ae43fe540 /platform/android/src/http_file_source.cpp
parent6d88a23a60bc0a6dc9945bf09a659d15dd827192 (diff)
downloadqtlocation-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.cpp180
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