/platforms/ios/Pods/WeexSDK/ios/sdk/WeexSDK/Sources/Module/WXStreamModule.m
Objective C | 449 lines | 364 code | 50 blank | 35 comment | 42 complexity | 04fafd65a457d6dca2bde0ff39f50697 MD5 | raw file
Possible License(s): BSD-2-Clause, GPL-3.0, 0BSD, BSD-3-Clause, CC-BY-4.0, JSON, CC-BY-SA-3.0, GPL-2.0, MIT, Apache-2.0, Unlicense
- /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
- #import "WXStreamModule.h"
- #import "WXSDKManager.h"
- #import "WXUtility.h"
- #import "WXHandlerFactory.h"
- #import "WXNetworkProtocol.h"
- #import "WXURLRewriteProtocol.h"
- #import "WXResourceLoader.h"
- #import "WXSDKEngine.h"
- @implementation WXStreamModule
- @synthesize weexInstance;
- WX_EXPORT_METHOD(@selector(sendHttp:callback:))
- WX_EXPORT_METHOD(@selector(fetch:callback:progressCallback:))
- WX_EXPORT_METHOD(@selector(fetchWithArrayBuffer:options:callback:progressCallback:))
- - (void)fetch:(NSDictionary *)options callback:(WXModuleCallback)callback progressCallback:(WXModuleKeepAliveCallback)progressCallback
- {
- __block NSInteger received = 0;
- __block NSHTTPURLResponse *httpResponse = nil;
- __block NSMutableDictionary * callbackRsp =[[NSMutableDictionary alloc] init];
- __block NSString *statusText = @"ERR_CONNECT_FAILED";
-
- //build stream request
- WXResourceRequest * request = [self _buildRequestWithOptions:options callbackRsp:callbackRsp];
- if (!request) {
- if (callback) {
- callback(callbackRsp);
- }
- // failed with some invaild inputs
- return ;
- }
-
- // notify to start request state
- if (progressCallback) {
- progressCallback(callbackRsp, TRUE);
- }
-
- WXResourceLoader *loader = [[WXResourceLoader alloc] initWithRequest:request];
- __weak typeof(self) weakSelf = self;
- loader.onResponseReceived = ^(const WXResourceResponse *response) {
- httpResponse = (NSHTTPURLResponse*)response;
- if (weakSelf) {
- [callbackRsp setObject:@{ @"HEADERS_RECEIVED" : @2 } forKey:@"readyState"];
- [callbackRsp setObject:[NSNumber numberWithInteger:httpResponse.statusCode] forKey:@"status"];
- [callbackRsp setObject:httpResponse.allHeaderFields forKey:@"headers"];
- statusText = [WXStreamModule _getStatusText:httpResponse.statusCode];
- [callbackRsp setObject:statusText forKey:@"statusText"];
- [callbackRsp setObject:[NSNumber numberWithInteger:received] forKey:@"length"];
- if (progressCallback) {
- progressCallback(callbackRsp, TRUE);
- }
- }
- };
-
- loader.onDataReceived = ^(NSData *data) {
- if (weakSelf) {
- [callbackRsp setObject:@{ @"LOADING" : @3 } forKey:@"readyState"];
- received += [data length];
- [callbackRsp setObject:[NSNumber numberWithInteger:received] forKey:@"length"];
- if (progressCallback) {
- progressCallback(callbackRsp, TRUE);
- }
- }
- };
-
- loader.onFinished = ^(const WXResourceResponse * response, NSData *data) {
- if (weakSelf && callback) {
- [weakSelf _loadFinishWithResponse:[response copy] data:data callbackRsp:callbackRsp];
- callback(callbackRsp);
- }
- };
-
- loader.onFailed = ^(NSError *error) {
- if (weakSelf && callback) {
- [weakSelf _loadFailedWithError:error callbackRsp:callbackRsp];
- callback(callbackRsp);
- }
- };
-
- [loader start];
- }
- - (void)fetchWithArrayBuffer:(id)arrayBuffer options:(NSDictionary *)options callback:(WXModuleCallback)callback progressCallback:(WXModuleKeepAliveCallback)progressCallback
- {
- NSMutableDictionary *newOptions = [options mutableCopy];
- if([arrayBuffer isKindOfClass:[NSDictionary class]]){
- NSData *sendData = [WXUtility base64DictToData:arrayBuffer];
- if(sendData){
- [newOptions setObject:sendData forKey:@"body"];
- }
- }
- [self fetch:newOptions callback:callback progressCallback:progressCallback];
- }
- - (WXResourceRequest*)_buildRequestWithOptions:(NSDictionary*)options callbackRsp:(NSMutableDictionary*)callbackRsp
- {
- // parse request url
- NSString *urlStr = [options objectForKey:@"url"];
- NSString *newURL = [urlStr copy];
- WX_REWRITE_URL(urlStr, WXResourceTypeLink, self.weexInstance)
- urlStr = newURL;
-
- if (!options || [WXUtility isBlankString:urlStr]) {
- [callbackRsp setObject:@(-1) forKey:@"status"];
- [callbackRsp setObject:@NO forKey:@"ok"];
-
- return nil;
- }
-
- WXResourceRequest *request = [WXResourceRequest requestWithURL:[NSURL URLWithString:urlStr] resourceType:WXResourceTypeOthers referrer:nil cachePolicy:NSURLRequestUseProtocolCachePolicy];
-
- // parse http method
- NSString *method = [options objectForKey:@"method"];
- if ([WXUtility isBlankString:method]) {
- // default HTTP method is GET
- method = @"GET";
- }
- request.HTTPMethod = method;
-
- //parse responseType
- NSString *responseType = [options objectForKey:@"type"];
- if ([responseType isKindOfClass:[NSString class]]) {
- [callbackRsp setObject:responseType? responseType.lowercaseString:@"" forKey:@"responseType"];
- }
-
- //parse timeout
- if ([options valueForKey:@"timeout"]){
- //the time unit is ms
- [request setTimeoutInterval:([[options valueForKey:@"timeout"] floatValue])/1000];
- }
-
- //install client userAgent
- request.userAgent = [WXUtility userAgent];
-
- // parse custom http headers
- NSDictionary *headers = [options objectForKey:@"headers"];
- for (NSString *header in headers) {
- NSString *value = [headers objectForKey:header];
- [request setValue:value forHTTPHeaderField:header];
- }
-
- //parse custom body
- if ([options objectForKey:@"body"]) {
- NSData * body = nil;
- if ([[options objectForKey:@"body"] isKindOfClass:[NSString class]]) {
- // compatible with the string body
- body = [[options objectForKey:@"body"] dataUsingEncoding:NSUTF8StringEncoding];
- }
- if ([[options objectForKey:@"body"] isKindOfClass:[NSDictionary class]]) {
- body = [[WXUtility JSONString:[options objectForKey:@"body"]] dataUsingEncoding:NSUTF8StringEncoding];
- }
- if (!body) {
- [callbackRsp setObject:@(-1) forKey:@"status"];
- [callbackRsp setObject:@NO forKey:@"ok"];
- return nil;
- }
-
- [request setHTTPBody:body];
- }
-
- [callbackRsp setObject:@{ @"OPENED": @1 } forKey:@"readyState"];
-
- return request;
- }
- - (void)_loadFailedWithError:(NSError*)error callbackRsp:(NSMutableDictionary*)callbackRsp
- {
- [callbackRsp removeObjectForKey:@"readyState"];
- [callbackRsp removeObjectForKey:@"length"];
- [callbackRsp removeObjectForKey:@"keepalive"];
- [callbackRsp removeObjectForKey:@"responseType"];
-
- [callbackRsp setObject:@(-1) forKey:@"status"];
- [callbackRsp setObject:[NSString stringWithFormat:@"%@(%ld)",[error localizedDescription], (long)[error code]] forKey:@"data"];
- NSString * statusText = @"";
-
- switch ([error code]) {
- case -1000:
- case -1002:
- case -1003:
- statusText = @"ERR_INVALID_REQUEST";
- break;
- default:
- break;
- }
- [callbackRsp setObject:statusText forKey:@"statusText"];
-
- }
- - (void)_loadFinishWithResponse:(WXResourceResponse*)response data:(NSData*)data callbackRsp:(NSMutableDictionary*)callbackRsp
- {
- [callbackRsp removeObjectForKey:@"readyState"];
- [callbackRsp removeObjectForKey:@"length"];
- [callbackRsp removeObjectForKey:@"keepalive"];
-
- [callbackRsp setObject:((NSHTTPURLResponse*)response).statusCode >= 200 && ((NSHTTPURLResponse*)response).statusCode <= 299 ? @YES : @NO forKey:@"ok"];
-
- NSString *responseData = [self _stringfromData:data encode:((NSHTTPURLResponse*)response).textEncodingName];
- NSString * responseType = [callbackRsp objectForKey:@"responseType"];
- [callbackRsp removeObjectForKey:@"responseType"];
- if ([responseType isEqualToString:@"json"] || [responseType isEqualToString:@"jsonp"]) {
- //handle json format
- if ([responseType isEqualToString:@"jsonp"]) {
- //TODO: to be more elegant
- NSUInteger start = [responseData rangeOfString:@"("].location + 1 ;
- NSUInteger end = [responseData rangeOfString:@")" options:NSBackwardsSearch].location;
- if (end < [responseData length] && end > start) {
- responseData = [responseData substringWithRange:NSMakeRange(start, end-start)];
- }
- }
- id jsonObj = [self _JSONObjFromData:[responseData dataUsingEncoding:NSUTF8StringEncoding]];
- if (jsonObj) {
- [callbackRsp setObject:jsonObj forKey:@"data"];
- }
-
- } else {
- // return original Data
- if (responseData) {
- [callbackRsp setObject:responseData forKey:@"data"];
- }
- }
- }
- - (NSString*)_stringfromData:(NSData *)data encode:(NSString *)encoding
- {
- NSMutableString *responseData = nil;
- if (data) {
- if (!encoding) {
- encoding = @"utf-8";
- }
- CFStringEncoding cfStrEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encoding);
- if (cfStrEncoding == kCFStringEncodingInvalidId) {
- WXLogError(@"not supported encode");
- } else {
- NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(cfStrEncoding);
- responseData = [[NSMutableString alloc]initWithData:data encoding:encoding];
- }
- }
- return responseData;
- }
- - (id)_JSONObjFromData:(NSData *)data
- {
- NSError * error = nil;
- id jsonObj = [WXUtility JSONObject:data error:&error];
- if (error) {
- WXLogDebug(@"%@", [error description]);
- }
- return jsonObj;
- }
- + (NSString*)_getStatusText:(NSInteger)code
- {
- switch (code) {
- case -1:
- return @"ERR_INVALID_REQUEST";
- case 100:
- return @"Continue";
- break;
- case 101:
- return @"Switching Protocol";
- case 102:
- return @"Processing";
-
- case 200:
- return @"OK";
- case 201:
- return @"Created";
- case 202:
- return @"Accepted";
- case 203:
- return @"Non-Authoritative Information";
- case 204:
- return @"No Content";
- case 205:
- return @" Reset Content";
- case 206:
- return @"Partial Content";
- case 207:
- return @"Multi-Status";
- case 208:
- return @"Already Reported";
- case 226:
- return @"IM Used";
-
- case 300:
- return @"Multiple Choices";
- case 301:
- return @"Moved Permanently";
- case 302:
- return @"Found";
- case 303:
- return @"See Other";
- case 304:
- return @"Not Modified";
- case 305:
- return @"Use Proxy";
- case 306:
- return @"Switch Proxy";
- case 307:
- return @"Temporary Redirect";
- case 308:
- return @"Permanent Redirect";
-
- case 400:
- return @"Bad Request";
- case 401:
- return @"Unauthorized";
- case 402:
- return @"Payment Required";
- case 403:
- return @"Forbidden";
- case 404:
- return @"Not Found";
- case 405:
- return @"Method Not Allowed";
- case 406:
- return @"Not Acceptable";
- case 407:
- return @"Proxy Authentication Required";
- case 408:
- return @"Request Timeout";
- case 409:
- return @"Conflict";
- case 410:
- return @"Gone";
- case 411:
- return @"Length Required";
- case 412:
- return @"Precondition Failed";
- case 413:
- return @"Payload Too Large";
- case 414:
- return @"URI Too Long";
- case 415:
- return @"Unsupported Media Type";
- case 416:
- return @"Range Not Satisfiable";
- case 417:
- return @"Expectation Failed";
- case 418:
- return @"I'm a teapot";
- case 421:
- return @"Misdirected Request";
- case 422:
- return @"Unprocessable Entity";
- case 423:
- return @"Locked";
- case 424:
- return @"Failed Dependency";
- case 426:
- return @"Upgrade Required";
- case 428:
- return @"Precondition Required";
- case 429:
- return @"Too Many Requests";
- case 431:
- return @"Request Header Fields Too Large";
- case 451:
- return @"Unavailable For Legal Reasons";
-
- case 500:
- return @"Internal Server Error";
- case 501:
- return @"Not Implemented";
- case 502:
- return @"Bad Gateway";
- case 503:
- return @"Service Unavailable";
- case 504:
- return @"Gateway Timeout";
- case 505:
- return @"HTTP Version Not Supported";
- case 506:
- return @"Variant Also Negotiates";
- case 507:
- return @"Insufficient Storage";
- case 508:
- return @"Loop Detected";
- case 510:
- return @"Not Extended";
- case 511:
- return @"Network Authentication Required";
- default:
- break;
- }
-
- return @"Unknown";
- }
- #pragma mark - Deprecated
- - (void)sendHttp:(NSDictionary*)param callback:(WXModuleCallback)callback
- {
- NSString* method = [param objectForKey:@"method"];
- NSString* urlStr = [param objectForKey:@"url"];
- NSDictionary* headers = [param objectForKey:@"header"];
- NSString* body = [param objectForKey:@"body"];
-
- NSURL *url = [NSURL URLWithString:urlStr];
-
- //TODO:referrer
- WXResourceRequest *request = [WXResourceRequest requestWithURL:url resourceType:WXResourceTypeOthers referrer:nil cachePolicy:NSURLRequestUseProtocolCachePolicy];
- request.HTTPMethod = method;
- request.timeoutInterval = 60.0;
- request.userAgent = [WXUtility userAgent];
-
- for (NSString *key in headers) {
- NSString *value = [headers objectForKey:key];
- [request setValue:value forHTTPHeaderField:key];
- }
- [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
-
- WXResourceLoader *loader = [[WXResourceLoader alloc] initWithRequest:request];
- loader.onFinished = ^(const WXResourceResponse * response, NSData *data) {
- NSString* responseData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- callback(responseData);
- };
-
- loader.onFailed = ^(NSError *error) {
- if (callback) {
- callback(nil);
- }
- };
- [loader start];
- }
- @end