カスタムリソースにはNSURLProtocolを使えば良いのじゃないか?
「UIWebView の取り扱いによってはjavascript経由でサンドボックス外のファイルシステムにアクセスできてしまうという話と対処法」 で、UIWebViewにfile://スキームのリソースを表示する場合の脆弱性について触れられていた。 ちょうど自分もこのあたりの仕組みが必要だったのでいろいろ試してみたのだけど、結論から言えば、その場合はNSURLProtocolを使えば良いと思う。
CocoaではUIWebViewやその下のNSURLConnectionがアクセスするリソースはNSURLProtocolで抽象化されているので、 独自のスキームを定義し、それを通してアプリケーション内のリソースを表示するようにする。
以下のようなNSURLProtocolのサブクラスを定義する。:
@interface HogeProtocol : NSURLProtocol
@end
@implementation HogeProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
return [[[request URL] scheme] isEqualToString:@"hoge"];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void)startLoading {
// ファイルから小さいリソースを読むぐらいだったら、dispachしなくても良いのかな...
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSString *filePath = [...] ///< self.request URL]から、該当するリソースのpathを
NSString *mimeType = @"text/html"; ///< ここも
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfFile:data];
if(!data) {
[self.client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable:nil]];
return;
}
[self.client URLProtocol:self didReceiveResponse:[[[NSURLResponse alloc] initWithURL:[self.request URL]
MIMEType:mimeType
expectedContentLength:[data length]
textEncodingName:@"UTF-8"] autorelease] cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
});
}
- (void)stopLoading {
// stopLoadingが来たらデータの読み込みを中断するのだが、このコードだと中断しようが無い...
}
@end
随所が適当だが、こんな感じのを作って、UIWebViewでhoge:///スキームのリソースを読み込む:
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"hoge:///index"]]];
リソース内で、例えば、<img src="sexy.jpg">のように相対パスでリソースをしても、hoge:///sexy.jpgのようなクエリが飛ぶので一安心。
実際には、リソース読み込み部分をカスタマイズして動的なデータにも対応していけば良いのだと思う。
ってほぼ↓のサンプルのコピペだな。
WebにはAppleのリファレンスぐらいしか情報がなかった。