RCTFileRequestHandler.mm 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import <React/RCTFileRequestHandler.h>
  8. #import <MobileCoreServices/MobileCoreServices.h>
  9. #import <React/RCTUtils.h>
  10. #import <ReactCommon/RCTTurboModule.h>
  11. #import "RCTNetworkPlugins.h"
  12. @interface RCTFileRequestHandler() <RCTTurboModule>
  13. @end
  14. @implementation RCTFileRequestHandler
  15. {
  16. NSOperationQueue *_fileQueue;
  17. }
  18. RCT_EXPORT_MODULE()
  19. - (void)invalidate
  20. {
  21. [_fileQueue cancelAllOperations];
  22. _fileQueue = nil;
  23. }
  24. - (BOOL)canHandleRequest:(NSURLRequest *)request
  25. {
  26. return
  27. [request.URL.scheme caseInsensitiveCompare:@"file"] == NSOrderedSame
  28. && !RCTIsBundleAssetURL(request.URL);
  29. }
  30. - (NSOperation *)sendRequest:(NSURLRequest *)request
  31. withDelegate:(id<RCTURLRequestDelegate>)delegate
  32. {
  33. // Lazy setup
  34. if (!_fileQueue) {
  35. _fileQueue = [NSOperationQueue new];
  36. _fileQueue.maxConcurrentOperationCount = 4;
  37. }
  38. __weak __block NSBlockOperation *weakOp;
  39. __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
  40. // Get content length
  41. NSError *error = nil;
  42. NSFileManager *fileManager = [NSFileManager new];
  43. NSDictionary<NSString *, id> *fileAttributes = [fileManager attributesOfItemAtPath:request.URL.path error:&error];
  44. if (!fileAttributes) {
  45. [delegate URLRequest:weakOp didCompleteWithError:error];
  46. return;
  47. }
  48. // Get mime type
  49. NSString *fileExtension = [request.URL pathExtension];
  50. NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(
  51. kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);
  52. NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(
  53. (__bridge CFStringRef)UTI, kUTTagClassMIMEType);
  54. // Send response
  55. NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
  56. MIMEType:contentType
  57. expectedContentLength:[fileAttributes[NSFileSize] ?: @-1 integerValue]
  58. textEncodingName:nil];
  59. [delegate URLRequest:weakOp didReceiveResponse:response];
  60. // Load data
  61. NSData *data = [NSData dataWithContentsOfURL:request.URL
  62. options:NSDataReadingMappedIfSafe
  63. error:&error];
  64. if (data) {
  65. [delegate URLRequest:weakOp didReceiveData:data];
  66. }
  67. [delegate URLRequest:weakOp didCompleteWithError:error];
  68. }];
  69. weakOp = op;
  70. [_fileQueue addOperation:op];
  71. return op;
  72. }
  73. - (void)cancelRequest:(NSOperation *)op
  74. {
  75. [op cancel];
  76. }
  77. @end
  78. Class RCTFileRequestHandlerCls(void) {
  79. return RCTFileRequestHandler.class;
  80. }