Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Zolotarev <deathbaba@gmail.com>2011-11-08 00:03:58 +0400
committerAlex Zolotarev <alex@maps.me>2015-09-23 01:27:29 +0300
commitcf4d77fa0bae136c90581650e4c72b0267baa0a2 (patch)
tree1164886744cec4a8b83266705475c0e603ee6100 /platform/http_thread_apple.mm
parent4ca29d9593b4890441dc163999302a870b76162a (diff)
[mac][downloader] Finished basic chunks support
Diffstat (limited to 'platform/http_thread_apple.mm')
-rw-r--r--platform/http_thread_apple.mm182
1 files changed, 182 insertions, 0 deletions
diff --git a/platform/http_thread_apple.mm b/platform/http_thread_apple.mm
new file mode 100644
index 0000000000..fabe9d655f
--- /dev/null
+++ b/platform/http_thread_apple.mm
@@ -0,0 +1,182 @@
+#import "http_thread_apple.h"
+
+#include "http_thread_callback.hpp"
+#include "platform.hpp"
+
+#include "../base/logging.hpp"
+
+#define TIMEOUT_IN_SECONDS 15.0
+
+@implementation HttpThread
+
+- (void) dealloc
+{
+ LOG(LDEBUG, ("ID:", [self hash], "Connection is destroyed"));
+ [m_connection cancel];
+ [m_connection release];
+ [super dealloc];
+}
+
+- (void) cancel
+{
+ [m_connection cancel];
+}
+
+- (id) initWith:(string const &)url callback:(downloader::IHttpThreadCallback &)cb begRange:(int64_t)beg
+ endRange:(int64_t)end expectedSize:(int64_t)size postBody:(string const &)pb
+{
+ self = [super init];
+
+ m_callback = &cb;
+ m_begRange = beg;
+ m_endRange = end;
+ m_downloadedBytes = 0;
+ m_expectedSize = size;
+
+ NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:
+ [NSURL URLWithString:[NSString stringWithUTF8String:url.c_str()]]
+ cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:TIMEOUT_IN_SECONDS];
+
+ // use Range header only if we don't download whole file from start
+ if (!(beg == 0 && end < 0))
+ {
+ NSString * val;
+ if (end > 0)
+ {
+ LOG(LDEBUG, (url, "downloading range [", beg, ",", end, "]"));
+ val = [[NSString alloc] initWithFormat: @"bytes=%qi-%qi", beg, end];
+ }
+ else
+ {
+ LOG(LDEBUG, (url, "resuming download from position", beg));
+ val = [[NSString alloc] initWithFormat: @"bytes=%qi-", beg];
+ }
+ [request addValue:val forHTTPHeaderField:@"Range"];
+ [val release];
+ }
+
+ if (!pb.empty())
+ {
+ NSData * postData = [NSData dataWithBytes:pb.data() length:pb.size()];
+ [request setHTTPBody:postData];
+ [request setHTTPMethod:@"POST"];
+ [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
+ }
+ // set user-agent with unique client id only for mapswithme requests
+ if (url.find("mapswithme.com") != string::npos)
+ {
+ static string const uid = GetPlatform().UniqueClientId();
+ [request addValue:[NSString stringWithUTF8String: uid.c_str()] forHTTPHeaderField:@"User-Agent"];
+ }
+
+ // create the connection with the request and start loading the data
+ m_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
+
+ if (m_connection == 0)
+ {
+ LOG(LERROR, ("Can't create connection for", url));
+ [self release];
+ return nil;
+ }
+ else
+ LOG(LDEBUG, ("ID:", [self hash], "Starting connection to", url));
+
+ return self;
+}
+
+/// @return -1 if can't decode
++ (int64_t) getContentRange:(NSDictionary *)httpHeader
+{
+ NSString * cr = [httpHeader valueForKey:@"Content-Range"];
+ if (cr)
+ {
+ NSArray * arr = [cr componentsSeparatedByString:@"/"];
+ if (arr && [arr count])
+ return [(NSString *)[arr objectAtIndex:[arr count] - 1] longLongValue];
+ }
+ return -1;
+}
+
+- (void) connection: (NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response
+{
+ // This method is called when the server has determined that it
+ // has enough information to create the NSURLResponse.
+
+ // check if this is OK (not a 404 or the like)
+ if ([response isKindOfClass:[NSHTTPURLResponse class]])
+ {
+ NSInteger const statusCode = [(NSHTTPURLResponse *)response statusCode];
+ LOG(LDEBUG, ("Got response with status code", statusCode));
+ if (statusCode < 200 || statusCode > 299)
+ {
+ LOG(LWARNING, ("Received HTTP error, canceling download", statusCode));
+ [m_connection cancel];
+ m_callback->OnFinish(statusCode, m_begRange, m_endRange);
+ return;
+ }
+ else if (m_expectedSize > 0)
+ {
+ // get full file expected size from Content-Range header
+ int64_t sizeOnServer = [HttpThread getContentRange:[(NSHTTPURLResponse *)response allHeaderFields]];
+ // if it's absent, use Content-Length instead
+ if (sizeOnServer < 0)
+ sizeOnServer = [response expectedContentLength];
+ if (sizeOnServer > 0 & m_expectedSize != sizeOnServer)
+ {
+
+ LOG(LWARNING, ("Canceling download - server replied with invalid size",
+ sizeOnServer, "!=", m_expectedSize));
+ [m_connection cancel];
+ m_callback->OnFinish(-2, m_begRange, m_endRange);
+ return;
+ }
+ }
+ }
+ else
+ { // in theory, we should never be here
+ LOG(LWARNING, ("Invalid non-http response, aborting request"));
+ [m_connection cancel];
+ m_callback->OnFinish(-1, m_begRange, m_endRange);
+ }
+}
+
+- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
+{
+ int64_t const length = [data length];
+ m_downloadedBytes += length;
+ m_callback->OnWrite(m_begRange + m_downloadedBytes - length, [data bytes], length);
+}
+
+- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
+{
+ LOG(LWARNING, ("Connection failed", [[error localizedDescription] cStringUsingEncoding:NSUTF8StringEncoding]));
+ m_callback->OnFinish([error code], m_begRange, m_endRange);
+}
+
+- (void) connectionDidFinishLoading:(NSURLConnection *)connection
+{
+ m_callback->OnFinish(200, m_begRange, m_endRange);
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////
+namespace downloader
+{
+HttpThread * CreateNativeHttpThread(string const & url,
+ downloader::IHttpThreadCallback & cb,
+ int64_t beg,
+ int64_t end,
+ int64_t size,
+ string const & pb)
+{
+ return [[HttpThread alloc] initWith:url callback:cb begRange:beg endRange:end expectedSize:size postBody:pb];
+}
+
+void DeleteNativeHttpThread(HttpThread * request)
+{
+ [request cancel];
+ [request release];
+}
+
+} // namespace downloader