1

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)
Community
  • 1
  • 1
Nerkatel
  • 1,805
  • 16
  • 25

2 Answers2

1

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).

Nerkatel
  • 1,805
  • 16
  • 25
  • Do you have any idea on this question similar to this one https://stackoverflow.com/questions/44584159/nsurlprotocol-subclass-changes-urls-automatically – Mrug Jun 16 '17 at 08:16
0

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"]];
Lepidopteron
  • 6,056
  • 5
  • 41
  • 53
  • Edited my question, but as you can now see, no, I'm not using loadHTMLString locally, but loadRequest instead. – Nerkatel Apr 01 '14 at 10:11
  • Hey Nerkatel, please make sure, that the zip-folder-structure is kept, when the zipData is writen to the filePath. I think, the structure might get lost. Can you validate this in the simulator? – Lepidopteron Apr 01 '14 at 10:47
  • I believe the structure is kept, I logged the following : `File at index 9 is "assets/css/main.css"`, `File at index 12 is "assets/css/styles.css"` … using the `zip_get_num_entries` libzip method. I'm only downloading the zip file (already zipped) and saving it to the filePath, I don't think there is any chance the structure could be lost in the process, could it ? – Nerkatel Apr 01 '14 at 11:40
  • Well, I think, because subfolders do not exist when saving them, there might be the problem, the files get lost? Just store the zip's content into the document's directory and go to/Users/~user/Library/Application Support/iPhone Simulator/7.1-64/Applications – Lepidopteron Apr 01 '14 at 11:59