summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2015-04-28 14:31:00 -0400
committerJohn Firebaugh <john.firebaugh@gmail.com>2015-04-28 19:26:35 -0400
commit481fa0e69ff8d84202e91a1643c72636200f1b80 (patch)
treea2679fd559046d2c7e6f64cb5c4a67e29e16bf66
parent2c3952af66d6907f8a892d42d0034e91126b073a (diff)
downloadqtlocation-mapboxgl-481fa0e69ff8d84202e91a1643c72636200f1b80.tar.gz
Restructure *Request and Context
The previous implementation, based on thread-local storage, did not ensure that the context was destructed before the FileSource run loop. This resulted in implementations attempting to uv_close handles for a loop that had already been destroyed. This change also fixes #1262.
-rw-r--r--platform/darwin/http_request_nsurl.mm140
-rw-r--r--platform/default/asset_request_fs.cpp106
-rw-r--r--platform/default/asset_request_zip.cpp138
-rw-r--r--platform/default/http_request_curl.cpp151
-rw-r--r--src/mbgl/storage/asset_context.hpp23
-rw-r--r--src/mbgl/storage/asset_request.hpp27
-rw-r--r--src/mbgl/storage/default_file_source.cpp12
-rw-r--r--src/mbgl/storage/default_file_source_impl.hpp4
-rw-r--r--src/mbgl/storage/http_context.cpp30
-rw-r--r--src/mbgl/storage/http_context.hpp72
-rw-r--r--src/mbgl/storage/http_request.hpp28
-rw-r--r--src/mbgl/storage/request_base.hpp1
-rw-r--r--src/mbgl/storage/thread_context.hpp78
-rw-r--r--src/mbgl/util/uv_detail.hpp4
14 files changed, 311 insertions, 503 deletions
diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm
index f5e7888f57..e3f0b5dad6 100644
--- a/platform/darwin/http_request_nsurl.mm
+++ b/platform/darwin/http_request_nsurl.mm
@@ -1,9 +1,8 @@
-#include <mbgl/storage/http_request.hpp>
#include <mbgl/storage/http_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
-#include <mbgl/util/uv.hpp>
+#include <mbgl/util/std.hpp>
#include <mbgl/util/time.hpp>
#include <mbgl/util/parsedate.h>
@@ -46,25 +45,29 @@ enum class ResponseStatus : uint8_t {
class HTTPNSURLContext;
-class HTTPRequestImpl {
+class HTTPRequest : public RequestBase {
public:
- HTTPRequestImpl(HTTPRequest *request, uv_loop_t *loop, std::shared_ptr<const Response> response);
- ~HTTPRequestImpl();
+ HTTPRequest(HTTPNSURLContext*,
+ const Resource&,
+ Callback,
+ uv_loop_t*,
+ std::shared_ptr<const Response>);
+ ~HTTPRequest();
- void cancel();
- void cancelTimer();
+ void cancel() override;
+ void retry() override;
+private:
+ void cancelTimer();
void start();
void handleResult(NSData *data, NSURLResponse *res, NSError *error);
void handleResponse();
-
void retry(uint64_t timeout);
- void retryImmediately();
+
static void restart(uv_timer_t *timer, int);
-private:
HTTPNSURLContext *context = nullptr;
- HTTPRequest *request = nullptr;
+ bool cancelled = false;
NSURLSessionDataTask *task = nullptr;
std::unique_ptr<Response> response;
const std::shared_ptr<const Response> existingResponse;
@@ -79,18 +82,20 @@ private:
// -------------------------------------------------------------------------------------------------
-class HTTPNSURLContext : public HTTPContext<HTTPNSURLContext> {
+class HTTPNSURLContext : public HTTPContext {
public:
HTTPNSURLContext(uv_loop_t *loop);
~HTTPNSURLContext();
+ RequestBase* createRequest(const Resource&,
+ RequestBase::Callback,
+ uv_loop_t*,
+ std::shared_ptr<const Response>) override;
+
NSURLSession *session = nil;
NSString *userAgent = nil;
};
-template<> pthread_key_t ThreadContext<HTTPNSURLContext>::key{};
-template<> pthread_once_t ThreadContext<HTTPNSURLContext>::once = PTHREAD_ONCE_INIT;
-
HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
@autoreleasepool {
NSURLSessionConfiguration *sessionConfig =
@@ -116,34 +121,51 @@ HTTPNSURLContext::~HTTPNSURLContext() {
userAgent = nullptr;
}
+RequestBase* HTTPNSURLContext::createRequest(const Resource& resource,
+ RequestBase::Callback callback,
+ uv_loop_t* loop,
+ std::shared_ptr<const Response> response) {
+ return new HTTPRequest(this, resource, callback, loop, response);
+}
+
// -------------------------------------------------------------------------------------------------
-HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop,
- std::shared_ptr<const Response> existingResponse_)
- : context(HTTPNSURLContext::Get(loop)),
- request(request_),
+HTTPRequest::HTTPRequest(HTTPNSURLContext* context_, const Resource& resource_, Callback callback_, uv_loop_t *loop, std::shared_ptr<const Response> existingResponse_)
+ : RequestBase(resource_, callback_),
+ context(context_),
existingResponse(existingResponse_),
async(new uv_async_t) {
- assert(request);
- context->addRequest(request);
+ context->addRequest(this);
async->data = this;
uv_async_init(loop, async, [](uv_async_t *as, int) {
- auto impl = reinterpret_cast<HTTPRequestImpl *>(as->data);
+ auto impl = reinterpret_cast<HTTPRequest *>(as->data);
impl->handleResponse();
});
start();
}
-void HTTPRequestImpl::start() {
+HTTPRequest::~HTTPRequest() {
+ assert(!task);
+ assert(async);
+
+ // Stop the backoff timer to avoid re-triggering this request.
+ cancelTimer();
+
+ uv::close(async);
+
+ context->removeRequest(this);
+}
+
+void HTTPRequest::start() {
assert(!task);
attempts++;
@autoreleasepool {
- NSMutableString *url = [[NSMutableString alloc] initWithString:@(request->resource.url.c_str())];
+ NSMutableString *url = [[NSMutableString alloc] initWithString:@(resource.url.c_str())];
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"mapbox_metrics_disabled"] == nil) {
if ([url rangeOfString:@"?"].location == NSNotFound) {
[url appendString:@"?"];
@@ -175,13 +197,13 @@ void HTTPRequestImpl::start() {
}
}
-void HTTPRequestImpl::handleResponse() {
+void HTTPRequest::handleResponse() {
if (task) {
[task release];
task = nullptr;
}
- if (request) {
+ if (!cancelled) {
if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) {
strategy = ExponentialBackoff;
return retry((1 << (attempts - 1)) * 1000);
@@ -194,23 +216,18 @@ void HTTPRequestImpl::handleResponse() {
// Actually return the response.
if (status == ResponseStatus::NotModified) {
- request->notify(std::move(response), FileCache::Hint::Refresh);
+ notify(std::move(response), FileCache::Hint::Refresh);
} else {
- request->notify(std::move(response), FileCache::Hint::Full);
+ notify(std::move(response), FileCache::Hint::Full);
}
-
- context->removeRequest(request);
- request->impl = nullptr;
- delete request;
- request = nullptr;
}
delete this;
}
-void HTTPRequestImpl::cancel() {
- context->removeRequest(request);
- request = nullptr;
+void HTTPRequest::cancel() {
+ context->removeRequest(this);
+ cancelled = true;
// Stop the backoff timer to avoid re-triggering this request.
cancelTimer();
@@ -224,7 +241,7 @@ void HTTPRequestImpl::cancel() {
}
}
-void HTTPRequestImpl::cancelTimer() {
+void HTTPRequest::cancelTimer() {
if (timer) {
uv_timer_stop(timer);
uv::close(timer);
@@ -232,21 +249,6 @@ void HTTPRequestImpl::cancelTimer() {
}
}
-HTTPRequestImpl::~HTTPRequestImpl() {
- assert(!task);
- assert(async);
-
- // Stop the backoff timer to avoid re-triggering this request.
- cancelTimer();
-
- uv::close(async);
-
- if (request) {
- context->removeRequest(request);
- request->impl = nullptr;
- }
-}
-
int64_t parseCacheControl(const char *value) {
if (value) {
unsigned long long seconds = 0;
@@ -262,7 +264,7 @@ int64_t parseCacheControl(const char *value) {
return 0;
}
-void HTTPRequestImpl::handleResult(NSData *data, NSURLResponse *res, NSError *error) {
+void HTTPRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error) {
if (error) {
if ([error code] == NSURLErrorCancelled) {
status = ResponseStatus::Canceled;
@@ -365,7 +367,7 @@ void HTTPRequestImpl::handleResult(NSData *data, NSURLResponse *res, NSError *er
uv_async_send(async);
}
-void HTTPRequestImpl::retry(uint64_t timeout) {
+void HTTPRequest::retry(uint64_t timeout) {
response.reset();
assert(!timer);
@@ -375,7 +377,7 @@ void HTTPRequestImpl::retry(uint64_t timeout) {
uv_timer_start(timer, restart, timeout, 0);
}
-void HTTPRequestImpl::retryImmediately() {
+void HTTPRequest::retry() {
// All batons get notified when the network status changed, but some of them
// might not actually wait for the network to become available again.
if (timer && strategy == PreemptImmediately) {
@@ -385,9 +387,9 @@ void HTTPRequestImpl::retryImmediately() {
}
}
-void HTTPRequestImpl::restart(uv_timer_t *timer, int) {
+void HTTPRequest::restart(uv_timer_t *timer, int) {
// Restart the request.
- auto impl = reinterpret_cast<HTTPRequestImpl *>(timer->data);
+ auto impl = reinterpret_cast<HTTPRequest *>(timer->data);
// Get rid of the timer.
impl->timer = nullptr;
@@ -396,28 +398,8 @@ void HTTPRequestImpl::restart(uv_timer_t *timer, int) {
impl->start();
}
-// -------------------------------------------------------------------------------------------------
-
-HTTPRequest::HTTPRequest(const Resource& resource, Callback callback,
- uv_loop_t* loop, std::shared_ptr<const Response> response)
- : RequestBase(resource, callback)
- , impl(new HTTPRequestImpl(this, loop, response)) {
-}
-
-HTTPRequest::~HTTPRequest() {
- if (impl) {
- impl->cancel();
- }
-}
-
-void HTTPRequest::retryImmediately() {
- if (impl) {
- impl->retryImmediately();
- }
-}
-
-void HTTPRequest::cancel() {
- delete this;
+std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
+ return util::make_unique<HTTPNSURLContext>(loop);
}
}
diff --git a/platform/default/asset_request_fs.cpp b/platform/default/asset_request_fs.cpp
index 87e4320622..8fc56eb16b 100644
--- a/platform/default/asset_request_fs.cpp
+++ b/platform/default/asset_request_fs.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/storage/asset_request.hpp>
+#include <mbgl/storage/asset_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/std.hpp>
@@ -7,27 +7,19 @@
#include <uv.h>
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#ifndef __clang__
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#endif
-#include <boost/algorithm/string.hpp>
-#pragma GCC diagnostic pop
-
#include <cassert>
-
-
-namespace algo = boost::algorithm;
+#include <limits>
namespace mbgl {
-class AssetRequestImpl {
+class AssetRequest : public RequestBase {
MBGL_STORE_THREAD(tid)
public:
- AssetRequestImpl(AssetRequest*, uv_loop_t*, const std::string& assetRoot);
- ~AssetRequestImpl();
+ AssetRequest(const Resource&, Callback, uv_loop_t*, const std::string& assetRoot);
+ ~AssetRequest();
+
+ void cancel() override;
static void fileOpened(uv_fs_t *req);
static void fileStated(uv_fs_t *req);
@@ -36,7 +28,6 @@ public:
static void notifyError(uv_fs_t *req);
static void cleanup(uv_fs_t *req);
- AssetRequest *request = nullptr;
std::string assetRoot;
bool canceled = false;
uv_fs_t req;
@@ -45,20 +36,25 @@ public:
std::unique_ptr<Response> response;
};
-AssetRequestImpl::~AssetRequestImpl() {
- MBGL_VERIFY_THREAD(tid);
-
- if (request) {
- request->impl = nullptr;
+class AssetFSContext : public AssetContext {
+ RequestBase* createRequest(const Resource& resource,
+ RequestBase::Callback callback,
+ uv_loop_t* loop,
+ const std::string& assetRoot) override {
+ return new AssetRequest(resource, callback, loop, assetRoot);
}
+};
+
+AssetRequest::~AssetRequest() {
+ MBGL_VERIFY_THREAD(tid);
}
-AssetRequestImpl::AssetRequestImpl(AssetRequest* request_, uv_loop_t* loop, const std::string& assetRoot_)
- : request(request_)
- , assetRoot(assetRoot_) {
+AssetRequest::AssetRequest(const Resource& resource_, Callback callback_, uv_loop_t* loop, const std::string& assetRoot_)
+ : RequestBase(resource_, callback_),
+ assetRoot(assetRoot_) {
req.data = this;
- const auto &url = request->resource.url;
+ const auto &url = resource.url;
std::string path;
if (url.size() <= 8 || url[8] == '/') {
// This is an empty or absolute path.
@@ -71,9 +67,9 @@ AssetRequestImpl::AssetRequestImpl(AssetRequest* request_, uv_loop_t* loop, cons
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, fileOpened);
}
-void AssetRequestImpl::fileOpened(uv_fs_t *req) {
+void AssetRequest::fileOpened(uv_fs_t *req) {
assert(req->data);
- auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
+ auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0) {
@@ -96,9 +92,9 @@ void AssetRequestImpl::fileOpened(uv_fs_t *req) {
}
}
-void AssetRequestImpl::fileStated(uv_fs_t *req) {
+void AssetRequest::fileStated(uv_fs_t *req) {
assert(req->data);
- auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
+ auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result != 0 || self->canceled) {
@@ -124,9 +120,7 @@ void AssetRequestImpl::fileStated(uv_fs_t *req) {
#else
response->message = uv_strerror(UV_EFBIG);
#endif
- assert(self->request);
- self->request->notify(std::move(response), FileCache::Hint::No);
- delete self->request;
+ self->notify(std::move(response), FileCache::Hint::No);
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
@@ -151,9 +145,9 @@ void AssetRequestImpl::fileStated(uv_fs_t *req) {
}
}
-void AssetRequestImpl::fileRead(uv_fs_t *req) {
+void AssetRequest::fileRead(uv_fs_t *req) {
assert(req->data);
- auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
+ auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0 || self->canceled) {
@@ -163,18 +157,16 @@ void AssetRequestImpl::fileRead(uv_fs_t *req) {
} else {
// File was successfully read.
self->response->status = Response::Successful;
- assert(self->request);
- self->request->notify(std::move(self->response), FileCache::Hint::No);
- delete self->request;
+ self->notify(std::move(self->response), FileCache::Hint::No);
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
}
-void AssetRequestImpl::fileClosed(uv_fs_t *req) {
+void AssetRequest::fileClosed(uv_fs_t *req) {
assert(req->data);
- auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
+ auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
(void(self)); // Silence unused variable error in Release mode
@@ -185,51 +177,37 @@ void AssetRequestImpl::fileClosed(uv_fs_t *req) {
cleanup(req);
}
-void AssetRequestImpl::notifyError(uv_fs_t *req) {
+void AssetRequest::notifyError(uv_fs_t *req) {
assert(req->data);
- auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
+ auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0 && !self->canceled && req->result != UV_ECANCELED) {
auto response = util::make_unique<Response>();
response->status = Response::Error;
response->message = uv::getFileRequestError(req);
- assert(self->request);
- self->request->notify(std::move(response), FileCache::Hint::No);
- delete self->request;
+ self->notify(std::move(response), FileCache::Hint::No);
}
}
-void AssetRequestImpl::cleanup(uv_fs_t *req) {
+void AssetRequest::cleanup(uv_fs_t *req) {
assert(req->data);
- auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
+ auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
uv_fs_req_cleanup(req);
delete self;
}
-// -------------------------------------------------------------------------------------------------
-
-AssetRequest::AssetRequest(const Resource& resource_, Callback callback_,
- uv_loop_t* loop, const std::string& assetRoot)
- : RequestBase(resource_, callback_)
- , impl(new AssetRequestImpl(this, loop, assetRoot)) {
- assert(algo::starts_with(resource.url, "asset://"));
- // Note: the AssetRequestImpl deletes itself.
-}
-
-AssetRequest::~AssetRequest() {
- if (impl) {
- impl->request = nullptr;
- }
-}
-
void AssetRequest::cancel() {
- impl->canceled = true;
+ canceled = true;
// uv_cancel fails frequently when the request has already been started.
// In that case, we have to let it complete and check the canceled bool
// instead. The cancelation callback will delete the AssetRequest object.
- uv_cancel((uv_req_t *)&impl->req);
+ uv_cancel((uv_req_t *)&req);
+}
+
+std::unique_ptr<AssetContext> AssetContext::createContext(uv_loop_t*) {
+ return util::make_unique<AssetFSContext>();
}
}
diff --git a/platform/default/asset_request_zip.cpp b/platform/default/asset_request_zip.cpp
index 9f7ed6d9b7..7666000d00 100644
--- a/platform/default/asset_request_zip.cpp
+++ b/platform/default/asset_request_zip.cpp
@@ -1,46 +1,40 @@
-#include <mbgl/storage/asset_request.hpp>
-#include <mbgl/storage/thread_context.hpp>
+#include <mbgl/storage/asset_context.hpp>
#include <mbgl/android/jni.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/std.hpp>
+#include <mbgl/util/util.hpp>
+#include <mbgl/util/uv.hpp>
+#include <uv.h>
#include "uv_zip.h"
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#ifndef __clang__
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#endif
-#include <boost/algorithm/string.hpp>
-#pragma GCC diagnostic pop
-
+#include <map>
+#include <cassert>
#include <forward_list>
-namespace algo = boost::algorithm;
-
namespace mbgl {
-class AssetZipContext : public ThreadContext<AssetZipContext> {
+class AssetZipContext : public AssetContext {
public:
AssetZipContext(uv_loop_t *loop);
~AssetZipContext();
+ RequestBase* createRequest(const Resource& resource,
+ RequestBase::Callback callback,
+ uv_loop_t* loop,
+ const std::string& assetRoot) override;
+
uv_zip_t *getHandle(const std::string &path);
void returnHandle(const std::string &path, uv_zip_t *zip);
-private:
// A list of resuable uv_zip handles to avoid creating and destroying them all the time.
std::map<std::string, std::forward_list<uv_zip_t *>> handles;
+ uv_loop_t *loop;
};
-// -------------------------------------------------------------------------------------------------
-
-template<> pthread_key_t ThreadContext<AssetZipContext>::key{};
-template<> pthread_once_t ThreadContext<AssetZipContext>::once = PTHREAD_ONCE_INIT;
-
-AssetZipContext::AssetZipContext(uv_loop_t *loop_) : ThreadContext(loop_) {
+AssetZipContext::AssetZipContext(uv_loop_t *loop_) : loop(loop_) {
}
uv_zip_t *AssetZipContext::getHandle(const std::string &path) {
@@ -71,20 +65,18 @@ AssetZipContext::~AssetZipContext() {
handles.clear();
}
-// -------------------------------------------------------------------------------------------------
-
-class AssetRequestImpl {
+class AssetRequest : public RequestBase {
MBGL_STORE_THREAD(tid)
public:
- AssetRequestImpl(AssetRequest*, uv_loop_t*, const std::string& assetRoot);
- ~AssetRequestImpl();
+ AssetRequest(AssetZipContext&, const Resource&, Callback, const std::string& assetRoot);
+ ~AssetRequest();
- void cancel();
+ void cancel() override;
private:
AssetZipContext &context;
- AssetRequest *request = nullptr;
+ bool cancelled = false;
const std::string root;
const std::string path;
std::unique_ptr<Response> response;
@@ -102,21 +94,18 @@ private:
void notifyError(const char *message);
};
-// -------------------------------------------------------------------------------------------------
-
-AssetRequestImpl::~AssetRequestImpl() {
- MBGL_VERIFY_THREAD(tid);
-
- if (request) {
- request->impl = nullptr;
- }
+RequestBase* AssetZipContext::createRequest(const Resource& resource,
+ RequestBase::Callback callback,
+ uv_loop_t*,
+ const std::string& assetRoot) {
+ return new AssetRequest(*this, resource, callback, assetRoot);
}
-AssetRequestImpl::AssetRequestImpl(AssetRequest* request_, uv_loop_t* loop, const std::string& assetRoot_)
- : context(*AssetZipContext::Get(loop)),
- request(request_),
+AssetRequest::AssetRequest(AssetZipContext& context_, const Resource& resource_, Callback callback_, const std::string& assetRoot_)
+ : RequestBase(resource_, callback_),
+ context(context_),
root(assetRoot_),
- path(std::string { "assets/" } + request->resource.url.substr(8)) {
+ path(std::string { "assets/" } + resource.url.substr(8)) {
auto zip = context.getHandle(root);
if (zip) {
archiveOpened(zip);
@@ -125,17 +114,19 @@ AssetRequestImpl::AssetRequestImpl(AssetRequest* request_, uv_loop_t* loop, cons
}
}
-void AssetRequestImpl::openZipArchive() {
+AssetRequest::~AssetRequest() {
+ MBGL_VERIFY_THREAD(tid);
+}
+
+void AssetRequest::openZipArchive() {
uv_fs_t *req = new uv_fs_t();
req->data = this;
- assert(request);
-
// We're using uv_fs_open first to obtain a file descriptor. Then, uv_zip_fdopen will operate
// on a read-only file.
uv_fs_open(context.loop, req, root.c_str(), O_RDONLY, S_IRUSR, [](uv_fs_t *fsReq) {
if (fsReq->result < 0) {
- auto impl = reinterpret_cast<AssetRequestImpl *>(fsReq->data);
+ auto impl = reinterpret_cast<AssetRequest *>(fsReq->data);
impl->notifyError(uv::getFileRequestError(fsReq));
delete impl;
} else {
@@ -143,7 +134,7 @@ void AssetRequestImpl::openZipArchive() {
uv_zip_init(zip);
zip->data = fsReq->data;
uv_zip_fdopen(fsReq->loop, zip, uv_file(fsReq->result), 0, [](uv_zip_t *openZip) {
- auto impl = reinterpret_cast<AssetRequestImpl *>(openZip->data);
+ auto impl = reinterpret_cast<AssetRequest *>(openZip->data);
if (openZip->result < 0) {
impl->notifyError(openZip->message);
delete openZip;
@@ -163,20 +154,20 @@ void AssetRequestImpl::openZipArchive() {
#define INVOKE_MEMBER(name) \
[](uv_zip_t *zip_) { \
assert(zip_->data); \
- reinterpret_cast<AssetRequestImpl *>(zip_->data)->name(zip_); \
+ reinterpret_cast<AssetRequest *>(zip_->data)->name(zip_); \
}
-void AssetRequestImpl::archiveOpened(uv_zip_t *zip) {
+void AssetRequest::archiveOpened(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
zip->data = this;
uv_zip_stat(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileStated));
}
-void AssetRequestImpl::fileStated(uv_zip_t *zip) {
+void AssetRequest::fileStated(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
- if (!request || zip->result < 0) {
+ if (cancelled || zip->result < 0) {
// Stat failed, probably because the file doesn't exist.
if (zip->result < 0) {
notifyError(zip->message);
@@ -206,14 +197,14 @@ void AssetRequestImpl::fileStated(uv_zip_t *zip) {
}
}
-void AssetRequestImpl::fileOpened(uv_zip_t *zip) {
+void AssetRequest::fileOpened(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
// Opening failed.
notifyError(zip->message);
cleanup(zip);
- } else if (!request) {
+ } else if (cancelled) {
// The request was canceled. Close the file again.
uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
} else {
@@ -221,23 +212,21 @@ void AssetRequestImpl::fileOpened(uv_zip_t *zip) {
}
}
-void AssetRequestImpl::fileRead(uv_zip_t *zip) {
+void AssetRequest::fileRead(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
// Reading failed. We still have an open file handle though.
notifyError(zip->message);
- } else if (request) {
+ } else if (!cancelled) {
response->status = Response::Successful;
- request->notify(std::move(response), FileCache::Hint::No);
- delete request;
- assert(request == nullptr);
+ notify(std::move(response), FileCache::Hint::No);
}
uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
}
-void AssetRequestImpl::fileClosed(uv_zip_t *zip) {
+void AssetRequest::fileClosed(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
@@ -247,53 +236,32 @@ void AssetRequestImpl::fileClosed(uv_zip_t *zip) {
cleanup(zip);
}
-void AssetRequestImpl::cleanup(uv_zip_t *zip) {
+void AssetRequest::cleanup(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
context.returnHandle(root, zip);
delete this;
}
-void AssetRequestImpl::notifyError(const char *message) {
+void AssetRequest::notifyError(const char *message) {
MBGL_VERIFY_THREAD(tid);
- if (request) {
+ if (!cancelled) {
response = util::make_unique<Response>();
response->status = Response::Error;
response->message = message;
- request->notify(std::move(response), FileCache::Hint::No);
- delete request;
- assert(request == nullptr);
+ notify(std::move(response), FileCache::Hint::No);
} else {
// The request was already canceled and deleted.
}
}
-void AssetRequestImpl::cancel() {
- request = nullptr;
-}
-
-// -------------------------------------------------------------------------------------------------
-
-AssetRequest::AssetRequest(const Resource& resource_, Callback callback_,
- uv_loop_t* loop, const std::string& assetRoot)
- : RequestBase(resource_, callback_)
- , impl(new AssetRequestImpl(this, loop, assetRoot)) {
- assert(algo::starts_with(resource.url, "asset://"));
-}
-
-AssetRequest::~AssetRequest() {
- if (impl) {
- impl->cancel();
- }
-}
-
void AssetRequest::cancel() {
- if (impl) {
- impl->cancel();
- }
+ cancelled = true;
+}
- delete this;
+std::unique_ptr<AssetContext> AssetContext::createContext(uv_loop_t* loop) {
+ return util::make_unique<AssetZipContext>(loop);
}
}
diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp
index 95cc882114..27e57aab81 100644
--- a/platform/default/http_request_curl.cpp
+++ b/platform/default/http_request_curl.cpp
@@ -1,4 +1,3 @@
-#include <mbgl/storage/http_request.hpp>
#include <mbgl/storage/http_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
@@ -6,6 +5,7 @@
#include <mbgl/platform/log.hpp>
#include <mbgl/util/time.hpp>
+#include <mbgl/util/util.hpp>
#include <curl/curl.h>
@@ -54,14 +54,20 @@ enum class ResponseStatus : int8_t {
NotModified,
};
-class HTTPRequestImpl;
+class HTTPRequest;
-class HTTPCURLContext : public HTTPContext<HTTPCURLContext> {
+class HTTPCURLContext : public HTTPContext {
+ MBGL_STORE_THREAD(tid)
public:
HTTPCURLContext(uv_loop_t *loop);
~HTTPCURLContext();
+ RequestBase* createRequest(const Resource&,
+ RequestBase::Callback,
+ uv_loop_t*,
+ std::shared_ptr<const Response>) override;
+
static int handleSocket(CURL *handle, curl_socket_t s, int action, void *userp, void *socketp);
static void perform(uv_poll_t *req, int status, int events);
static int startTimeout(CURLM *multi, long timeout_ms, void *userp);
@@ -75,7 +81,8 @@ public:
void returnHandle(CURL *handle);
void checkMultiInfo();
-public:
+ uv_loop_t *loop = nullptr;
+
// Used as the CURL timer function to periodically check for socket updates.
uv_timer_t *timeout = nullptr;
@@ -91,17 +98,21 @@ public:
std::queue<CURL *> handles;
};
-
-class HTTPRequestImpl {
+class HTTPRequest : public RequestBase {
MBGL_STORE_THREAD(tid)
public:
- HTTPRequestImpl(HTTPRequest *request, uv_loop_t *loop, std::shared_ptr<const Response> response);
- ~HTTPRequestImpl();
+ HTTPRequest(HTTPCURLContext*,
+ const Resource&,
+ Callback,
+ uv_loop_t*,
+ std::shared_ptr<const Response>);
+ ~HTTPRequest();
+
+ void cancel() override;
+ void retry() override;
void handleResult(CURLcode code);
- void abandon();
- void retryImmediately();
private:
static size_t headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp);
@@ -116,9 +127,8 @@ private:
void finish(ResponseStatus status);
void start();
-private:
HTTPCURLContext *context = nullptr;
- HTTPRequest *request = nullptr;
+ bool cancelled = false;
// Will store the current response.
std::unique_ptr<Response> response;
@@ -176,10 +186,9 @@ private:
// -------------------------------------------------------------------------------------------------
-template<> pthread_key_t ThreadContext<HTTPCURLContext>::key{};
-template<> pthread_once_t ThreadContext<HTTPCURLContext>::once = PTHREAD_ONCE_INIT;
-
-HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
+HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_)
+ : HTTPContext(loop_),
+ loop(loop_) {
if (curl_global_init(CURL_GLOBAL_ALL)) {
throw std::runtime_error("Could not init cURL");
}
@@ -208,6 +217,13 @@ HTTPCURLContext::~HTTPCURLContext() {
uv::close(timeout);
}
+RequestBase* HTTPCURLContext::createRequest(const Resource& resource,
+ RequestBase::Callback callback,
+ uv_loop_t* loop_,
+ std::shared_ptr<const Response> response) {
+ return new HTTPRequest(this, resource, callback, loop_, response);
+}
+
CURL *HTTPCURLContext::getHandle() {
if (!handles.empty()) {
auto handle = handles.front();
@@ -231,7 +247,7 @@ void HTTPCURLContext::checkMultiInfo() {
while ((message = curl_multi_info_read(multi, &pending))) {
switch (message->msg) {
case CURLMSG_DONE: {
- HTTPRequestImpl *baton = nullptr;
+ HTTPRequest *baton = nullptr;
curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&baton);
assert(baton);
baton->handleResult(message->data.result);
@@ -426,13 +442,12 @@ static CURLcode sslctx_function(CURL * /* curl */, void *sslctx, void * /* parm
}
#endif
-HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::shared_ptr<const Response> response_)
- : context(HTTPCURLContext::Get(loop)),
- request(request_),
+HTTPRequest::HTTPRequest(HTTPCURLContext* context_, const Resource& resource_, Callback callback_, uv_loop_t*, std::shared_ptr<const Response> response_)
+ : RequestBase(resource_, callback_),
+ context(context_),
existingResponse(response_),
handle(context->getHandle()) {
- assert(request);
- context->addRequest(request);
+ context->addRequest(this);
// Zero out the error buffer.
memset(error, 0, sizeof(error));
@@ -463,7 +478,7 @@ HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::sh
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_URL, resource.url.c_str()));
handleError(curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback));
handleError(curl_easy_setopt(handle, CURLOPT_WRITEDATA, this));
handleError(curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerCallback));
@@ -475,28 +490,10 @@ HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::sh
start();
}
-void HTTPRequestImpl::abandon() {
- if (request) {
- context->removeRequest(request);
- request = nullptr;
- }
-}
-
-void HTTPRequestImpl::start() {
- // Count up the attempts.
- attempts++;
-
- // Start requesting the information.
- handleError(curl_multi_add_handle(context->multi, handle));
-}
-
-HTTPRequestImpl::~HTTPRequestImpl() {
+HTTPRequest::~HTTPRequest() {
MBGL_VERIFY_THREAD(tid);
- if (request) {
- context->removeRequest(request);
- request->impl = nullptr;
- }
+ context->removeRequest(this);
handleError(curl_multi_remove_handle(context->multi, handle));
context->returnHandle(handle);
@@ -515,11 +512,23 @@ HTTPRequestImpl::~HTTPRequestImpl() {
}
}
+void HTTPRequest::cancel() {
+ delete this;
+}
+
+void HTTPRequest::start() {
+ // Count up the attempts.
+ attempts++;
+
+ // Start requesting the information.
+ handleError(curl_multi_add_handle(context->multi, handle));
+}
+
// This function is called when we have new data for a request. We just append it to the string
// containing the previous data.
-size_t HTTPRequestImpl::writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp) {
+size_t HTTPRequest::writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp) {
assert(userp);
- auto impl = reinterpret_cast<HTTPRequestImpl *>(userp);
+ auto impl = reinterpret_cast<HTTPRequest *>(userp);
MBGL_VERIFY_THREAD(impl->tid);
if (!impl->response) {
@@ -561,9 +570,9 @@ int64_t parseCacheControl(const char *value) {
return 0;
}
-size_t HTTPRequestImpl::headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp) {
+size_t HTTPRequest::headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp) {
assert(userp);
- auto baton = reinterpret_cast<HTTPRequestImpl *>(userp);
+ auto baton = reinterpret_cast<HTTPRequest *>(userp);
MBGL_VERIFY_THREAD(baton->tid);
if (!baton->response) {
@@ -590,8 +599,7 @@ size_t HTTPRequestImpl::headerCallback(char *const buffer, const size_t size, co
return length;
}
-
-void HTTPRequestImpl::retry(uint64_t timeout) {
+void HTTPRequest::retry(uint64_t timeout) {
handleError(curl_multi_remove_handle(context->multi, handle));
response.reset();
@@ -603,7 +611,7 @@ void HTTPRequestImpl::retry(uint64_t timeout) {
uv_timer_start(timer, restart, timeout, 0);
}
-void HTTPRequestImpl::retryImmediately() {
+void HTTPRequest::retry() {
// All batons get notified when the network status changed, but some of them
// might not actually wait for the network to become available again.
if (timer && strategy == PreemptImmediately) {
@@ -614,12 +622,12 @@ void HTTPRequestImpl::retryImmediately() {
}
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-void HTTPRequestImpl::restart(uv_timer_t *timer, int) {
+void HTTPRequest::restart(uv_timer_t *timer, int) {
#else
-void HTTPRequestImpl::restart(uv_timer_t *timer) {
+void HTTPRequest::restart(uv_timer_t *timer) {
#endif
// Restart the request.
- auto baton = reinterpret_cast<HTTPRequestImpl *>(timer->data);
+ auto baton = reinterpret_cast<HTTPRequest *>(timer->data);
// Get rid of the timer.
baton->timer = nullptr;
@@ -628,7 +636,7 @@ void HTTPRequestImpl::restart(uv_timer_t *timer) {
baton->start();
}
-void HTTPRequestImpl::finish(ResponseStatus status) {
+void HTTPRequest::finish(ResponseStatus status) {
if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) {
strategy = ExponentialBackoff;
return retry((1 << (attempts - 1)) * 1000);
@@ -641,19 +649,18 @@ void HTTPRequestImpl::finish(ResponseStatus status) {
// Actually return the response.
if (status == ResponseStatus::NotModified) {
- request->notify(std::move(response), FileCache::Hint::Refresh);
+ notify(std::move(response), FileCache::Hint::Refresh);
} else {
- request->notify(std::move(response), FileCache::Hint::Full);
+ notify(std::move(response), FileCache::Hint::Full);
}
- delete request;
delete this;
}
-void HTTPRequestImpl::handleResult(CURLcode code) {
+void HTTPRequest::handleResult(CURLcode code) {
MBGL_VERIFY_THREAD(tid);
- if (!request) {
+ if (cancelled) {
// In this case, it doesn't make sense to even process the response even further since
// the request was canceled anyway.
delete this;
@@ -721,30 +728,8 @@ void HTTPRequestImpl::handleResult(CURLcode code) {
throw std::runtime_error("Response hasn't been handled");
}
-// -------------------------------------------------------------------------------------------------
-
-HTTPRequest::HTTPRequest(const Resource& resource_, Callback callback_,
- uv_loop_t* loop, std::shared_ptr<const Response> response)
- : RequestBase(resource_, callback_)
- , impl(new HTTPRequestImpl(this, loop, response)) {
-}
-
-HTTPRequest::~HTTPRequest() {
- if (impl) {
- impl->abandon();
- }
-}
-
-void HTTPRequest::retryImmediately() {
- if (impl) {
- impl->retryImmediately();
- }
-}
-
-void HTTPRequest::cancel() {
- delete impl;
- impl = nullptr;
- delete this;
+std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
+ return util::make_unique<HTTPCURLContext>(loop);
}
}
diff --git a/src/mbgl/storage/asset_context.hpp b/src/mbgl/storage/asset_context.hpp
new file mode 100644
index 0000000000..44ebdba4ff
--- /dev/null
+++ b/src/mbgl/storage/asset_context.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STORAGE_DEFAULT_ASSET_CONTEXT
+#define MBGL_STORAGE_DEFAULT_ASSET_CONTEXT
+
+#include <mbgl/storage/request_base.hpp>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace mbgl {
+
+class AssetContext {
+public:
+ static std::unique_ptr<AssetContext> createContext(uv_loop_t*);
+
+ virtual ~AssetContext() = default;
+ virtual RequestBase* createRequest(const Resource&,
+ RequestBase::Callback,
+ uv_loop_t*,
+ const std::string& assetRoot) = 0;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/storage/asset_request.hpp b/src/mbgl/storage/asset_request.hpp
deleted file mode 100644
index 3f9b018b54..0000000000
--- a/src/mbgl/storage/asset_request.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef MBGL_STORAGE_DEFAULT_ASSET_REQUEST
-#define MBGL_STORAGE_DEFAULT_ASSET_REQUEST
-
-#include "request_base.hpp"
-
-typedef struct uv_loop_s uv_loop_t;
-
-namespace mbgl {
-
-class AssetRequestImpl;
-
-class AssetRequest : public RequestBase {
-public:
- AssetRequest(const Resource&, Callback, uv_loop_t*, const std::string& assetRoot);
-
- void cancel() override;
-
-private:
- ~AssetRequest();
-
- AssetRequestImpl* impl;
- friend class AssetRequestImpl;
-};
-
-}
-
-#endif
diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp
index b652e5e716..7ddfa08d93 100644
--- a/src/mbgl/storage/default_file_source.cpp
+++ b/src/mbgl/storage/default_file_source.cpp
@@ -1,7 +1,7 @@
#include <mbgl/storage/default_file_source_impl.hpp>
#include <mbgl/storage/request.hpp>
-#include <mbgl/storage/asset_request.hpp>
-#include <mbgl/storage/http_request.hpp>
+#include <mbgl/storage/asset_context.hpp>
+#include <mbgl/storage/http_context.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/platform.hpp>
@@ -64,7 +64,9 @@ void DefaultFileSource::cancel(Request *req) {
DefaultFileSource::Impl::Impl(uv_loop_t* loop_, FileCache* cache_, const std::string& root)
: loop(loop_),
cache(cache_),
- assetRoot(root.empty() ? platform::assetRoot() : root) {
+ assetRoot(root.empty() ? platform::assetRoot() : root),
+ assetContext(AssetContext::createContext(loop_)),
+ httpContext(HTTPContext::createContext(loop_)) {
}
DefaultFileRequest* DefaultFileSource::Impl::find(const Resource& resource) {
@@ -130,9 +132,9 @@ void DefaultFileSource::Impl::startRealRequest(const Resource& resource, std::sh
};
if (algo::starts_with(resource.url, "asset://")) {
- request->request = new AssetRequest(resource, callback, loop, assetRoot);
+ request->request = assetContext->createRequest(resource, callback, loop, assetRoot);
} else {
- request->request = new HTTPRequest(resource, callback, loop, response);
+ request->request = httpContext->createRequest(resource, callback, loop, response);
}
}
diff --git a/src/mbgl/storage/default_file_source_impl.hpp b/src/mbgl/storage/default_file_source_impl.hpp
index 1d42f474ff..ed2d248d0a 100644
--- a/src/mbgl/storage/default_file_source_impl.hpp
+++ b/src/mbgl/storage/default_file_source_impl.hpp
@@ -2,6 +2,8 @@
#define MBGL_STORAGE_DEFAULT_DEFAULT_FILE_SOURCE_IMPL
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/asset_context.hpp>
+#include <mbgl/storage/http_context.hpp>
#include <set>
#include <unordered_map>
@@ -39,6 +41,8 @@ private:
uv_loop_t* loop = nullptr;
FileCache* cache = nullptr;
const std::string assetRoot;
+ std::unique_ptr<AssetContext> assetContext;
+ std::unique_ptr<HTTPContext> httpContext;
};
}
diff --git a/src/mbgl/storage/http_context.cpp b/src/mbgl/storage/http_context.cpp
new file mode 100644
index 0000000000..c747490804
--- /dev/null
+++ b/src/mbgl/storage/http_context.cpp
@@ -0,0 +1,30 @@
+#include <mbgl/storage/http_context.hpp>
+
+namespace mbgl {
+
+HTTPContext::HTTPContext(uv_loop_t* loop_)
+ : reachability(loop_, [this] { retryRequests(); }) {
+ NetworkStatus::Subscribe(reachability.get());
+ reachability.unref();
+}
+
+HTTPContext::~HTTPContext() {
+ assert(requests.empty());
+ NetworkStatus::Unsubscribe(reachability.get());
+}
+
+void HTTPContext::addRequest(RequestBase* request) {
+ requests.insert(request);
+}
+
+void HTTPContext::removeRequest(RequestBase* request) {
+ requests.erase(request);
+}
+
+void HTTPContext::retryRequests() {
+ for (auto request : requests) {
+ request->retry();
+ }
+}
+
+}
diff --git a/src/mbgl/storage/http_context.hpp b/src/mbgl/storage/http_context.hpp
index 6b9518dab3..64a8afa6dd 100644
--- a/src/mbgl/storage/http_context.hpp
+++ b/src/mbgl/storage/http_context.hpp
@@ -1,76 +1,40 @@
#ifndef MBGL_STORAGE_DEFAULT_HTTP_CONTEXT
#define MBGL_STORAGE_DEFAULT_HTTP_CONTEXT
-#include "thread_context.hpp"
+#include <mbgl/storage/request_base.hpp>
#include <mbgl/storage/network_status.hpp>
+#include <mbgl/util/uv_detail.hpp>
#include <set>
namespace mbgl {
-class HTTPRequest;
+class HTTPContext {
+public:
+ static std::unique_ptr<HTTPContext> createContext(uv_loop_t*);
-// This is a template class that provides a per-thread Context object. It can be used by HTTP
-// implementations to store global state. It also implements the NetworkStatus mechanism and
-// triggers immediate retries on all requests waiting for network status changes.
+ HTTPContext(uv_loop_t*);
+ virtual ~HTTPContext();
-template <typename Context>
-class HTTPContext : public ThreadContext<Context> {
-public:
- HTTPContext(uv_loop_t *loop);
- ~HTTPContext();
+ virtual RequestBase* createRequest(const Resource&,
+ RequestBase::Callback,
+ uv_loop_t*,
+ std::shared_ptr<const Response>) = 0;
- void addRequest(HTTPRequest *request);
- void removeRequest(HTTPRequest *baton);
+ void addRequest(RequestBase*);
+ void removeRequest(RequestBase*);
+
+private:
+ void retryRequests();
-public:
// Will be fired when the network status becomes reachable.
- uv_async_t *reachability = nullptr;
+ uv::async reachability;
// A list of all pending HTTPRequestImpls that we need to notify when the network status
// changes.
- std::set<HTTPRequest *> requests;
+ std::set<RequestBase*> requests;
};
-template <typename Context>
-HTTPContext<Context>::HTTPContext(uv_loop_t *loop_)
- : ThreadContext<Context>(loop_) {
- reachability = new uv_async_t;
- reachability->data = this;
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
- uv_async_init(loop_, reachability, [](uv_async_t *async, int) {
-#else
- uv_async_init(loop_, reachability, [](uv_async_t *async) {
-#endif
- for (auto request : reinterpret_cast<Context *>(async->data)->requests) {
- request->retryImmediately();
- }
- });
- // Allow the loop to quit even though this handle is still active.
- uv_unref(reinterpret_cast<uv_handle_t *>(reachability));
- NetworkStatus::Subscribe(reachability);
-}
-
-template <typename Context>
-HTTPContext<Context>::~HTTPContext() {
- MBGL_VERIFY_THREAD(HTTPContext<Context>::tid);
-
- assert(requests.empty());
-
- NetworkStatus::Unsubscribe(reachability);
- uv::close(reachability);
-}
-
-template <typename Context>
-void HTTPContext<Context>::addRequest(HTTPRequest *request) {
- requests.insert(request);
-}
-
-template <typename Context>
-void HTTPContext<Context>::removeRequest(HTTPRequest *request) {
- requests.erase(request);
-}
-
}
#endif
diff --git a/src/mbgl/storage/http_request.hpp b/src/mbgl/storage/http_request.hpp
deleted file mode 100644
index bbe1265c6d..0000000000
--- a/src/mbgl/storage/http_request.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef MBGL_STORAGE_DEFAULT_HTTP_REQUEST
-#define MBGL_STORAGE_DEFAULT_HTTP_REQUEST
-
-#include "request_base.hpp"
-
-typedef struct uv_loop_s uv_loop_t;
-
-namespace mbgl {
-
-class HTTPRequestImpl;
-
-class HTTPRequest : public RequestBase {
-public:
- HTTPRequest(const Resource&, Callback, uv_loop_t*, std::shared_ptr<const Response> = nullptr);
-
- void cancel() override;
- void retryImmediately();
-
-private:
- ~HTTPRequest();
-
- HTTPRequestImpl* impl;
- friend class HTTPRequestImpl;
-};
-
-}
-
-#endif
diff --git a/src/mbgl/storage/request_base.hpp b/src/mbgl/storage/request_base.hpp
index e4ea7117c1..77c1d94229 100644
--- a/src/mbgl/storage/request_base.hpp
+++ b/src/mbgl/storage/request_base.hpp
@@ -23,6 +23,7 @@ public:
virtual ~RequestBase() = default;
virtual void cancel() = 0;
+ virtual void retry() {};
protected:
const Resource& resource;
diff --git a/src/mbgl/storage/thread_context.hpp b/src/mbgl/storage/thread_context.hpp
deleted file mode 100644
index 763c83a25b..0000000000
--- a/src/mbgl/storage/thread_context.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef MBGL_STORAGE_DEFAULT_THREAD_CONTEXT
-#define MBGL_STORAGE_DEFAULT_THREAD_CONTEXT
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/std.hpp>
-#include <mbgl/util/util.hpp>
-#include <mbgl/util/uv.hpp>
-
-#include <uv.h>
-#include <pthread.h>
-
-#include <map>
-#include <cassert>
-
-namespace mbgl {
-
-// This is a template class that provides a per-thread and per-loop Context object. It can be used
-// by implementations to store global state.
-
-template <typename Context>
-class ThreadContext : private util::noncopyable {
-protected:
- MBGL_STORE_THREAD(tid)
- using Map = std::map<uv_loop_t *, std::unique_ptr<Context>>;
-
-public:
- static Context *Get(uv_loop_t *loop);
-
-private:
- static pthread_key_t key;
- static pthread_once_t once;
-
-public:
- ThreadContext(uv_loop_t *loop);
- ~ThreadContext();
-
-public:
- uv_loop_t *loop;
-};
-
-template <typename Context>
-Context *ThreadContext<Context>::Get(uv_loop_t *loop) {
- pthread_once(&once, []() {
- pthread_key_create(&key, [](void *ptr) {
- assert(ptr);
- delete reinterpret_cast<Map *>(ptr);
- });
- });
- auto contexts = reinterpret_cast<Map *>(pthread_getspecific(key));
- if (!contexts) {
- contexts = new Map();
- pthread_setspecific(key, contexts);
- }
-
- // Now find a ThreadContext that matches the requested loop.
- auto it = contexts->find(loop);
- if (it == contexts->end()) {
- auto result = contexts->emplace(loop, util::make_unique<Context>(loop));
- assert(result.second); // Make sure it was actually inserted.
- return result.first->second.get();
- } else {
- return it->second.get();
- }
-}
-
-template <typename Context>
-ThreadContext<Context>::ThreadContext(uv_loop_t *loop_) : loop(loop_) {
-}
-
-template <typename Context>
-ThreadContext<Context>::~ThreadContext() {
- MBGL_VERIFY_THREAD(tid);
-}
-
-
-}
-
-#endif
diff --git a/src/mbgl/util/uv_detail.hpp b/src/mbgl/util/uv_detail.hpp
index 96d5442462..fbc0ec5aa0 100644
--- a/src/mbgl/util/uv_detail.hpp
+++ b/src/mbgl/util/uv_detail.hpp
@@ -104,6 +104,10 @@ public:
uv_unref(reinterpret_cast<uv_handle_t*>(a.get()));
}
+ inline uv_async_t* get() {
+ return a.get();
+ }
+
private:
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
static void async_cb(uv_async_t* a, int) {