diff options
author | M.Stephen <truestyle2005@163.com> | 2019-12-10 00:19:50 +0800 |
---|---|---|
committer | M.Stephen <truestyle2005@163.com> | 2019-12-10 00:19:50 +0800 |
commit | ca723845be6fffacb66874fdacf4308cf14af71b (patch) | |
tree | 27146a8e772c35ebd4d11d70a4b24366c36dc5c7 | |
parent | bc3fb0b1393e4c4bbbf8baa0b4fc1f7045e1b5ca (diff) | |
download | qtlocation-mapboxgl-ca723845be6fffacb66874fdacf4308cf14af71b.tar.gz |
http_file_source
-rw-r--r-- | platform/darwin/src/http_file_source.mm | 264 |
1 files changed, 128 insertions, 136 deletions
diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm index dbf92aa462..43b832633a 100644 --- a/platform/darwin/src/http_file_source.mm +++ b/platform/darwin/src/http_file_source.mm @@ -8,12 +8,7 @@ #import <Foundation/Foundation.h> -#import "MGLLoggingConfiguration_Private.h" -#import "MGLNetworkConfiguration_Private.h" - -#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR -#import "MGLAccountManager_Private.h" -#endif +#import <mbgl/interface/native_apple_interface.h> #include <mutex> #include <chrono> @@ -30,10 +25,10 @@ namespace mbgl { class HTTPRequestShared { public: HTTPRequestShared(Response& response_, util::AsyncTask& async_) - : response(response_), - async(async_) { + : response(response_), + async(async_) { } - + void notify(const Response& response_) { std::lock_guard<std::mutex> lock(mutex); if (!cancelled) { @@ -41,16 +36,16 @@ public: async.send(); } } - + void cancel() { std::lock_guard<std::mutex> lock(mutex); cancelled = true; } - + private: std::mutex mutex; bool cancelled = false; - + Response& response; util::AsyncTask& async; }; @@ -58,24 +53,24 @@ private: class HTTPRequest : public AsyncRequest { public: HTTPRequest(FileSource::Callback callback_) - : shared(std::make_shared<HTTPRequestShared>(response, async)), - callback(callback_) { + : shared(std::make_shared<HTTPRequestShared>(response, async)), + callback(callback_) { } - + ~HTTPRequest() override { shared->cancel(); if (task) { [task cancel]; } } - + std::shared_ptr<HTTPRequestShared> shared; NSURLSessionDataTask* task = nil; - + private: FileSource::Callback callback; Response response; - + util::AsyncTask async { [this] { // Calling `callback` may result in deleting `this`. Copy data to temporaries first. auto callback_ = callback; @@ -88,21 +83,21 @@ class HTTPFileSource::Impl { public: Impl() { @autoreleasepool { - NSURLSessionConfiguration *sessionConfig = [MGLNetworkConfiguration sharedManager].sessionConfiguration; + NSURLSessionConfiguration *sessionConfig = MGLNativeAppleInterfaceTransmitter.shared.sessionConfiguration; session = [NSURLSession sessionWithConfiguration:sessionConfig]; - + userAgent = getUserAgent(); - + #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey]; + accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLNativeAppleInterfaceTransmitter.shared.accountTypeKey]; #endif } } - + NSURLSession* session = nil; NSString* userAgent = nil; NSInteger accountType = 0; - + private: NSString* getUserAgent() const; NSBundle* getSDKBundle() const; @@ -110,7 +105,7 @@ private: NSString *HTTPFileSource::Impl::getUserAgent() const { NSMutableArray *userAgentComponents = [NSMutableArray array]; - + NSBundle *appBundle = [NSBundle mainBundle]; if (appBundle) { NSString *appName = appBundle.infoDictionary[@"CFBundleName"]; @@ -120,7 +115,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { } else { [userAgentComponents addObject:[NSProcessInfo processInfo].processName]; } - + NSBundle *sdkBundle = HTTPFileSource::Impl::getSDKBundle(); if (sdkBundle) { NSString *versionString = sdkBundle.infoDictionary[@"MGLSemanticVersionString"]; @@ -132,12 +127,12 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { sdkBundle.infoDictionary[@"CFBundleName"], versionString]]; } } - + // Avoid %s here because it inserts hidden bidirectional markers on macOS when the system // language is set to a right-to-left language. [userAgentComponents addObject:[NSString stringWithFormat:@"MapboxGL/0.0.0 (%@)", @(mbgl::version::revision)]]; - + NSString *systemName = @"Darwin"; #if TARGET_OS_IPHONE systemName = @"iOS"; @@ -160,7 +155,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { if (systemVersion) { [userAgentComponents addObject:[NSString stringWithFormat:@"%@/%@", systemName, systemVersion]]; } - + NSString *cpu = nil; #if TARGET_CPU_X86 cpu = @"x86"; @@ -174,7 +169,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { if (cpu) { [userAgentComponents addObject:[NSString stringWithFormat:@"(%@)", cpu]]; } - + return [userAgentComponents componentsJoinedByString:@" "]; } @@ -190,12 +185,12 @@ NSBundle *HTTPFileSource::Impl::getSDKBundle() const { } HTTPFileSource::HTTPFileSource() - : impl(std::make_unique<Impl>()) { +: impl(std::make_unique<Impl>()) { } HTTPFileSource::~HTTPFileSource() = default; -MGL_EXPORT +__attribute__((visibility ("default"))) BOOL isValidMapboxEndpoint(NSURL *url) { return ([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"] || @@ -203,7 +198,7 @@ BOOL isValidMapboxEndpoint(NSURL *url) { [url.host hasSuffix:@".mapbox.cn"]); } -MGL_EXPORT +__attribute__((visibility ("default"))) NSURL *resourceURLWithAccountType(const Resource& resource, NSInteger accountType) { NSURL *url = [NSURL URLWithString:@(resource.url.c_str())]; @@ -212,12 +207,12 @@ NSURL *resourceURLWithAccountType(const Resource& resource, NSInteger accountTyp if (accountType == 0 && isValidMapboxEndpoint(url)) { NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; NSMutableArray *queryItems = [NSMutableArray array]; - + if (resource.usage == Resource::Usage::Offline) { [queryItems addObject:[NSURLQueryItem queryItemWithName:@"offline" value:@"true"]]; } else { // Only add SKU token to requests not tagged as "offline" usage. - [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sku" value:MGLAccountManager.skuToken]]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sku" value:MGLNativeAppleInterfaceTransmitter.shared.skuToken]]; } if (components.queryItems) { @@ -232,57 +227,55 @@ NSURL *resourceURLWithAccountType(const Resource& resource, NSInteger accountTyp #endif return url; } - + std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource, Callback callback) { auto request = std::make_unique<HTTPRequest>(callback); auto shared = request->shared; // Explicit copy so that it also gets copied into the completion handler block below. - + @autoreleasepool { NSURL *url = resourceURLWithAccountType(resource, impl->accountType); - MGLLogDebug(@"Requesting URI: %@", url.relativePath); - + NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; if (resource.priorEtag) { [req addValue:@(resource.priorEtag->c_str()) - forHTTPHeaderField:@"If-None-Match"]; + forHTTPHeaderField:@"If-None-Match"]; } else if (resource.priorModified) { [req addValue:@(util::rfc1123(*resource.priorModified).c_str()) - forHTTPHeaderField:@"If-Modified-Since"]; + forHTTPHeaderField:@"If-Modified-Since"]; } - + [req addValue:impl->userAgent forHTTPHeaderField:@"User-Agent"]; - + const bool isTile = resource.kind == mbgl::Resource::Kind::Tile; - + if (isTile) { - [[MGLNetworkConfiguration sharedManager] startDownloadEvent:url.relativePath type:@"tile"]; + [MGLNativeAppleInterfaceTransmitter.shared startDownloadEvent:url.relativePath type:@"tile"]; } request->task = [impl->session - dataTaskWithRequest:req - completionHandler:^(NSData* data, NSURLResponse* res, NSError* error) { - if (error && [error code] == NSURLErrorCancelled) { - [[MGLNetworkConfiguration sharedManager] cancelDownloadEventForResponse:res]; - return; + dataTaskWithRequest:req + completionHandler:^(NSData* data, NSURLResponse* res, NSError* error) { + if (error && [error code] == NSURLErrorCancelled) { + [MGLNativeAppleInterfaceTransmitter.shared cancelDownloadEventForResponse:res]; + return; + } + [MGLNativeAppleInterfaceTransmitter.shared stopDownloadEventForResponse:res]; + Response response; + using Error = Response::Error; + + if (error) { + + if (data) { + response.data = + std::make_shared<std::string>((const char*)[data bytes], [data length]); } - [[MGLNetworkConfiguration sharedManager] stopDownloadEventForResponse:res]; - Response response; - using Error = Response::Error; - - if (error) { - MGLLogError(@"Requesting: %@ failed with error: %@", res.URL.relativePath, error); - - if (data) { - response.data = - std::make_shared<std::string>((const char*)[data bytes], [data length]); - } - - switch ([error code]) { + + switch ([error code]) { case NSURLErrorBadServerResponse: // 5xx errors response.error = std::make_unique<Error>( - Error::Reason::Server, [[error localizedDescription] UTF8String]); + Error::Reason::Server, [[error localizedDescription] UTF8String]); break; - + case NSURLErrorNetworkConnectionLost: case NSURLErrorCannotFindHost: case NSURLErrorCannotConnectToHost: @@ -293,87 +286,86 @@ std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource, case NSURLErrorDataNotAllowed: case NSURLErrorTimedOut: response.error = std::make_unique<Error>( - Error::Reason::Connection, [[error localizedDescription] UTF8String]); + Error::Reason::Connection, [[error localizedDescription] UTF8String]); break; - + default: response.error = std::make_unique<Error>( - Error::Reason::Other, [[error localizedDescription] UTF8String]); + Error::Reason::Other, [[error localizedDescription] UTF8String]); break; + } + } else if ([res isKindOfClass:[NSHTTPURLResponse class]]) { + const long responseCode = [(NSHTTPURLResponse *)res statusCode]; + + NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields]; + NSString *cache_control = [headers objectForKey:@"Cache-Control"]; + if (cache_control) { + const auto cc = http::CacheControl::parse([cache_control UTF8String]); + response.expires = cc.toTimePoint(); + response.mustRevalidate = cc.mustRevalidate; + } + + NSString *expires = [headers objectForKey:@"Expires"]; + if (expires) { + response.expires = util::parseTimestamp([expires UTF8String]); + } + + NSString *last_modified = [headers objectForKey:@"Last-Modified"]; + if (last_modified) { + response.modified = util::parseTimestamp([last_modified UTF8String]); + } + + NSString *etag = [headers objectForKey:@"ETag"]; + if (etag) { + response.etag = std::string([etag UTF8String]); + } + + if (responseCode == 200) { + response.data = std::make_shared<std::string>((const char *)[data bytes], [data length]); + } else if (responseCode == 204 || (responseCode == 404 && isTile)) { + response.noContent = true; + } else if (responseCode == 304) { + response.notModified = true; + } else if (responseCode == 404) { + response.error = + std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404"); + } else if (responseCode == 429) { + // Get the standard header + optional<std::string> retryAfter; + NSString *retryAfterHeader = headers[@"Retry-After"]; + if (retryAfterHeader) { + retryAfter = std::string([retryAfterHeader UTF8String]); } - } else if ([res isKindOfClass:[NSHTTPURLResponse class]]) { - const long responseCode = [(NSHTTPURLResponse *)res statusCode]; - MGLLogDebug(@"Requesting %@ returned responseCode: %lu", res.URL.relativePath, responseCode); - - NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields]; - NSString *cache_control = [headers objectForKey:@"Cache-Control"]; - if (cache_control) { - const auto cc = http::CacheControl::parse([cache_control UTF8String]); - response.expires = cc.toTimePoint(); - response.mustRevalidate = cc.mustRevalidate; - } - - NSString *expires = [headers objectForKey:@"Expires"]; - if (expires) { - response.expires = util::parseTimestamp([expires UTF8String]); - } - - NSString *last_modified = [headers objectForKey:@"Last-Modified"]; - if (last_modified) { - response.modified = util::parseTimestamp([last_modified UTF8String]); - } - - NSString *etag = [headers objectForKey:@"ETag"]; - if (etag) { - response.etag = std::string([etag UTF8String]); - } - - if (responseCode == 200) { - response.data = std::make_shared<std::string>((const char *)[data bytes], [data length]); - } else if (responseCode == 204 || (responseCode == 404 && isTile)) { - response.noContent = true; - } else if (responseCode == 304) { - response.notModified = true; - } else if (responseCode == 404) { - response.error = - std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404"); - } else if (responseCode == 429) { - // Get the standard header - optional<std::string> retryAfter; - NSString *retryAfterHeader = headers[@"Retry-After"]; - if (retryAfterHeader) { - retryAfter = std::string([retryAfterHeader UTF8String]); - } - - // Fallback mapbox specific header - optional<std::string> xRateLimitReset; - NSString *xReset = headers[@"x-rate-limit-reset"]; - if (xReset) { - xRateLimitReset = std::string([xReset UTF8String]); - } - - response.error = std::make_unique<Error>(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset)); - } else if (responseCode >= 500 && responseCode < 600) { - response.error = - std::make_unique<Error>(Error::Reason::Server, std::string{ "HTTP status code " } + - std::to_string(responseCode)); - } else { - response.error = - std::make_unique<Error>(Error::Reason::Other, std::string{ "HTTP status code " } + - std::to_string(responseCode)); + + // Fallback mapbox specific header + optional<std::string> xRateLimitReset; + NSString *xReset = headers[@"x-rate-limit-reset"]; + if (xReset) { + xRateLimitReset = std::string([xReset UTF8String]); } + + response.error = std::make_unique<Error>(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset)); + } else if (responseCode >= 500 && responseCode < 600) { + response.error = + std::make_unique<Error>(Error::Reason::Server, std::string{ "HTTP status code " } + + std::to_string(responseCode)); } else { - // This should never happen. - response.error = std::make_unique<Error>(Error::Reason::Other, - "Response class is not NSHTTPURLResponse"); + response.error = + std::make_unique<Error>(Error::Reason::Other, std::string{ "HTTP status code " } + + std::to_string(responseCode)); } - - shared->notify(response); - }]; - + } else { + // This should never happen. + response.error = std::make_unique<Error>(Error::Reason::Other, + "Response class is not NSHTTPURLResponse"); + } + + shared->notify(response); + }]; + [request->task resume]; } - + return std::move(request); } |