Question

I implemented a custom NSURLProtocol that allows me to use a static zipped version of a website as a target for a webView. It opens the zip on the go and load the required data. But the issue is that NSURLProtocol seems not to behave properly with relative paths ? That is I have the following structure :

assets/css/main.css
assets/css/style.css
assets/images/sprite.png
index.html

And call sprite.png from the css using : background: url(../images/sprite.png) no-repeat; but, the requestURL in my custom NSURLProtocol shows scheme://host/images/sprite.png, missing the assets part. It works fine if I switch the .. part for assets, but I would rather not have to do this.

I found the same issue here : Loading resources from relative paths through NSURLProtocol subclass but this got no answer.

I couldn't find any way to either fix this issue so that the request properly resolves the relative path, or fix the path myself afterwards (But i would need to know where the request originated from, and had no luck there either)

Any help appreciated, thanks in advance.

Side note : Same problem using @import url("style.css"); in main.css

Edit :

I start by downloading the zip file from a remote server :

NSURL * fetchURL = [NSURL URLWithString:zipURLString];
[…]
NSString * filePath = [[self documentsDirectory] stringByAppendingPathComponent:fetchURL.path.lastPathComponent];
[zipData writeToFile:filePath atomically:YES];

So, from http://host/foo/archive.zip, i save it to documentsDirectory/archive.zip. From there, I change the scheme and the url to point on the zip file :

NSString * str = [NSString stringWithFormat:@"myzip://%@", zipURL.path.lastPathComponent];
[_webView loadRequest:[NSURLRequest str]];

Which opens myzip://archive.zip, and if no such file was found in the zip file, I append /index.html to the current path. Thus the following requests arrive in my NSURLProtocol subclass - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id < NSURLProtocolClient >)client

myzip://archive.zip (Changed to myzip://archive.zip/index.html)
myzip://archive.zip/assets/css/main.css
myzip://archive.zip/styles.css (Problem here)
Was it helpful?

Solution

Finally fixed it.

I had the following in my NSURLProtocol :

- (void)startLoading {
    [self.client URLProtocol:self
          didReceiveResponse:[[NSURLResponse alloc] init]
          cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    //Some other stuff
}

and solved the issue with the following :

- (void)startLoading {
    [self.client URLProtocol:self
          didReceiveResponse:[[NSURLResponse alloc] initWithURL:_lastReqURL MIMEType:nil expectedContentLength:-1 textEncodingName:nil]
          cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    //Some other stuff
}

Where _lastReqURL is _lastReqURL = request.URL;, from

- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id < NSURLProtocolClient >)client {
    self = [super initWithRequest:request cachedResponse:cachedResponse client:client];
    if (self) {
        _lastReqURL = request.URL;
        // Some stuff
    }
}

I can only assume the URL part in NSURLResponse is critical when dealing with relative-paths (seems logical).

OTHER TIPS

I think this might refer to the way you do load the Request or the HTML. Could you paste the code for your request? I guess, you load the HTML locally, so don't forget to set the baseURL accordingly, else the relative pathes won't work anymore:

For example the following:

[self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"host"]];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top