MKNetworkOperation.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. //
  2. // MKNetwork.h
  3. // MKNetworkKit
  4. //
  5. // Created by Mugunth Kumar (@mugunthkumar) on 11/11/11.
  6. // Copyright (C) 2011-2020 by Steinlogic Consulting and Training Pte Ltd
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. @class MKNetworkOperation;
  25. typedef enum {
  26. MKNetworkOperationStateReady = 1,
  27. MKNetworkOperationStateExecuting = 2,
  28. MKNetworkOperationStateFinished = 3
  29. } MKNetworkOperationState;
  30. typedef void (^MKNKProgressBlock)(double progress);
  31. typedef void (^MKNKResponseBlock)(MKNetworkOperation* completedOperation);
  32. #if TARGET_OS_IPHONE
  33. typedef void (^MKNKImageBlock) (UIImage* fetchedImage, NSURL* url, BOOL isInCache);
  34. #elif TARGET_OS_MAC
  35. typedef void (^MKNKImageBlock) (NSImage* fetchedImage, NSURL* url, BOOL isInCache);
  36. #endif
  37. typedef void (^MKNKErrorBlock)(NSError* error);
  38. typedef void (^MKNKAuthBlock)(NSURLAuthenticationChallenge* challenge);
  39. typedef NSString* (^MKNKEncodingBlock) (NSDictionary* postDataDict);
  40. typedef enum {
  41. MKNKPostDataEncodingTypeURL = 0, // default
  42. MKNKPostDataEncodingTypeJSON,
  43. MKNKPostDataEncodingTypePlist,
  44. MKNKPostDataEncodingTypeCustom
  45. } MKNKPostDataEncodingType;
  46. /*!
  47. @header MKNetworkOperation.h
  48. @abstract Represents a single unique network operation.
  49. */
  50. /*!
  51. * @class MKNetworkOperation
  52. * @abstract Represents a single unique network operation.
  53. *
  54. * @discussion
  55. * You normally create an instance of this class using the methods exposed by MKNetworkEngine
  56. * Created operations are enqueued into the shared queue on MKNetworkEngine
  57. * MKNetworkOperation encapsulates both request and response
  58. * Printing a MKNetworkOperation prints out a cURL command that can be copied and pasted directly on terminal
  59. * Freezable operations are serialized when network connectivity is lost and performed when connection is restored
  60. */
  61. @interface MKNetworkOperation : NSOperation {
  62. @private
  63. int _state;
  64. BOOL _freezable;
  65. MKNKPostDataEncodingType _postDataEncoding;
  66. }
  67. /*!
  68. * @abstract Request URL Property
  69. * @property url
  70. *
  71. * @discussion
  72. * Returns the operation's URL
  73. * This property is readonly cannot be updated.
  74. * To create an operation with a specific URL, use the operationWithURLString:params:httpMethod:
  75. */
  76. @property (nonatomic, readonly) NSString *url;
  77. /*!
  78. * @abstract The internal request object
  79. * @property readonlyRequest
  80. *
  81. * @discussion
  82. * Returns the operation's actual request object
  83. * This property is readonly cannot be modified.
  84. * To create an operation with a new request, use the operationWithURLString:params:httpMethod:
  85. */
  86. @property (nonatomic, strong, readonly) NSURLRequest *readonlyRequest;
  87. /*!
  88. * @abstract The internal HTTP Response Object
  89. * @property readonlyResponse
  90. *
  91. * @discussion
  92. * Returns the operation's actual response object
  93. * This property is readonly cannot be updated.
  94. */
  95. @property (nonatomic, strong, readonly) NSHTTPURLResponse *readonlyResponse;
  96. /*!
  97. * @abstract The internal HTTP Post data values
  98. * @property readonlyPostDictionary
  99. *
  100. * @discussion
  101. * Returns the operation's post data dictionary
  102. * This property is readonly cannot be updated.
  103. * Rather, updating this post dictionary doesn't have any effect on the MKNetworkOperation.
  104. * Use the addHeaders method to add post data parameters to the operation.
  105. *
  106. * @seealso
  107. * addHeaders:
  108. */
  109. @property (nonatomic, strong, readonly) NSDictionary *readonlyPostDictionary;
  110. /*!
  111. * @abstract The internal request object's method type
  112. * @property HTTPMethod
  113. *
  114. * @discussion
  115. * Returns the operation's method type
  116. * This property is readonly cannot be modified.
  117. * To create an operation with a new method type, use the operationWithURLString:params:httpMethod:
  118. */
  119. @property (nonatomic, strong, readonly) NSString *HTTPMethod;
  120. /*!
  121. * @abstract The internal response object's status code
  122. * @property HTTPStatusCode
  123. *
  124. * @discussion
  125. * Returns the operation's response's status code.
  126. * Returns 0 when the operation has not yet started and the response is not available.
  127. * This property is readonly cannot be modified.
  128. */
  129. @property (nonatomic, assign, readonly) NSInteger HTTPStatusCode;
  130. /*!
  131. * @abstract Post Data Encoding Type Property
  132. * @property postDataEncoding
  133. *
  134. * @discussion
  135. * Specifies which type of encoding should be used to encode post data.
  136. * MKNKPostDataEncodingTypeURL is the default which defaults to application/x-www-form-urlencoded
  137. * MKNKPostDataEncodingTypeJSON uses JSON encoding.
  138. * JSON Encoding is supported only in iOS 5 or Mac OS X 10.7 and above.
  139. * On older operating systems, JSON Encoding reverts back to URL Encoding
  140. * You can use the postDataEncodingHandler to provide a custom postDataEncoding
  141. * For example, JSON encoding using a third party library.
  142. *
  143. * @seealso
  144. * setCustomPostDataEncodingHandler:forType:
  145. *
  146. */
  147. @property (nonatomic, assign) MKNKPostDataEncodingType postDataEncoding;
  148. /*!
  149. * @abstract Set a customized Post Data Encoding Handler for a given HTTP Content Type
  150. *
  151. * @discussion
  152. * If you need customized post data encoding support, provide a block method here.
  153. * This block method will be invoked only when your HTTP Method is POST or PUT
  154. * For default URL encoding or JSON encoding, use the property postDataEncoding
  155. * If you change the postData format, it's your responsiblity to provide a correct Content-Type.
  156. *
  157. * @seealso
  158. * postDataEncoding
  159. */
  160. -(void) setCustomPostDataEncodingHandler:(MKNKEncodingBlock) postDataEncodingHandler forType:(NSString*) contentType;
  161. /*!
  162. * @abstract String Encoding Property
  163. * @property stringEncoding
  164. *
  165. * @discussion
  166. * Specifies which type of encoding should be used to encode URL strings
  167. */
  168. @property (nonatomic, assign) NSStringEncoding stringEncoding;
  169. /*!
  170. * @abstract Freezable request
  171. * @property freezable
  172. *
  173. * @discussion
  174. * Freezable operations are serialized when the network goes down and restored when the connectivity is up again.
  175. * Only POST, PUT and DELETE operations are freezable.
  176. * In short, any operation that changes the state of the server are freezable, creating a tweet, checking into a new location etc., Operations like fetching a list of tweets (think readonly GET operations) are not freezable.
  177. * MKNetworkKit doesn't freeze (readonly) GET operations even if they are marked as freezable
  178. */
  179. @property (nonatomic, assign) BOOL freezable;
  180. /*!
  181. * @abstract Error object
  182. * @property error
  183. *
  184. * @discussion
  185. * If the network operation results in an error, this will hold the response error, otherwise it will be nil
  186. */
  187. @property (nonatomic, readonly, strong) NSError *error;
  188. /*!
  189. * @abstract Cache headers of the response
  190. * @property cacheHeaders
  191. *
  192. * @discussion
  193. * If the network operation is a GET, this dictionary will be populated with relevant cache related headers
  194. * MKNetworkKit assumes a 7 day cache for images and 1 minute cache for all requests with no-cache set
  195. * This property is internal to MKNetworkKit. Modifying this is not recommended and will result in unexpected behaviour
  196. */
  197. @property (strong, nonatomic) NSMutableDictionary *cacheHeaders;
  198. /*!
  199. * @abstract Authentication methods
  200. *
  201. * @discussion
  202. * If your request needs to be authenticated, set your username and password using this method.
  203. */
  204. -(void) setUsername:(NSString*) name password:(NSString*) password;
  205. /*!
  206. * @abstract Authentication methods
  207. *
  208. * @discussion
  209. * If your request needs to be authenticated using HTTP Basic, use this method to set your username and password.
  210. * Calling this method with basicAuth:NO is same as calling setUserName:password:
  211. * @seealso
  212. * setUserName:password:
  213. */
  214. -(void) setUsername:(NSString*) username password:(NSString*) password basicAuth:(BOOL) bYesOrNo;
  215. /*!
  216. * @abstract Authentication methods (Client Certificate)
  217. * @property clientCertificate
  218. *
  219. * @discussion
  220. * If your request needs to be authenticated using a client certificate, set the certificate path here
  221. */
  222. @property (strong, nonatomic) NSString *clientCertificate;
  223. /*!
  224. * @abstract Custom authentication handler
  225. * @property authHandler
  226. *
  227. * @discussion
  228. * If your request needs to be authenticated using a custom method (like a Web page/HTML Form), add a block method here
  229. * and process the NSURLAuthenticationChallenge
  230. */
  231. @property (nonatomic, copy) MKNKAuthBlock authHandler;
  232. /*!
  233. * @abstract Handler that you implement to monitor reachability changes
  234. * @property operationStateChangedHandler
  235. *
  236. * @discussion
  237. * The framework calls this handler whenever the operation state changes
  238. */
  239. @property (copy, nonatomic) void (^operationStateChangedHandler)(MKNetworkOperationState newState);
  240. /*!
  241. * @abstract controls persistence of authentication credentials
  242. * @property credentialPersistence
  243. *
  244. * @discussion
  245. * The default value is set to NSURLCredentialPersistenceForSession, change it to NSURLCredentialPersistenceNone to avoid caching issues (isse #35)
  246. */
  247. @property (nonatomic, assign) NSURLCredentialPersistence credentialPersistence;
  248. #if TARGET_OS_IPHONE
  249. /*!
  250. * @abstract notification that has to be shown when an error occurs and the app is in background
  251. * @property localNotification
  252. *
  253. * @discussion
  254. * The default value nil. No notification is shown when an error occurs.
  255. * To show a notification when the app is in background and the network operation running in background fails,
  256. * set this parameter to a UILocalNotification object
  257. */
  258. @property (nonatomic, strong) UILocalNotification *localNotification;
  259. /*!
  260. * @abstract Shows a local notification when an error occurs
  261. * @property shouldShowLocalNotificationOnError
  262. *
  263. * @discussion
  264. * The default value NO. No notification is shown when an error occurs.
  265. * When set to YES, MKNetworkKit shows the NSError localizedDescription text as a notification when the app is in background and the network operation ended in error.
  266. * To customize the local notification text, use the property localNotification
  267. * @seealso
  268. * localNotification
  269. */
  270. @property (nonatomic, assign) BOOL shouldShowLocalNotificationOnError;
  271. #endif
  272. /*!
  273. * @abstract Add additional header parameters
  274. *
  275. * @discussion
  276. * If you ever need to set additional headers after creating your operation, you this method.
  277. * You normally set default headers to the engine and they get added to every request you create.
  278. * On specific cases where you need to set a new header parameter for just a single API call, you can use this
  279. */
  280. -(void) addHeaders:(NSDictionary*) headersDictionary;
  281. /*!
  282. * @abstract Sets the authorization header after prefixing it with a given auth type
  283. *
  284. * @discussion
  285. * If you need to set the HTTP Authorization header, you can use this convinience method.
  286. * This method internally calls addHeaders:
  287. * The authType parameter is a string that you can prefix to your auth token to tell your server what kind of authentication scheme you want to use. HTTP Basic Authentication uses the string "Basic" for authType
  288. * To use HTTP Basic Authentication, consider using the method setUsername:password:basicAuth: instead.
  289. *
  290. * Example
  291. * [op setToken:@"abracadabra" forAuthType:@"Token"] will set the header value to
  292. * "Authorization: Token abracadabra"
  293. * @seealso
  294. * setUsername:password:basicAuth:
  295. * addHeaders:
  296. */
  297. -(void) setAuthorizationHeaderValue:(NSString*) token forAuthType:(NSString*) authType;
  298. /*!
  299. * @abstract Attaches a file to the request
  300. *
  301. * @discussion
  302. * This method lets you attach a file to the request
  303. * The method has a side effect. It changes the HTTPMethod to "POST" regardless of what it was before.
  304. * It also changes the post format to multipart/form-data
  305. * The mime-type is assumed to be application/octet-stream
  306. */
  307. -(void) addFile:(NSString*) filePath forKey:(NSString*) key;
  308. /*!
  309. * @abstract Attaches a file to the request and allows you to specify a mime-type
  310. *
  311. * @discussion
  312. * This method lets you attach a file to the request
  313. * The method has a side effect. It changes the HTTPMethod to "POST" regardless of what it was before.
  314. * It also changes the post format to multipart/form-data
  315. */
  316. -(void) addFile:(NSString*) filePath forKey:(NSString*) key mimeType:(NSString*) mimeType;
  317. /*!
  318. * @abstract Attaches a resource to the request from a NSData pointer
  319. *
  320. * @discussion
  321. * This method lets you attach a NSData object to the request. The behaviour is exactly similar to addFile:forKey:
  322. * The method has a side effect. It changes the HTTPMethod to "POST" regardless of what it was before.
  323. * It also changes the post format to multipart/form-data
  324. * The mime-type is assumed to be application/octet-stream
  325. */
  326. -(void) addData:(NSData*) data forKey:(NSString*) key;
  327. /*!
  328. * @abstract Attaches a resource to the request from a NSData pointer and allows you to specify a mime-type
  329. *
  330. * @discussion
  331. * This method lets you attach a NSData object to the request. The behaviour is exactly similar to addFile:forKey:mimeType:
  332. * The method has a side effect. It changes the HTTPMethod to "POST" regardless of what it was before.
  333. * It also changes the post format to multipart/form-data
  334. */
  335. -(void) addData:(NSData*) data forKey:(NSString*) key mimeType:(NSString*) mimeType fileName:(NSString*) fileName;
  336. /*!
  337. * @abstract Block Handler for completion and error
  338. *
  339. * @discussion
  340. * This method sets your completion and error blocks. If your operation's response data was previously called,
  341. * the completion block will be called almost immediately with the cached response. You can check if the completion
  342. * handler was invoked with a cached data or with real data by calling the isCachedResponse method.
  343. *
  344. * @seealso
  345. * isCachedResponse
  346. */
  347. -(void) onCompletion:(MKNKResponseBlock) response onError:(MKNKErrorBlock) error;
  348. /*!
  349. * @abstract Block Handler for tracking upload progress
  350. *
  351. * @discussion
  352. * This method can be used to update your progress bars when an upload is in progress.
  353. * The value range of the progress is 0 to 1.
  354. *
  355. */
  356. -(void) onUploadProgressChanged:(MKNKProgressBlock) uploadProgressBlock;
  357. /*!
  358. * @abstract Block Handler for tracking download progress
  359. *
  360. * @discussion
  361. * This method can be used to update your progress bars when a download is in progress.
  362. * The value range of the progress is 0 to 1.
  363. *
  364. */
  365. -(void) onDownloadProgressChanged:(MKNKProgressBlock) downloadProgressBlock;
  366. /*!
  367. * @abstract Uploads a resource from a stream
  368. *
  369. * @discussion
  370. * This method can be used to upload a resource for a post body directly from a stream.
  371. *
  372. */
  373. -(void) setUploadStream:(NSInputStream*) inputStream;
  374. /*!
  375. * @abstract Downloads a resource directly to a file or any output stream
  376. *
  377. * @discussion
  378. * This method can be used to download a resource directly to a stream (It's normally a file in most cases).
  379. * Calling this method multiple times adds new streams to the same operation.
  380. * A stream cannot be removed after it is added.
  381. *
  382. */
  383. -(void) addDownloadStream:(NSOutputStream*) outputStream;
  384. /*!
  385. * @abstract Helper method to check if the response is from cache
  386. *
  387. * @discussion
  388. * This method should be used to check if your response is cached.
  389. * When you enable caching on MKNetworkEngine, your completionHandler will be called with cached data first and then
  390. * with real data, later after fetching. In your handler, you can call this method to check if it is from cache or not
  391. *
  392. */
  393. -(BOOL) isCachedResponse;
  394. /*!
  395. * @abstract Helper method to retrieve the contents
  396. *
  397. * @discussion
  398. * This method is used for accessing the downloaded data. If the operation is still in progress, the method returns nil instead of partial data. To access partial data, use a downloadStream.
  399. *
  400. * @seealso
  401. * addDownloadStream:
  402. */
  403. -(NSData*) responseData;
  404. /*!
  405. * @abstract Helper method to retrieve the contents as a NSString
  406. *
  407. * @discussion
  408. * This method is used for accessing the downloaded data. If the operation is still in progress, the method returns nil instead of partial data. To access partial data, use a downloadStream. The method also converts the responseData to a NSString using the stringEncoding specified in the operation
  409. *
  410. * @seealso
  411. * addDownloadStream:
  412. * stringEncoding
  413. */
  414. -(NSString*)responseString;
  415. /*!
  416. * @abstract Helper method to print the request as a cURL command
  417. *
  418. * @discussion
  419. * This method is used for displaying the request you created as a cURL command
  420. *
  421. */
  422. -(NSString*) curlCommandLineString;
  423. /*!
  424. * @abstract Helper method to retrieve the contents as a NSString encoded using a specific string encoding
  425. *
  426. * @discussion
  427. * This method is used for accessing the downloaded data. If the operation is still in progress, the method returns nil instead of partial data. To access partial data, use a downloadStream. The method also converts the responseData to a NSString using the stringEncoding specified in the parameter
  428. *
  429. * @seealso
  430. * addDownloadStream:
  431. * stringEncoding
  432. */
  433. -(NSString*) responseStringWithEncoding:(NSStringEncoding) encoding;
  434. /*!
  435. * @abstract Helper method to retrieve the contents as a UIImage
  436. *
  437. * @discussion
  438. * This method is used for accessing the downloaded data as a UIImage. If the operation is still in progress, the method returns nil instead of a partial image. To access partial data, use a downloadStream. If the response is not a valid image, this method returns nil. This method doesn't obey the response mime type property. If the server response with a proper image data but set the mime type incorrectly, this method will still be able access the response as an image.
  439. *
  440. * @seealso
  441. * addDownloadStream:
  442. */
  443. #if TARGET_OS_IPHONE
  444. -(UIImage*) responseImage;
  445. #elif TARGET_OS_MAC
  446. -(NSImage*) responseImage;
  447. -(NSXMLDocument*) responseXML;
  448. #endif
  449. /*!
  450. * @abstract Helper method to retrieve the contents as a NSDictionary or NSArray depending on the JSON contents
  451. *
  452. * @discussion
  453. * This method is used for accessing the downloaded data as a NSDictionary or an NSArray. If the operation is still in progress, the method returns nil. If the response is not a valid JSON, this method returns nil.
  454. *
  455. * @availability
  456. * iOS 5 and above or Mac OS 10.7 and above
  457. */
  458. -(id) responseJSON;
  459. /*!
  460. * @abstract Overridable custom method where you can add your custom business logic error handling
  461. *
  462. * @discussion
  463. * This optional method can be overridden to do custom error handling. Be sure to call [super operationSucceeded] at the last.
  464. * For example, a valid HTTP response (200) like "Item not found in database" might have a custom business error code
  465. * You can override this method and called [super failWithError:customError]; to notify that HTTP call was successful but the method
  466. * ended as a failed call
  467. *
  468. */
  469. -(void) operationSucceeded;
  470. /*!
  471. * @abstract Overridable custom method where you can add your custom business logic error handling
  472. *
  473. * @discussion
  474. * This optional method can be overridden to do custom error handling. Be sure to call [super operationSucceeded] at the last.
  475. * For example, a invalid HTTP response (401) like "Unauthorized" might be a valid case in your app.
  476. * You can override this method and called [super operationSucceeded]; to notify that HTTP call failed but the method
  477. * ended as a success call. For example, Facebook login failed, but to your business implementation, it's not a problem as you
  478. * are going to try alternative login mechanisms.
  479. *
  480. */
  481. -(void) operationFailedWithError:(NSError*) error;
  482. // internal methods called by MKNetworkEngine only.
  483. // Don't touch
  484. -(BOOL) isCacheable;
  485. -(void) setCachedData:(NSData*) cachedData;
  486. -(void) setCacheHandler:(MKNKResponseBlock) cacheHandler;
  487. -(void) updateHandlersFromOperation:(MKNetworkOperation*) operation;
  488. -(void) updateOperationBasedOnPreviousHeaders:(NSMutableDictionary*) headers;
  489. -(NSString*) uniqueIdentifier;
  490. - (id)initWithURLString:(NSString *)aURLString
  491. params:(NSMutableDictionary *)params
  492. httpMethod:(NSString *)method;
  493. @end