diff --git a/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.h b/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.h index 5221206..aa7368c 100644 --- a/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.h +++ b/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.h @@ -1,6 +1,6 @@ #import -@interface AppDelegate : UIResponder +@interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; diff --git a/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.m b/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.m index 05475d9..ba7bfaa 100644 --- a/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.m +++ b/ExampleWebViewProxyApp/ExampleWebViewProxyApp/AppDelegate.m @@ -72,6 +72,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [WebViewProxy handleRequestsMatching:[NSPredicate predicateWithFormat:@"host MATCHES[cd] '[foo|bar]'"] handler:^(NSURLRequest* req, WVPResponse *res) { // ... }]; + + [WebViewProxy handleRequestsWithHost:@"example.proxy" handler:^(NSURLRequest *req, WVPResponse *res) { + NSString* proxyUrl = [req.URL.absoluteString stringByReplacingOccurrencesOfString:@"example.proxy" withString:@"example.com"]; + NSURLRequest* proxyReq = [NSURLRequest requestWithURL:[NSURL URLWithString:proxyUrl]]; + [NSURLConnection connectionWithRequest:proxyReq delegate:res]; + }]; return YES; } diff --git a/ExampleWebViewProxyApp/ExampleWebViewProxyApp/WebViewContent.html b/ExampleWebViewProxyApp/ExampleWebViewProxyApp/WebViewContent.html index 62e6a0c..a574ee4 100644 --- a/ExampleWebViewProxyApp/ExampleWebViewProxyApp/WebViewContent.html +++ b/ExampleWebViewProxyApp/ExampleWebViewProxyApp/WebViewContent.html @@ -6,4 +6,6 @@ + + \ No newline at end of file diff --git a/README.md b/README.md index ee77f22..ea0ccec 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ Examples [res respondWithError:404 text:@"Not found"]; ##### - (void) setHeader:(NSString\*)headerName value:(NSString\*)headerValue; -Set response headers before responding. +Set a response header before responding. Examples @@ -149,6 +149,13 @@ Examples [res setHeader:@"Content-Type" value:@"audio/wav"]; [res setHeader:@"Host" value:@"WebViewProxy"]; +##### - (void) setHeaders:(NSDictionary*)headers; +Set multiple response headers before responding. + +Examples + + [res setHeaders:@{ @"Content-Type":@"image/gif", @"Host":@"WebViewProxy" }]; + ##### - (void) respondWithData:(NSData\*)data mimeType:(NSString\*)mimeType; Respond with the given data and mime type (the mime type gets sent as the HTTP header `Content-Type`). @@ -184,6 +191,31 @@ Examples response.cachePolicy = NSURLCacheStorageAllowedInMemoryOnly; response.cachePolicy = NSURLCacheStorageNotAllowed; +#### Proxy requests to remote servers + +There are many ways to proxy remote requests with `WebViewProxy`. + +The easiest approach uses `WebViewProxyResponse` as a `NSURLConnection` delegate. This pipes the response through the proxy response: + + [WebViewProxy handleRequestsWithHost:@"example.proxy" handler:^(NSURLRequest *req, WVPResponse *res) { + NSString* proxyUrl = [req.URL.absoluteString stringByReplacingOccurrencesOfString:@"example.proxy" withString:@"example.com"]; + NSURLRequest* proxyReq = [NSURLRequest requestWithURL:[NSURL URLWithString:proxyUrl]]; + [NSURLConnection connectionWithRequest:proxyReq delegate:res]; + }]; + +Another approach which sports more control but reads the entire response into memory: + + NSOperationQueue* queue = [[NSOperationQueue alloc] init]; + [WebViewProxy handleRequestsWithHost:@"example.proxy" handler:^(NSURLRequest *req, WVPResponse *res) { + NSString* proxyUrl = [req.URL.absoluteString stringByReplacingOccurrencesOfString:@"example.proxy" withString:@"example.com"]; + NSURLRequest* proxyReq = [NSURLRequest requestWithURL:[NSURL URLWithString:proxyUrl]]; + [NSURLConnection sendAsynchronousRequest:proxyReq queue:queue completionHandler:^(NSURLResponse* proxyRes, NSData* proxyData, NSError* proxyErr) { + if (proxyErr) { return [res respondWithError:203 text:@"Could not reach server"]; } + NSInteger statusCode = [(NSHTTPURLResponse*)proxyRes statusCode]; + [res setHeaders:[(NSHTTPURLResponse*)proxyRes allHeaderFields]]; + [res respondWithData:proxyData mimeType:proxyRes.MIMEType statusCode:statusCode]; + }]; + }]; #### Piping response API @@ -192,13 +224,10 @@ Pipe an `NSURLResponse` and its data into the `WVPResponse`. This makes it simp Examples to be written. ##### - (void) pipeResponse:(NSURLResponse\*)response; - Pipe an NSURLResponse into the response. ##### - (void) pipeData:(NSData\*)data; - Pipe data into the response. ##### - (void) pipeEnd; - Finish a piped response. diff --git a/WebViewProxy/WebViewProxy.h b/WebViewProxy/WebViewProxy.h index 9b2484b..b8d5131 100644 --- a/WebViewProxy/WebViewProxy.h +++ b/WebViewProxy/WebViewProxy.h @@ -1,6 +1,6 @@ #import -@interface WVPResponse : NSObject +@interface WVPResponse : NSObject @property (assign,nonatomic) NSURLCacheStoragePolicy cachePolicy; @property (strong,nonatomic) NSURLRequest* request; // High level API @@ -12,6 +12,7 @@ // Low level API - (void) respondWithError:(NSInteger)statusCode text:(NSString*)text; - (void) setHeader:(NSString*)headerName value:(NSString*)headerValue; +- (void) setHeaders:(NSDictionary*)headers; - (void) respondWithData:(NSData*)data mimeType:(NSString*)mimeType; - (void) respondWithData:(NSData*)data mimeType:(NSString*)mimeType statusCode:(NSInteger)statusCode; // Pipe data API diff --git a/WebViewProxy/WebViewProxy.m b/WebViewProxy/WebViewProxy.m index 7c37563..d4bd732 100644 --- a/WebViewProxy/WebViewProxy.m +++ b/WebViewProxy/WebViewProxy.m @@ -80,6 +80,11 @@ - (void)respondWithHTML:(NSString *)html { - (void)setHeader:(NSString *)headerName value:(NSString *)headerValue { _headers[headerName] = headerValue; } +- (void)setHeaders:(NSDictionary *)headers { + for (NSString* headerName in headers) { + [self setHeader:headerName value:headers[headerName]]; + } +} - (void)respondWithData:(NSData *)data mimeType:(NSString *)mimeType { [self respondWithData:data mimeType:mimeType statusCode:200]; } @@ -140,6 +145,19 @@ - (void)pipeEnd { if (_stopped) { return; } [_protocol.client URLProtocolDidFinishLoading:_protocol]; } +// NSURLConnectionDataDelegate +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + [self pipeResponse:response]; +} +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + [self pipeData:data]; +} +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + [self pipeEnd]; +} +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + [self pipeEnd]; +} @end // The NSURLProtocol implementation that allows us to intercept requests.