I've been writing a Mac app to inspect each HTTP request and so I'm using WebView to load the request.
The problem is that I can't seem to figure out how to get the content of each of the resource items.
I'm trying to get the content for the resource via the WebResourceLoadDelegate
method:
- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
That doesn't seem to be working.
I was also looking at [dataSource data]
but that just gave me the HTML for the request and not the data for the resource item.
Any ideas on how I can get the content of the resource?
Yes, that ought to work, and it appears that once upon a time it did. You can work around it by implementing a custom NSURLProtocol.
First, you'll need to figure out which requests you are interested in intercepting (or all of them, no matter). I do this in my WebResourceLoadDelegate. If I care about the request, I replace it with one of my own, attaching myself as a property. I'll use that property in the NSURLProtocol later.
- (NSURLRequest*) webView:(WebView*)sender
resource:(id)identifier
willSendRequest:(NSURLRequest*)request
redirectResponse:(NSURLResponse*)redirectResponse
fromDataSource:(WebDataSource*)dataSource
{
// Am I interested in this request?
if (/* figure out if you want it or not */) {
NSMutableURLRequest* newRequest = [[request mutableCopy] autorelease];
[NSURLProtocol setProperty:self forKey:@"MyApp" inRequest:newRequest];
return newRequest;
}
else {
// Not interested, let it go through normally
return request;
}
}
My NSURLProtocol looks like this.
@interface MyURLProtocol : NSURLProtocol {
id _delegate;
NSURLConnection* _connection;
NSMutableData* _data;
}
@end
In my NSURLProtocol subclass, I can use the attached property to see if I should intercept the response.
+ (BOOL) canInitWithRequest:(NSURLRequest*)request
{
id delegate = [NSURLProtocol propertyForKey:@"MyApp" inRequest:request];
return (delegate != nil);
}
In initWithRequest, I move the delegate into my NSURLProtocol instance, and remove the property from the request. This prevents an infinite loop later, when I actually try to load this request.
- (id) initWithRequest:(NSURLRequest*)theRequest
cachedResponse:(NSCachedURLResponse*)cachedResponse
client:(id<NSURLProtocolClient>)client
{
// Move the delegate from the request to this instance
NSMutableURLRequest* req = (NSMutableURLRequest*)theRequest;
_delegate = [NSURLProtocol propertyForKey:@"MyApp" inRequest:req];
[NSURLProtocol removePropertyForKey:@"MyApp" inRequest:req];
// Complete my setup
self = [super initWithRequest:req cachedResponse:cachedResponse client:client];
if (self) {
_data = [[NSMutableData data] retain];
}
return self;
}
The rest is stock URL loading stuff.
- (void) startLoading
{
_connection = [[NSURLConnection connectionWithRequest:[self request] delegate:self] retain];
}
- (void) stopLoading
{
[_connection cancel];
}
- (void)connection:(NSURLConnection*)conn didReceiveResponse:(NSURLResponse*)response
{
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:[[self request] cachePolicy]];
[_data setLength:0];
}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
[[self client] URLProtocol:self didLoadData:data];
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)conn
{
[[self client] URLProtocolDidFinishLoading:self];
// Forward the response to your delegate however you like
if (_delegate && [_delegate respondsToSelector:@selector(...)]) {
[_delegate ... withRequest:[self request] withData:_data];
}
}
- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)theRequest redirectResponse:(NSURLResponse*)redirectResponse
{
return theRequest;
}
- (void)connection:(NSURLConnection*)conn didFailWithError:(NSError*)error
{
[[self client] URLProtocol:self didFailWithError:error];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With