[core] Replace time_t with std::chrono::seconds
Added aliases for std::chrono typedefs (eg. 'Seconds' for std::chrono::seconds). These aliases are used together with templated helper functions to replace time_t with std::chrono::seconds for most cases, in particular for 'modified' and 'expires' values in Response.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#ifndef MBGL_STORAGE_RESPONSE
|
||||
#define MBGL_STORAGE_RESPONSE
|
||||
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -25,8 +27,8 @@ public:
|
||||
// The actual data of the response. This is guaranteed to never be empty.
|
||||
std::shared_ptr<const std::string> data;
|
||||
|
||||
int64_t modified = 0;
|
||||
int64_t expires = 0;
|
||||
Seconds modified = Seconds::zero();
|
||||
Seconds expires = Seconds::zero();
|
||||
std::string etag;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,9 +8,40 @@ namespace mbgl {
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using SystemClock = std::chrono::system_clock;
|
||||
|
||||
using Seconds = std::chrono::seconds;
|
||||
using Milliseconds = std::chrono::milliseconds;
|
||||
|
||||
using TimePoint = Clock::time_point;
|
||||
using Duration = Clock::duration;
|
||||
|
||||
using SystemTimePoint = SystemClock::time_point;
|
||||
using SystemDuration = SystemClock::duration;
|
||||
|
||||
template <class _Clock, class _Duration>
|
||||
_Duration toDuration(std::chrono::time_point<_Clock, _Duration> time_point) {
|
||||
return time_point.time_since_epoch();
|
||||
}
|
||||
|
||||
template <class _Duration>
|
||||
Seconds asSeconds(_Duration duration) {
|
||||
return std::chrono::duration_cast<Seconds>(duration);
|
||||
}
|
||||
|
||||
template <class _Clock, class _Duration>
|
||||
Seconds toSeconds(std::chrono::time_point<_Clock, _Duration> time_point) {
|
||||
return asSeconds(toDuration<_Clock, _Duration>(time_point));
|
||||
}
|
||||
|
||||
template <class _Duration>
|
||||
Milliseconds asMilliseconds(_Duration duration) {
|
||||
return std::chrono::duration_cast<Milliseconds>(duration);
|
||||
}
|
||||
|
||||
template <class _Clock, class _Duration>
|
||||
Milliseconds toMilliseconds(std::chrono::time_point<_Clock, _Duration> time_point) {
|
||||
return asMilliseconds(toDuration<_Clock, _Duration>(time_point));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -129,8 +129,8 @@ HTTPAndroidRequest::HTTPAndroidRequest(HTTPAndroidContext* context_, const Resou
|
||||
if (existingResponse) {
|
||||
if (!existingResponse->etag.empty()) {
|
||||
etagStr = existingResponse->etag;
|
||||
} else if (existingResponse->modified) {
|
||||
modifiedStr = util::rfc1123(existingResponse->modified);
|
||||
} else if (existingResponse->modified != Seconds::zero()) {
|
||||
modifiedStr = util::rfc1123(existingResponse->modified.count());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,11 +195,11 @@ void HTTPAndroidRequest::onResponse(int code, std::string message, std::string e
|
||||
response = std::make_unique<Response>();
|
||||
using Error = Response::Error;
|
||||
|
||||
response->modified = parse_date(modified.c_str());
|
||||
response->modified = Seconds(parse_date(modified.c_str()));
|
||||
response->etag = etag;
|
||||
response->expires = parseCacheControl(cacheControl.c_str());
|
||||
if (!expires.empty()) {
|
||||
response->expires = parse_date(expires.c_str());
|
||||
response->expires = Seconds(parse_date(expires.c_str()));
|
||||
}
|
||||
response->data = std::make_shared<std::string>(body);
|
||||
|
||||
|
||||
@@ -114,8 +114,8 @@ HTTPNSURLRequest::HTTPNSURLRequest(HTTPNSURLContext* context_,
|
||||
if (!existingResponse->etag.empty()) {
|
||||
[req addValue:@(existingResponse->etag.c_str())
|
||||
forHTTPHeaderField:@"If-None-Match"];
|
||||
} else if (existingResponse->modified) {
|
||||
const std::string time = util::rfc1123(existingResponse->modified);
|
||||
} else if (existingResponse->modified != Seconds::zero()) {
|
||||
const std::string time = util::rfc1123(existingResponse->modified.count());
|
||||
[req addValue:@(time.c_str()) forHTTPHeaderField:@"If-Modified-Since"];
|
||||
}
|
||||
}
|
||||
@@ -214,12 +214,12 @@ void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *e
|
||||
|
||||
NSString *expires = [headers objectForKey:@"Expires"];
|
||||
if (expires) {
|
||||
response->expires = parse_date([expires UTF8String]);
|
||||
response->expires = Seconds(parse_date([expires UTF8String]));
|
||||
}
|
||||
|
||||
NSString *last_modified = [headers objectForKey:@"Last-Modified"];
|
||||
if (last_modified) {
|
||||
response->modified = parse_date([last_modified UTF8String]);
|
||||
response->modified = Seconds(parse_date([last_modified UTF8String]));
|
||||
}
|
||||
|
||||
NSString *etag = [headers objectForKey:@"ETag"];
|
||||
|
||||
@@ -130,12 +130,12 @@ void AssetRequest::fileStated(uv_fs_t *req) {
|
||||
self->response = std::make_unique<Response>();
|
||||
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
|
||||
#ifdef __APPLE__
|
||||
self->response->modified = stat->st_mtimespec.tv_sec;
|
||||
self->response->modified = Seconds(stat->st_mtimespec.tv_sec);
|
||||
#else
|
||||
self->response->modified = stat->st_mtime;
|
||||
self->response->modified = Seconds(stat->st_mtime);
|
||||
#endif
|
||||
#else
|
||||
self->response->modified = stat->st_mtim.tv_sec;
|
||||
self->response->modified = Seconds(stat->st_mtim.tv_sec);
|
||||
#endif
|
||||
self->response->etag = util::toString(stat->st_ino);
|
||||
const auto size = (unsigned int)(stat->st_size);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/util.hpp>
|
||||
#include <mbgl/util/uv.hpp>
|
||||
|
||||
@@ -187,7 +188,7 @@ void AssetRequest::fileStated(uv_zip_t *zip) {
|
||||
|
||||
// Get the modification time in case we have one.
|
||||
if (zip->stat->valid & ZIP_STAT_MTIME) {
|
||||
response->modified = zip->stat->mtime;
|
||||
response->modified = Seconds(zip->stat->mtime);
|
||||
}
|
||||
|
||||
if (zip->stat->valid & ZIP_STAT_INDEX) {
|
||||
|
||||
@@ -425,9 +425,9 @@ HTTPCURLRequest::HTTPCURLRequest(HTTPCURLContext* context_, const Resource& reso
|
||||
if (!existingResponse->etag.empty()) {
|
||||
const std::string header = std::string("If-None-Match: ") + existingResponse->etag;
|
||||
headers = curl_slist_append(headers, header.c_str());
|
||||
} else if (existingResponse->modified) {
|
||||
} else if (existingResponse->modified != Seconds::zero()) {
|
||||
const std::string time =
|
||||
std::string("If-Modified-Since: ") + util::rfc1123(existingResponse->modified);
|
||||
std::string("If-Modified-Since: ") + util::rfc1123(existingResponse->modified.count());
|
||||
headers = curl_slist_append(headers, time.c_str());
|
||||
}
|
||||
}
|
||||
@@ -525,7 +525,7 @@ size_t HTTPCURLRequest::headerCallback(char *const buffer, const size_t size, co
|
||||
// Always overwrite the modification date; We might already have a value here from the
|
||||
// Date header, but this one is more accurate.
|
||||
const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n
|
||||
baton->response->modified = curl_getdate(value.c_str(), nullptr);
|
||||
baton->response->modified = Seconds(curl_getdate(value.c_str(), nullptr));
|
||||
} else if ((begin = headerMatches("etag: ", buffer, length)) != std::string::npos) {
|
||||
baton->response->etag = { buffer + begin, length - begin - 2 }; // remove \r\n
|
||||
} else if ((begin = headerMatches("cache-control: ", buffer, length)) != std::string::npos) {
|
||||
@@ -533,7 +533,7 @@ size_t HTTPCURLRequest::headerCallback(char *const buffer, const size_t size, co
|
||||
baton->response->expires = parseCacheControl(value.c_str());
|
||||
} else if ((begin = headerMatches("expires: ", buffer, length)) != std::string::npos) {
|
||||
const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n
|
||||
baton->response->expires = curl_getdate(value.c_str(), nullptr);
|
||||
baton->response->expires = Seconds(curl_getdate(value.c_str(), nullptr));
|
||||
}
|
||||
|
||||
return length;
|
||||
|
||||
@@ -118,9 +118,9 @@ void SQLiteCache::Impl::get(const Resource &resource, Callback callback) {
|
||||
// Status codes > 1 indicate an error
|
||||
response->error = std::make_unique<Response::Error>(Response::Error::Reason(status));
|
||||
}
|
||||
response->modified = getStmt->get<int64_t>(1);
|
||||
response->modified = Seconds(getStmt->get<Seconds::rep>(1));
|
||||
response->etag = getStmt->get<std::string>(2);
|
||||
response->expires = getStmt->get<int64_t>(3);
|
||||
response->expires = Seconds(getStmt->get<Seconds::rep>(3));
|
||||
response->data = std::make_shared<std::string>(std::move(getStmt->get<std::string>(4)));
|
||||
if (getStmt->get<int>(5)) { // == compressed
|
||||
response->data = std::make_shared<std::string>(std::move(util::decompress(*response->data)));
|
||||
@@ -177,9 +177,9 @@ void SQLiteCache::Impl::put(const Resource& resource, std::shared_ptr<const Resp
|
||||
putStmt->bind(2 /* status */, 1 /* success */);
|
||||
}
|
||||
putStmt->bind(3 /* kind */, int(resource.kind));
|
||||
putStmt->bind(4 /* modified */, response->modified);
|
||||
putStmt->bind(4 /* modified */, response->modified.count());
|
||||
putStmt->bind(5 /* etag */, response->etag.c_str());
|
||||
putStmt->bind(6 /* expires */, response->expires);
|
||||
putStmt->bind(6 /* expires */, response->expires.count());
|
||||
|
||||
std::string data;
|
||||
if (resource.kind != Resource::SpriteImage && response->data) {
|
||||
@@ -208,7 +208,7 @@ void SQLiteCache::Impl::put(const Resource& resource, std::shared_ptr<const Resp
|
||||
}
|
||||
}
|
||||
|
||||
void SQLiteCache::Impl::refresh(const Resource& resource, int64_t expires) {
|
||||
void SQLiteCache::Impl::refresh(const Resource& resource, Seconds expires) {
|
||||
try {
|
||||
if (!db) {
|
||||
createDatabase();
|
||||
@@ -226,7 +226,7 @@ void SQLiteCache::Impl::refresh(const Resource& resource, int64_t expires) {
|
||||
}
|
||||
|
||||
const auto canonicalURL = util::mapbox::canonicalURL(resource.url);
|
||||
refreshStmt->bind(1, int64_t(expires));
|
||||
refreshStmt->bind(1, expires.count());
|
||||
refreshStmt->bind(2, canonicalURL.c_str());
|
||||
refreshStmt->run();
|
||||
} catch (mapbox::sqlite::Exception& ex) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MBGL_STORAGE_DEFAULT_SQLITE_CACHE_IMPL
|
||||
|
||||
#include <mbgl/storage/sqlite_cache.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
namespace mapbox {
|
||||
namespace sqlite {
|
||||
@@ -19,7 +20,7 @@ public:
|
||||
|
||||
void get(const Resource&, Callback);
|
||||
void put(const Resource& resource, std::shared_ptr<const Response> response);
|
||||
void refresh(const Resource& resource, int64_t expires);
|
||||
void refresh(const Resource& resource, Seconds expires);
|
||||
|
||||
private:
|
||||
void createDatabase();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "node_request.hpp"
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
@@ -43,6 +44,8 @@ v8::Handle<v8::Object> NodeRequest::Create(const mbgl::Resource& resource, mbgl:
|
||||
|
||||
NAN_METHOD(NodeRequest::Respond) {
|
||||
using Error = mbgl::Response::Error;
|
||||
using Milliseconds = mbgl::Milliseconds;
|
||||
|
||||
mbgl::Response response;
|
||||
|
||||
if (info.Length() < 1) {
|
||||
@@ -63,14 +66,14 @@ NAN_METHOD(NodeRequest::Respond) {
|
||||
if (Nan::Has(res, Nan::New("modified").ToLocalChecked()).FromJust()) {
|
||||
const double modified = Nan::Get(res, Nan::New("modified").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value();
|
||||
if (!std::isnan(modified)) {
|
||||
response.modified = modified / 1000; // JS timestamps are milliseconds
|
||||
response.modified = mbgl::asSeconds(Milliseconds(Milliseconds::rep(modified)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Nan::Has(res, Nan::New("expires").ToLocalChecked()).FromJust()) {
|
||||
const double expires = Nan::Get(res, Nan::New("expires").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value();
|
||||
if (!std::isnan(expires)) {
|
||||
response.expires = expires / 1000; // JS timestamps are milliseconds
|
||||
response.expires = mbgl::asSeconds(Milliseconds(Milliseconds::rep(expires)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,17 +231,17 @@ void DefaultFileSource::Impl::reschedule(DefaultFileRequestImpl& request) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto timeout = request.getRetryTimeout();
|
||||
const Seconds timeout = request.getRetryTimeout();
|
||||
|
||||
if (timeout == 0) {
|
||||
if (timeout == Seconds::zero()) {
|
||||
update(request);
|
||||
} else if (timeout > 0) {
|
||||
} else if (timeout > Seconds::zero()) {
|
||||
if (!request.timerRequest) {
|
||||
request.timerRequest = std::make_unique<uv::timer>(util::RunLoop::getLoop());
|
||||
}
|
||||
|
||||
// timeout is in seconds, but the timer takes milliseconds.
|
||||
request.timerRequest->start(1000 * timeout, 0, [this, &request] {
|
||||
request.timerRequest->start(asMilliseconds(timeout).count(), 0, [this, &request] {
|
||||
assert(!request.realRequest);
|
||||
startRealRequest(request);
|
||||
});
|
||||
@@ -298,14 +298,16 @@ const std::shared_ptr<const Response>& DefaultFileRequestImpl::getResponse() con
|
||||
return response;
|
||||
}
|
||||
|
||||
int64_t DefaultFileRequestImpl::getRetryTimeout() const {
|
||||
Seconds DefaultFileRequestImpl::getRetryTimeout() const {
|
||||
Seconds timeout = Seconds::zero();
|
||||
|
||||
if (!response) {
|
||||
// If we don't have a response, we should retry immediately.
|
||||
return 0;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
// A value < 0 means that we should not retry.
|
||||
int64_t timeout = -1;
|
||||
timeout = Seconds(-1);
|
||||
|
||||
if (response->error) {
|
||||
assert(failedRequests > 0);
|
||||
@@ -314,14 +316,14 @@ int64_t DefaultFileRequestImpl::getRetryTimeout() const {
|
||||
// Retry immediately, unless we have a certain number of attempts already
|
||||
const int graceRetries = 3;
|
||||
if (failedRequests <= graceRetries) {
|
||||
timeout = 1;
|
||||
timeout = Seconds(1);
|
||||
} else {
|
||||
timeout = 1 << std::min(failedRequests - graceRetries, 31);
|
||||
timeout = Seconds(1 << std::min(failedRequests - graceRetries, 31));
|
||||
}
|
||||
} break;
|
||||
case Response::Error::Reason::Connection: {
|
||||
// Exponential backoff
|
||||
timeout = 1 << std::min(failedRequests - 1, 31);
|
||||
timeout = Seconds(1 << std::min(failedRequests - 1, 31));
|
||||
} break;
|
||||
default:
|
||||
// Do not retry due to error.
|
||||
@@ -330,14 +332,11 @@ int64_t DefaultFileRequestImpl::getRetryTimeout() const {
|
||||
}
|
||||
|
||||
// Check to see if this response expires earlier than a potential error retry.
|
||||
if (response->expires > 0) {
|
||||
const int64_t expires =
|
||||
response->expires -
|
||||
std::chrono::duration_cast<std::chrono::seconds>(SystemClock::now().time_since_epoch())
|
||||
.count();
|
||||
if (response->expires > Seconds::zero()) {
|
||||
const Seconds secsToExpire = response->expires - toSeconds(SystemClock::now());
|
||||
// Only update the timeout if we don't have one yet, and only if the new timeout is shorter
|
||||
// than the previous one.
|
||||
timeout = timeout < 0 ? expires : std::min(timeout, std::max<int64_t>(0, expires));
|
||||
timeout = timeout < Seconds::zero() ? secsToExpire: std::min(timeout, std::max(Seconds::zero(), secsToExpire));
|
||||
}
|
||||
|
||||
return timeout;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <mbgl/storage/asset_context_base.hpp>
|
||||
#include <mbgl/storage/http_context_base.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
@@ -57,7 +58,7 @@ public:
|
||||
// Returns the seconds we have to wait until we need to redo this request. A value of 0
|
||||
// means that we need to redo it immediately, and a negative value means that we're not setting
|
||||
// a timeout at all.
|
||||
int64_t getRetryTimeout() const;
|
||||
Seconds getRetryTimeout() const;
|
||||
|
||||
// Checks the currently stored response and replaces it with an idential one, except with the
|
||||
// stale flag set, if the response is expired.
|
||||
|
||||
@@ -5,18 +5,15 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
int64_t HTTPRequestBase::parseCacheControl(const char *value) {
|
||||
Seconds HTTPRequestBase::parseCacheControl(const char *value) {
|
||||
if (value) {
|
||||
const auto cacheControl = http::CacheControl::parse(value);
|
||||
|
||||
if (cacheControl.maxAge) {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count() +
|
||||
*cacheControl.maxAge;
|
||||
return toSeconds(SystemClock::now()) + Seconds(*cacheControl.maxAge);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Seconds::zero();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MBGL_STORAGE_HTTP_REQUEST_BASE
|
||||
|
||||
#include <mbgl/storage/request_base.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -16,7 +17,7 @@ public:
|
||||
virtual void cancel() override { cancelled = true; };
|
||||
|
||||
protected:
|
||||
static int64_t parseCacheControl(const char *value);
|
||||
static Seconds parseCacheControl(const char *value);
|
||||
|
||||
bool cancelled;
|
||||
};
|
||||
|
||||
@@ -18,11 +18,8 @@ Response& Response::operator=(const Response& res) {
|
||||
}
|
||||
|
||||
bool Response::isExpired() const {
|
||||
const int64_t now =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(SystemClock::now().time_since_epoch())
|
||||
.count();
|
||||
// Note: expires == 0 also counts as expired!
|
||||
return expires <= now;
|
||||
return SystemTimePoint(expires) <= SystemClock::now();
|
||||
}
|
||||
|
||||
Response::Error::Error(Reason reason_, const std::string& message_)
|
||||
|
||||
20
src/mbgl/util/chrono.cpp
Normal file
20
src/mbgl/util/chrono.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template Duration toDuration<Clock, Duration>(TimePoint);
|
||||
template SystemDuration toDuration<SystemClock, SystemDuration>(SystemTimePoint);
|
||||
|
||||
template Seconds asSeconds<Duration>(Duration);
|
||||
template Seconds asSeconds<Milliseconds>(Milliseconds);
|
||||
|
||||
template Seconds toSeconds<Clock, Duration>(TimePoint);
|
||||
template Seconds toSeconds<SystemClock, SystemDuration>(SystemTimePoint);
|
||||
|
||||
template Milliseconds asMilliseconds<Duration>(Duration);
|
||||
template Milliseconds asMilliseconds<Seconds>(Seconds);
|
||||
|
||||
template Milliseconds toMilliseconds<Clock, Duration>(TimePoint);
|
||||
template Milliseconds toMilliseconds<SystemClock, SystemDuration>(SystemTimePoint);
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/sqlite_cache.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, CacheResponse) {
|
||||
@@ -27,8 +28,8 @@ TEST_F(Storage, CacheResponse) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Response 1", *res.data);
|
||||
EXPECT_LT(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_LT(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
response = res;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/sqlite_cache.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, CacheRevalidateSame) {
|
||||
@@ -31,8 +32,8 @@ TEST_F(Storage, CacheRevalidateSame) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Response", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("snowfall", res.etag);
|
||||
|
||||
req2 = fs.request(revalidateSame, [&, res](Response res2) {
|
||||
@@ -53,8 +54,8 @@ TEST_F(Storage, CacheRevalidateSame) {
|
||||
EXPECT_EQ(res.data, res2.data);
|
||||
EXPECT_EQ("Response", *res2.data);
|
||||
// We use this to indicate that a 304 reply came back.
|
||||
EXPECT_LT(0, res2.expires);
|
||||
EXPECT_EQ(0, res2.modified);
|
||||
EXPECT_LT(Seconds::zero(), res2.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res2.modified);
|
||||
// We're not sending the ETag in the 304 reply, but it should still be there.
|
||||
EXPECT_EQ("snowfall", res2.etag);
|
||||
|
||||
@@ -92,8 +93,8 @@ TEST_F(Storage, CacheRevalidateModified) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Response", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(1420070400, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(1420070400, res.modified.count());
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
req2 = fs.request(revalidateModified, [&, res](Response res2) {
|
||||
@@ -114,8 +115,8 @@ TEST_F(Storage, CacheRevalidateModified) {
|
||||
EXPECT_EQ("Response", *res2.data);
|
||||
EXPECT_EQ(res.data, res2.data);
|
||||
// We use this to indicate that a 304 reply came back.
|
||||
EXPECT_LT(0, res2.expires);
|
||||
EXPECT_EQ(1420070400, res2.modified);
|
||||
EXPECT_LT(Seconds::zero(), res2.expires);
|
||||
EXPECT_EQ(1420070400, res2.modified.count());
|
||||
EXPECT_EQ("", res2.etag);
|
||||
|
||||
loop.stop();
|
||||
@@ -151,8 +152,8 @@ TEST_F(Storage, CacheRevalidateEtag) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Response 1", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("response-1", res.etag);
|
||||
|
||||
req2 = fs.request(revalidateEtag, [&, res](Response res2) {
|
||||
@@ -172,8 +173,8 @@ TEST_F(Storage, CacheRevalidateEtag) {
|
||||
ASSERT_TRUE(res2.data.get());
|
||||
EXPECT_NE(res.data, res2.data);
|
||||
EXPECT_EQ("Response 2", *res2.data);
|
||||
EXPECT_EQ(0, res2.expires);
|
||||
EXPECT_EQ(0, res2.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res2.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res2.modified);
|
||||
EXPECT_EQ("response-2", res2.etag);
|
||||
|
||||
loop.stop();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, AssetReadDirectory) {
|
||||
@@ -24,8 +25,8 @@ TEST_F(Storage, AssetReadDirectory) {
|
||||
EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_FALSE(res.data.get());
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
#ifdef MBGL_ASSET_ZIP
|
||||
EXPECT_EQ("No such file", res.error->message);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, AssetEmptyFile) {
|
||||
@@ -25,8 +26,8 @@ TEST_F(Storage, AssetEmptyFile) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_LT(1420000000, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_LT(1420000000, res.modified.count());
|
||||
EXPECT_NE("", res.etag);
|
||||
loop.stop();
|
||||
EmptyFile.finish();
|
||||
@@ -54,8 +55,8 @@ TEST_F(Storage, AssetNonEmptyFile) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("content is here\n", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_LT(1420000000, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_LT(1420000000, res.modified.count());
|
||||
EXPECT_NE("", res.etag);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("content is here\n", *res.data);
|
||||
@@ -85,8 +86,8 @@ TEST_F(Storage, AssetNonExistentFile) {
|
||||
EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_FALSE(res.data.get());
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
#ifdef MBGL_ASSET_ZIP
|
||||
EXPECT_EQ("No such file", res.error->message);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <cmath>
|
||||
@@ -45,8 +46,8 @@ TEST_F(Storage, HTTPCancelMultiple) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPCancelMultiple.finish();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, HTTPCoalescing) {
|
||||
@@ -31,8 +32,8 @@ TEST_F(Storage, HTTPCoalescing) {
|
||||
EXPECT_EQ(nullptr, res.error);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
if (counter >= total) {
|
||||
@@ -70,8 +71,8 @@ TEST_F(Storage, HTTPMultiple) {
|
||||
EXPECT_EQ(nullptr, res.error);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(2147483647, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(2147483647, res.expires.count());
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
// Start a second request for the same resource after the first one has been completed.
|
||||
@@ -86,8 +87,8 @@ TEST_F(Storage, HTTPMultiple) {
|
||||
EXPECT_EQ(nullptr, res2.error);
|
||||
ASSERT_TRUE(res2.data.get());
|
||||
EXPECT_EQ("Hello World!", *res2.data);
|
||||
EXPECT_EQ(2147483647, res2.expires);
|
||||
EXPECT_EQ(0, res2.modified);
|
||||
EXPECT_EQ(2147483647, res2.expires.count());
|
||||
EXPECT_EQ(Seconds::zero(), res2.modified);
|
||||
EXPECT_EQ("", res2.etag);
|
||||
|
||||
loop.stop();
|
||||
@@ -119,8 +120,8 @@ TEST_F(Storage, HTTPStale) {
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(false, res.stale);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
// Don't start the request twice in case this callback gets fired multiple times.
|
||||
@@ -135,8 +136,8 @@ TEST_F(Storage, HTTPStale) {
|
||||
EXPECT_EQ(nullptr, res2.error);
|
||||
ASSERT_TRUE(res2.data.get());
|
||||
EXPECT_EQ("Hello World!", *res2.data);
|
||||
EXPECT_EQ(0, res2.expires);
|
||||
EXPECT_EQ(0, res2.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res2.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res2.modified);
|
||||
EXPECT_EQ("", res2.etag);
|
||||
|
||||
if (res2.stale) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <cmath>
|
||||
@@ -30,8 +31,8 @@ TEST_F(Storage, HTTPTemporaryError) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
} break;
|
||||
case 1: {
|
||||
@@ -43,8 +44,8 @@ TEST_F(Storage, HTTPTemporaryError) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPTemporaryError.finish();
|
||||
@@ -86,8 +87,8 @@ TEST_F(Storage, HTTPConnectionError) {
|
||||
#endif
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_FALSE(res.data.get());
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
if (counter == 2) {
|
||||
|
||||
@@ -24,8 +24,8 @@ TEST_F(Storage, HTTPExpiresParsing) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(1420797926, res.expires);
|
||||
EXPECT_EQ(1420794326, res.modified);
|
||||
EXPECT_EQ(1420797926, res.expires.count());
|
||||
EXPECT_EQ(1420794326, res.modified.count());
|
||||
EXPECT_EQ("foo", res.etag);
|
||||
loop.stop();
|
||||
HTTPExpiresTest.finish();
|
||||
@@ -42,8 +42,7 @@ TEST_F(Storage, HTTPCacheControlParsing) {
|
||||
DefaultFileSource fs(nullptr);
|
||||
util::RunLoop loop(uv_default_loop());
|
||||
|
||||
int64_t now = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
SystemClock::now().time_since_epoch()).count();
|
||||
const Seconds now = toSeconds(SystemClock::now());
|
||||
|
||||
std::unique_ptr<FileRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test?cachecontrol=max-age=120" },
|
||||
[&](Response res) {
|
||||
@@ -52,8 +51,8 @@ TEST_F(Storage, HTTPCacheControlParsing) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_GT(2, std::abs(res.expires - now - 120)) << "Expiration date isn't about 120 seconds in the future";
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_GT(2, std::abs(res.expires.count() - now.count() - 120)) << "Expiration date isn't about 120 seconds in the future";
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPCacheControlTest.finish();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/sqlite_cache.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
// Test for https://github.com/mapbox/mapbox-gl-native/issue/1369
|
||||
@@ -38,8 +39,8 @@ TEST_F(Storage, HTTPIssue1369) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPIssue1369.finish();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, HTTPLoad) {
|
||||
@@ -29,8 +30,8 @@ TEST_F(Storage, HTTPLoad) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
if (number <= max) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
TEST_F(Storage, HTTPOtherLoop) {
|
||||
@@ -21,8 +22,8 @@ TEST_F(Storage, HTTPOtherLoop) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPOtherLoop.finish();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <future>
|
||||
@@ -26,8 +27,8 @@ TEST_F(Storage, HTTPTest) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPTest.finish();
|
||||
@@ -56,8 +57,8 @@ TEST_F(Storage, HTTP404) {
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Cannot GET /doesnotexist\n", *res.data);
|
||||
EXPECT_EQ("HTTP status code 404", res.error->message);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTP404.finish();
|
||||
@@ -86,8 +87,8 @@ TEST_F(Storage, HTTP500) {
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Server Error!", *res.data);
|
||||
EXPECT_EQ("HTTP status code 500", res.error->message);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTP500.finish();
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
|
||||
// Test for https://github.com/mapbox/mapbox-gl-native/issues/2123
|
||||
//
|
||||
// A request is made. While the request is in progress, the network status changes. This should
|
||||
@@ -30,8 +30,8 @@ TEST_F(Storage, HTTPNetworkStatusChange) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Response", *res.data);
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
loop.stop();
|
||||
HTTPNetworkStatusChange.finish();
|
||||
@@ -90,8 +90,8 @@ TEST_F(Storage, HTTPNetworkStatusChangePreempt) {
|
||||
#endif
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_FALSE(res.data.get());
|
||||
EXPECT_EQ(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_EQ(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
|
||||
if (counter++ == 1) {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
|
||||
TEST_F(Storage, HTTPTimeout) {
|
||||
SCOPED_TEST(HTTPTimeout)
|
||||
|
||||
@@ -24,8 +24,8 @@ TEST_F(Storage, HTTPTimeout) {
|
||||
EXPECT_EQ(false, res.stale);
|
||||
ASSERT_TRUE(res.data.get());
|
||||
EXPECT_EQ("Hello World!", *res.data);
|
||||
EXPECT_LT(0, res.expires);
|
||||
EXPECT_EQ(0, res.modified);
|
||||
EXPECT_LT(Seconds::zero(), res.expires);
|
||||
EXPECT_EQ(Seconds::zero(), res.modified);
|
||||
EXPECT_EQ("", res.etag);
|
||||
if (counter == 4) {
|
||||
req.reset();
|
||||
|
||||
Reference in New Issue
Block a user