diff --git a/android/jni/com/mapswithme/util/HttpClient.cpp b/android/jni/com/mapswithme/util/HttpClient.cpp index a599b11030..e4a1f2a31f 100644 --- a/android/jni/com/mapswithme/util/HttpClient.cpp +++ b/android/jni/com/mapswithme/util/HttpClient.cpp @@ -75,6 +75,12 @@ void SetBoolean(ScopedEnv & env, jobject params, jfieldID const fieldId, bool co RethrowOnJniException(env); } +void SetInt(ScopedEnv & env, jobject params, jfieldID const fieldId, int const value) +{ + env->SetIntField(params, fieldId, value); + RethrowOnJniException(env); +} + // Get string value from HttpClient.Params object, throws JniException. void GetString(ScopedEnv & env, jobject const params, jfieldID const fieldId, std::string & result) { @@ -160,7 +166,8 @@ public: {"receivedUrl", GetHttpParamsFieldId(env, "receivedUrl")}, {"followRedirects", GetHttpParamsFieldId(env, "followRedirects", "Z")}, {"loadHeaders", GetHttpParamsFieldId(env, "loadHeaders", "Z")}, - {"httpResponseCode", GetHttpParamsFieldId(env, "httpResponseCode", "I")}}; + {"httpResponseCode", GetHttpParamsFieldId(env, "httpResponseCode", "I")}, + {"timeoutMillisec", GetHttpParamsFieldId(env, "timeoutMillisec", "I")}}; } jfieldID GetId(std::string const & fieldName) const @@ -232,6 +239,8 @@ bool HttpClient::RunHttpRequest() SetString(env, httpParamsObject.get(), ids.GetId("cookies"), m_cookies); SetBoolean(env, httpParamsObject.get(), ids.GetId("followRedirects"), m_handleRedirects); SetBoolean(env, httpParamsObject.get(), ids.GetId("loadHeaders"), m_loadHeaders); + SetInt(env, httpParamsObject.get(), ids.GetId("timeoutMillisec"), + static_cast(m_timeoutSec * 1000)); SetHeaders(env, httpParamsObject.get(), m_headers); } diff --git a/android/src/com/mapswithme/util/HttpClient.java b/android/src/com/mapswithme/util/HttpClient.java index b57f41afe5..26ea0ffd8a 100644 --- a/android/src/com/mapswithme/util/HttpClient.java +++ b/android/src/com/mapswithme/util/HttpClient.java @@ -56,8 +56,6 @@ public final class HttpClient private final static String TAG = HttpClient.class.getSimpleName(); // TODO(AlexZ): tune for larger files private final static int STREAM_BUFFER_SIZE = 1024 * 64; - // Globally accessible for faster unit-testing - private static int TIMEOUT_IN_MILLISECONDS = 30000; private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.NETWORK); public static Params run(@NonNull final Params p) throws IOException, NullPointerException @@ -91,8 +89,8 @@ public final class HttpClient // Looks like this bug was fixed by switching to OkHttp implementation in this commit: // https://android.googlesource.com/platform/libcore/+/2503556d17b28c7b4e6e514540a77df1627857d0 connection.setInstanceFollowRedirects(p.followRedirects); - connection.setConnectTimeout(TIMEOUT_IN_MILLISECONDS); - connection.setReadTimeout(TIMEOUT_IN_MILLISECONDS); + connection.setConnectTimeout(p.timeoutMillisec); + connection.setReadTimeout(p.timeoutMillisec); connection.setUseCaches(false); connection.setRequestMethod(p.httpMethod); @@ -289,6 +287,7 @@ public final class HttpClient int httpResponseCode = -1; boolean followRedirects = true; boolean loadHeaders; + int timeoutMillisec = 30000; // Simple GET request constructor. public Params(String url) diff --git a/platform/http_client.cpp b/platform/http_client.cpp index aa29bee506..7688a7438c 100644 --- a/platform/http_client.cpp +++ b/platform/http_client.cpp @@ -71,6 +71,11 @@ HttpClient & HttpClient::SetRawHeader(string const & key, string const & value) return *this; } +void HttpClient::SetTimeout(double timeoutSec) +{ + m_timeoutSec = timeoutSec; +} + string const & HttpClient::UrlRequested() const { return m_urlRequested; diff --git a/platform/http_client.hpp b/platform/http_client.hpp index c4bb22d4cd..d21ef6a880 100644 --- a/platform/http_client.hpp +++ b/platform/http_client.hpp @@ -77,6 +77,7 @@ public: // TODO: "false" is now supported on Android only. HttpClient & SetHandleRedirects(bool handle_redirects); HttpClient & SetRawHeader(string const & key, string const & value); + void SetTimeout(double timeoutSec); string const & UrlRequested() const; // @returns empty string in the case of error @@ -117,6 +118,8 @@ private: unordered_map m_headers; bool m_handleRedirects = true; bool m_loadHeaders = false; + // Use 30 seconds timeout by default. + double m_timeoutSec = 30.0; DISALLOW_COPY_AND_MOVE(HttpClient); }; diff --git a/platform/http_client_apple.mm b/platform/http_client_apple.mm index 7c366dafa0..f34e76c193 100644 --- a/platform/http_client_apple.mm +++ b/platform/http_client_apple.mm @@ -48,15 +48,11 @@ extern NSString * gBrowserUserAgent; namespace platform { -// If we try to upload our data from the background fetch handler on iOS, we have ~30 seconds to do that gracefully. -static const double kTimeoutInSeconds = 24.0; - -// TODO(AlexZ): Rewrite to use async implementation for better redirects handling and ability to cancel request from destructor. bool HttpClient::RunHttpRequest() { NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL: static_cast([NSURL URLWithString:@(m_urlRequested.c_str())]) - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:kTimeoutInSeconds]; + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:m_timeoutSec]; // We handle cookies manually. request.HTTPShouldHandleCookies = NO; diff --git a/platform/http_client_curl.cpp b/platform/http_client_curl.cpp index 496e3901dd..a8e8e70bf9 100644 --- a/platform/http_client_curl.cpp +++ b/platform/http_client_curl.cpp @@ -190,6 +190,8 @@ bool HttpClient::RunHttpRequest() if (!m_cookies.empty()) cmd += "-b '" + m_cookies + "' "; + cmd += "-m '" + m_timeoutSec + "' "; + if (!m_bodyData.empty()) { body_deleter.m_fileName = GetTmpFileName(); diff --git a/storage/diff_scheme/diff_scheme_checker.cpp b/storage/diff_scheme/diff_scheme_checker.cpp index 800e909059..0dae962201 100644 --- a/storage/diff_scheme/diff_scheme_checker.cpp +++ b/storage/diff_scheme/diff_scheme_checker.cpp @@ -25,6 +25,8 @@ char const kNameKey[] = "name"; char const kSizeKey[] = "size"; char const kVersionKey[] = "version"; +auto const kTimeoutInSeconds = 5.0; + string SerializeCheckerData(Checker::LocalMapsInfo const & info) { auto mwmsArrayNode = my::NewJSONArray(); @@ -114,10 +116,10 @@ void Checker::Check(LocalMapsInfo const & info, Callback const & fn) threads::SimpleThread thread([info, fn] { platform::HttpClient request(DIFF_LIST_URL); - // TODO(Vlad): Check request's time. string const body = SerializeCheckerData(info); ASSERT(!body.empty(), ()); request.SetBodyData(body, "application/json"); + request.SetTimeout(kTimeoutInSeconds); NameFileInfoMap diffs; if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200) diffs = DeserializeResponse(request.ServerResponse(), info.m_localMaps);