In WebKit, how do I get the content of a resource?

前端 未结 2 1139
说谎
说谎 2020-12-28 23:07

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 t

相关标签:
2条回答
  • 2020-12-28 23:34

    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];
    }
    
    0 讨论(0)
  • 2020-12-28 23:57

    use this one inside that delegate method

      for(NSString *s in [dataSource subresources])
            NSLog(@"resource : %@",s);
    

    it will show all the resources being downloaded in WebDataSource

    0 讨论(0)
提交回复
热议问题