PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/platforms/ios/Pods/WeexSDK/ios/sdk/WeexSDK/Sources/Module/WXStreamModule.m

https://bitbucket.org/SitongChen/weexdemo
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
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. #import "WXStreamModule.h"
  20. #import "WXSDKManager.h"
  21. #import "WXUtility.h"
  22. #import "WXHandlerFactory.h"
  23. #import "WXNetworkProtocol.h"
  24. #import "WXURLRewriteProtocol.h"
  25. #import "WXResourceLoader.h"
  26. #import "WXSDKEngine.h"
  27. @implementation WXStreamModule
  28. @synthesize weexInstance;
  29. WX_EXPORT_METHOD(@selector(sendHttp:callback:))
  30. WX_EXPORT_METHOD(@selector(fetch:callback:progressCallback:))
  31. WX_EXPORT_METHOD(@selector(fetchWithArrayBuffer:options:callback:progressCallback:))
  32. - (void)fetch:(NSDictionary *)options callback:(WXModuleCallback)callback progressCallback:(WXModuleKeepAliveCallback)progressCallback
  33. {
  34. __block NSInteger received = 0;
  35. __block NSHTTPURLResponse *httpResponse = nil;
  36. __block NSMutableDictionary * callbackRsp =[[NSMutableDictionary alloc] init];
  37. __block NSString *statusText = @"ERR_CONNECT_FAILED";
  38. //build stream request
  39. WXResourceRequest * request = [self _buildRequestWithOptions:options callbackRsp:callbackRsp];
  40. if (!request) {
  41. if (callback) {
  42. callback(callbackRsp);
  43. }
  44. // failed with some invaild inputs
  45. return ;
  46. }
  47. // notify to start request state
  48. if (progressCallback) {
  49. progressCallback(callbackRsp, TRUE);
  50. }
  51. WXResourceLoader *loader = [[WXResourceLoader alloc] initWithRequest:request];
  52. __weak typeof(self) weakSelf = self;
  53. loader.onResponseReceived = ^(const WXResourceResponse *response) {
  54. httpResponse = (NSHTTPURLResponse*)response;
  55. if (weakSelf) {
  56. [callbackRsp setObject:@{ @"HEADERS_RECEIVED" : @2 } forKey:@"readyState"];
  57. [callbackRsp setObject:[NSNumber numberWithInteger:httpResponse.statusCode] forKey:@"status"];
  58. [callbackRsp setObject:httpResponse.allHeaderFields forKey:@"headers"];
  59. statusText = [WXStreamModule _getStatusText:httpResponse.statusCode];
  60. [callbackRsp setObject:statusText forKey:@"statusText"];
  61. [callbackRsp setObject:[NSNumber numberWithInteger:received] forKey:@"length"];
  62. if (progressCallback) {
  63. progressCallback(callbackRsp, TRUE);
  64. }
  65. }
  66. };
  67. loader.onDataReceived = ^(NSData *data) {
  68. if (weakSelf) {
  69. [callbackRsp setObject:@{ @"LOADING" : @3 } forKey:@"readyState"];
  70. received += [data length];
  71. [callbackRsp setObject:[NSNumber numberWithInteger:received] forKey:@"length"];
  72. if (progressCallback) {
  73. progressCallback(callbackRsp, TRUE);
  74. }
  75. }
  76. };
  77. loader.onFinished = ^(const WXResourceResponse * response, NSData *data) {
  78. if (weakSelf && callback) {
  79. [weakSelf _loadFinishWithResponse:[response copy] data:data callbackRsp:callbackRsp];
  80. callback(callbackRsp);
  81. }
  82. };
  83. loader.onFailed = ^(NSError *error) {
  84. if (weakSelf && callback) {
  85. [weakSelf _loadFailedWithError:error callbackRsp:callbackRsp];
  86. callback(callbackRsp);
  87. }
  88. };
  89. [loader start];
  90. }
  91. - (void)fetchWithArrayBuffer:(id)arrayBuffer options:(NSDictionary *)options callback:(WXModuleCallback)callback progressCallback:(WXModuleKeepAliveCallback)progressCallback
  92. {
  93. NSMutableDictionary *newOptions = [options mutableCopy];
  94. if([arrayBuffer isKindOfClass:[NSDictionary class]]){
  95. NSData *sendData = [WXUtility base64DictToData:arrayBuffer];
  96. if(sendData){
  97. [newOptions setObject:sendData forKey:@"body"];
  98. }
  99. }
  100. [self fetch:newOptions callback:callback progressCallback:progressCallback];
  101. }
  102. - (WXResourceRequest*)_buildRequestWithOptions:(NSDictionary*)options callbackRsp:(NSMutableDictionary*)callbackRsp
  103. {
  104. // parse request url
  105. NSString *urlStr = [options objectForKey:@"url"];
  106. NSString *newURL = [urlStr copy];
  107. WX_REWRITE_URL(urlStr, WXResourceTypeLink, self.weexInstance)
  108. urlStr = newURL;
  109. if (!options || [WXUtility isBlankString:urlStr]) {
  110. [callbackRsp setObject:@(-1) forKey:@"status"];
  111. [callbackRsp setObject:@NO forKey:@"ok"];
  112. return nil;
  113. }
  114. WXResourceRequest *request = [WXResourceRequest requestWithURL:[NSURL URLWithString:urlStr] resourceType:WXResourceTypeOthers referrer:nil cachePolicy:NSURLRequestUseProtocolCachePolicy];
  115. // parse http method
  116. NSString *method = [options objectForKey:@"method"];
  117. if ([WXUtility isBlankString:method]) {
  118. // default HTTP method is GET
  119. method = @"GET";
  120. }
  121. request.HTTPMethod = method;
  122. //parse responseType
  123. NSString *responseType = [options objectForKey:@"type"];
  124. if ([responseType isKindOfClass:[NSString class]]) {
  125. [callbackRsp setObject:responseType? responseType.lowercaseString:@"" forKey:@"responseType"];
  126. }
  127. //parse timeout
  128. if ([options valueForKey:@"timeout"]){
  129. //the time unit is ms
  130. [request setTimeoutInterval:([[options valueForKey:@"timeout"] floatValue])/1000];
  131. }
  132. //install client userAgent
  133. request.userAgent = [WXUtility userAgent];
  134. // parse custom http headers
  135. NSDictionary *headers = [options objectForKey:@"headers"];
  136. for (NSString *header in headers) {
  137. NSString *value = [headers objectForKey:header];
  138. [request setValue:value forHTTPHeaderField:header];
  139. }
  140. //parse custom body
  141. if ([options objectForKey:@"body"]) {
  142. NSData * body = nil;
  143. if ([[options objectForKey:@"body"] isKindOfClass:[NSString class]]) {
  144. // compatible with the string body
  145. body = [[options objectForKey:@"body"] dataUsingEncoding:NSUTF8StringEncoding];
  146. }
  147. if ([[options objectForKey:@"body"] isKindOfClass:[NSDictionary class]]) {
  148. body = [[WXUtility JSONString:[options objectForKey:@"body"]] dataUsingEncoding:NSUTF8StringEncoding];
  149. }
  150. if (!body) {
  151. [callbackRsp setObject:@(-1) forKey:@"status"];
  152. [callbackRsp setObject:@NO forKey:@"ok"];
  153. return nil;
  154. }
  155. [request setHTTPBody:body];
  156. }
  157. [callbackRsp setObject:@{ @"OPENED": @1 } forKey:@"readyState"];
  158. return request;
  159. }
  160. - (void)_loadFailedWithError:(NSError*)error callbackRsp:(NSMutableDictionary*)callbackRsp
  161. {
  162. [callbackRsp removeObjectForKey:@"readyState"];
  163. [callbackRsp removeObjectForKey:@"length"];
  164. [callbackRsp removeObjectForKey:@"keepalive"];
  165. [callbackRsp removeObjectForKey:@"responseType"];
  166. [callbackRsp setObject:@(-1) forKey:@"status"];
  167. [callbackRsp setObject:[NSString stringWithFormat:@"%@(%ld)",[error localizedDescription], (long)[error code]] forKey:@"data"];
  168. NSString * statusText = @"";
  169. switch ([error code]) {
  170. case -1000:
  171. case -1002:
  172. case -1003:
  173. statusText = @"ERR_INVALID_REQUEST";
  174. break;
  175. default:
  176. break;
  177. }
  178. [callbackRsp setObject:statusText forKey:@"statusText"];
  179. }
  180. - (void)_loadFinishWithResponse:(WXResourceResponse*)response data:(NSData*)data callbackRsp:(NSMutableDictionary*)callbackRsp
  181. {
  182. [callbackRsp removeObjectForKey:@"readyState"];
  183. [callbackRsp removeObjectForKey:@"length"];
  184. [callbackRsp removeObjectForKey:@"keepalive"];
  185. [callbackRsp setObject:((NSHTTPURLResponse*)response).statusCode >= 200 && ((NSHTTPURLResponse*)response).statusCode <= 299 ? @YES : @NO forKey:@"ok"];
  186. NSString *responseData = [self _stringfromData:data encode:((NSHTTPURLResponse*)response).textEncodingName];
  187. NSString * responseType = [callbackRsp objectForKey:@"responseType"];
  188. [callbackRsp removeObjectForKey:@"responseType"];
  189. if ([responseType isEqualToString:@"json"] || [responseType isEqualToString:@"jsonp"]) {
  190. //handle json format
  191. if ([responseType isEqualToString:@"jsonp"]) {
  192. //TODO: to be more elegant
  193. NSUInteger start = [responseData rangeOfString:@"("].location + 1 ;
  194. NSUInteger end = [responseData rangeOfString:@")" options:NSBackwardsSearch].location;
  195. if (end < [responseData length] && end > start) {
  196. responseData = [responseData substringWithRange:NSMakeRange(start, end-start)];
  197. }
  198. }
  199. id jsonObj = [self _JSONObjFromData:[responseData dataUsingEncoding:NSUTF8StringEncoding]];
  200. if (jsonObj) {
  201. [callbackRsp setObject:jsonObj forKey:@"data"];
  202. }
  203. } else {
  204. // return original Data
  205. if (responseData) {
  206. [callbackRsp setObject:responseData forKey:@"data"];
  207. }
  208. }
  209. }
  210. - (NSString*)_stringfromData:(NSData *)data encode:(NSString *)encoding
  211. {
  212. NSMutableString *responseData = nil;
  213. if (data) {
  214. if (!encoding) {
  215. encoding = @"utf-8";
  216. }
  217. CFStringEncoding cfStrEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encoding);
  218. if (cfStrEncoding == kCFStringEncodingInvalidId) {
  219. WXLogError(@"not supported encode");
  220. } else {
  221. NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(cfStrEncoding);
  222. responseData = [[NSMutableString alloc]initWithData:data encoding:encoding];
  223. }
  224. }
  225. return responseData;
  226. }
  227. - (id)_JSONObjFromData:(NSData *)data
  228. {
  229. NSError * error = nil;
  230. id jsonObj = [WXUtility JSONObject:data error:&error];
  231. if (error) {
  232. WXLogDebug(@"%@", [error description]);
  233. }
  234. return jsonObj;
  235. }
  236. + (NSString*)_getStatusText:(NSInteger)code
  237. {
  238. switch (code) {
  239. case -1:
  240. return @"ERR_INVALID_REQUEST";
  241. case 100:
  242. return @"Continue";
  243. break;
  244. case 101:
  245. return @"Switching Protocol";
  246. case 102:
  247. return @"Processing";
  248. case 200:
  249. return @"OK";
  250. case 201:
  251. return @"Created";
  252. case 202:
  253. return @"Accepted";
  254. case 203:
  255. return @"Non-Authoritative Information";
  256. case 204:
  257. return @"No Content";
  258. case 205:
  259. return @" Reset Content";
  260. case 206:
  261. return @"Partial Content";
  262. case 207:
  263. return @"Multi-Status";
  264. case 208:
  265. return @"Already Reported";
  266. case 226:
  267. return @"IM Used";
  268. case 300:
  269. return @"Multiple Choices";
  270. case 301:
  271. return @"Moved Permanently";
  272. case 302:
  273. return @"Found";
  274. case 303:
  275. return @"See Other";
  276. case 304:
  277. return @"Not Modified";
  278. case 305:
  279. return @"Use Proxy";
  280. case 306:
  281. return @"Switch Proxy";
  282. case 307:
  283. return @"Temporary Redirect";
  284. case 308:
  285. return @"Permanent Redirect";
  286. case 400:
  287. return @"Bad Request";
  288. case 401:
  289. return @"Unauthorized";
  290. case 402:
  291. return @"Payment Required";
  292. case 403:
  293. return @"Forbidden";
  294. case 404:
  295. return @"Not Found";
  296. case 405:
  297. return @"Method Not Allowed";
  298. case 406:
  299. return @"Not Acceptable";
  300. case 407:
  301. return @"Proxy Authentication Required";
  302. case 408:
  303. return @"Request Timeout";
  304. case 409:
  305. return @"Conflict";
  306. case 410:
  307. return @"Gone";
  308. case 411:
  309. return @"Length Required";
  310. case 412:
  311. return @"Precondition Failed";
  312. case 413:
  313. return @"Payload Too Large";
  314. case 414:
  315. return @"URI Too Long";
  316. case 415:
  317. return @"Unsupported Media Type";
  318. case 416:
  319. return @"Range Not Satisfiable";
  320. case 417:
  321. return @"Expectation Failed";
  322. case 418:
  323. return @"I'm a teapot";
  324. case 421:
  325. return @"Misdirected Request";
  326. case 422:
  327. return @"Unprocessable Entity";
  328. case 423:
  329. return @"Locked";
  330. case 424:
  331. return @"Failed Dependency";
  332. case 426:
  333. return @"Upgrade Required";
  334. case 428:
  335. return @"Precondition Required";
  336. case 429:
  337. return @"Too Many Requests";
  338. case 431:
  339. return @"Request Header Fields Too Large";
  340. case 451:
  341. return @"Unavailable For Legal Reasons";
  342. case 500:
  343. return @"Internal Server Error";
  344. case 501:
  345. return @"Not Implemented";
  346. case 502:
  347. return @"Bad Gateway";
  348. case 503:
  349. return @"Service Unavailable";
  350. case 504:
  351. return @"Gateway Timeout";
  352. case 505:
  353. return @"HTTP Version Not Supported";
  354. case 506:
  355. return @"Variant Also Negotiates";
  356. case 507:
  357. return @"Insufficient Storage";
  358. case 508:
  359. return @"Loop Detected";
  360. case 510:
  361. return @"Not Extended";
  362. case 511:
  363. return @"Network Authentication Required";
  364. default:
  365. break;
  366. }
  367. return @"Unknown";
  368. }
  369. #pragma mark - Deprecated
  370. - (void)sendHttp:(NSDictionary*)param callback:(WXModuleCallback)callback
  371. {
  372. NSString* method = [param objectForKey:@"method"];
  373. NSString* urlStr = [param objectForKey:@"url"];
  374. NSDictionary* headers = [param objectForKey:@"header"];
  375. NSString* body = [param objectForKey:@"body"];
  376. NSURL *url = [NSURL URLWithString:urlStr];
  377. //TODO:referrer
  378. WXResourceRequest *request = [WXResourceRequest requestWithURL:url resourceType:WXResourceTypeOthers referrer:nil cachePolicy:NSURLRequestUseProtocolCachePolicy];
  379. request.HTTPMethod = method;
  380. request.timeoutInterval = 60.0;
  381. request.userAgent = [WXUtility userAgent];
  382. for (NSString *key in headers) {
  383. NSString *value = [headers objectForKey:key];
  384. [request setValue:value forHTTPHeaderField:key];
  385. }
  386. [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
  387. WXResourceLoader *loader = [[WXResourceLoader alloc] initWithRequest:request];
  388. loader.onFinished = ^(const WXResourceResponse * response, NSData *data) {
  389. NSString* responseData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  390. callback(responseData);
  391. };
  392. loader.onFailed = ^(NSError *error) {
  393. if (callback) {
  394. callback(nil);
  395. }
  396. };
  397. [loader start];
  398. }
  399. @end