diff --git a/README.md b/README.md index 8fe644069..e140ac0b7 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ simply hook `window.open` during initialization. For example: Opens a URL in a new `InAppBrowser` instance, the current browser instance, or the system browser. - var ref = cordova.InAppBrowser.open(url, target, options); + var ref = cordova.InAppBrowser.open(url, target, options, headers); - __ref__: Reference to the `InAppBrowser` window when the target is set to `'_blank'`. _(InAppBrowser)_ @@ -162,6 +162,9 @@ instance, or the system browser. - __hardwareback__: works the same way as on Android platform. - __fullscreen__: set to `yes` to create the browser control without a border around it. Please note that if __location=no__ is also specified, there will be no control presented to user to close IAB window. +- __headers__: Headers for the http request. Optional. _(String)_ or _(javascript object)_ + - _(String)_: headers must be in `header=value` form, separated by commas : `header1=value1,header2=value2`. don't use _(String)_ if commas or equals can be contained in headers or values. + - _(javascript object)_: headers are stored in object's properties like this `{ 'header1': 'value1', 'header2': 'value2'}`. this storage always works even if headers contain commas or equals. ### Supported Platforms diff --git a/src/android/InAppBrowser.java b/src/android/InAppBrowser.java index 060330261..0a27c6eb1 100644 --- a/src/android/InAppBrowser.java +++ b/src/android/InAppBrowser.java @@ -168,6 +168,7 @@ public boolean execute(String action, CordovaArgs args, final CallbackContext ca } final String target = t; final HashMap features = parseFeature(args.optString(2)); + final HashMap headers = parseHeaders(args.optString(3)); LOG.d(LOG_TAG, "target = " + target); @@ -233,7 +234,7 @@ else if (url.startsWith(WebView.SCHEME_TEL)) // load in InAppBrowser else { LOG.d(LOG_TAG, "loading in InAppBrowser"); - result = showWebPage(url, features); + result = showWebPage(url, features, headers); } } // SYSTEM @@ -244,7 +245,7 @@ else if (SYSTEM.equals(target)) { // BLANK - or anything else else { LOG.d(LOG_TAG, "in blank"); - result = showWebPage(url, features); + result = showWebPage(url, features, headers); } PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result); @@ -271,7 +272,7 @@ public void run() { } else { ((InAppBrowserClient)inAppWebView.getWebViewClient()).waitForBeforeload = false; } - inAppWebView.loadUrl(url); + inAppWebView.loadUrl(url, null); } }); } @@ -408,7 +409,7 @@ private void injectDeferredObject(String source, String jsWrapper) { public void run() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { // This action will have the side-effect of blurring the currently focused element - inAppWebView.loadUrl("javascript:" + finalScriptToInject); + inAppWebView.loadUrl("javascript:" + finalScriptToInject, null); } else { inAppWebView.evaluateJavascript(finalScriptToInject, null); } @@ -447,6 +448,31 @@ private HashMap parseFeature(String optString) { } } + /** + * Put the headers string into a hash map + * + * @param headersString string of headers comma separated (key=value) + * @return map of headers + */ + private HashMap parseHeaders(String headersString) { + if (headersString.equals(NULL)) { + return null; + } else { + HashMap map = new HashMap(); + StringTokenizer headers = new StringTokenizer(headersString, ","); + StringTokenizer header; + while(headers.hasMoreElements()) { + header = new StringTokenizer(headers.nextToken(), "="); + if (header.hasMoreElements()) { + String key = header.nextToken().replace("@e","=").replace("@c", ",").replace("@a","@"); + String value = header.nextToken().replace("@e","=").replace("@c", ",").replace("@a","@"); + map.put(key, value); + } + } + return map; + } + } + /** * Display a new browser with the specified URL. * @@ -542,7 +568,7 @@ public void onPageFinished(WebView view, String url) { // NB: From SDK 19: "If you call methods on WebView from any thread // other than your app's UI thread, it can cause unexpected results." // http://developer.android.com/guide/webapps/migrating.html#Threads - childView.loadUrl("about:blank"); + childView.loadUrl("about:blank", null); try { JSONObject obj = new JSONObject(); @@ -599,9 +625,9 @@ private void navigate(String url) { imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0); if (!url.startsWith("http") && !url.startsWith("file:")) { - this.inAppWebView.loadUrl("http://" + url); + this.inAppWebView.loadUrl("http://" + url, null); } else { - this.inAppWebView.loadUrl(url); + this.inAppWebView.loadUrl(url, null); } this.inAppWebView.requestFocus(); } @@ -625,8 +651,9 @@ private InAppBrowser getInAppBrowser(){ * * @param url the url to load. * @param features jsonObject + * @param headers headers for navigation */ - public String showWebPage(final String url, HashMap features) { + public String showWebPage(final String url, HashMap features, final HashMap headers) { // Determine if we should hide the location bar. showLocationBar = true; showZoomControls = true; @@ -1029,7 +1056,7 @@ public void postMessage(String data) { CookieManager.getInstance().setAcceptThirdPartyCookies(inAppWebView,true); } - inAppWebView.loadUrl(url); + inAppWebView.loadUrl(url, headers); inAppWebView.setId(Integer.valueOf(6)); inAppWebView.getSettings().setLoadWithOverviewMode(true); inAppWebView.getSettings().setUseWideViewPort(useWideViewPort); diff --git a/src/ios/CDVInAppBrowserOptions.h b/src/ios/CDVInAppBrowserOptions.h index d9f46bf7d..ca018d584 100644 --- a/src/ios/CDVInAppBrowserOptions.h +++ b/src/ios/CDVInAppBrowserOptions.h @@ -49,5 +49,6 @@ @property (nonatomic, copy) NSString* beforeload; + (CDVInAppBrowserOptions*)parseOptions:(NSString*)options; ++ (NSMutableURLRequest*)createRequest:(NSURL*)url headers:(NSString*)headers; @end diff --git a/src/ios/CDVInAppBrowserOptions.m b/src/ios/CDVInAppBrowserOptions.m index 4e6253922..cf45702f8 100644 --- a/src/ios/CDVInAppBrowserOptions.m +++ b/src/ios/CDVInAppBrowserOptions.m @@ -90,4 +90,22 @@ + (CDVInAppBrowserOptions*)parseOptions:(NSString*)options return obj; } ++ (NSMutableURLRequest*)createRequest:(NSURL*)url headers:(NSString*)headers +{ + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; + if (headers != nil) { + NSArray* pairs = [headers componentsSeparatedByString:@","]; + for (NSString* pair in pairs) { + NSArray* keyvalue = [pair componentsSeparatedByString:@"="]; + + if ([keyvalue count] == 2) { + NSString* key = [[[[keyvalue objectAtIndex:0] stringByReplacingOccurrencesOfString:@"@e" withString:@"="] stringByReplacingOccurrencesOfString:@"@c" withString:@","] stringByReplacingOccurrencesOfString:@"@a" withString:@"@"]; + NSString* value = [[[[keyvalue objectAtIndex:1] stringByReplacingOccurrencesOfString:@"@e" withString:@"="] stringByReplacingOccurrencesOfString:@"@c" withString:@","] stringByReplacingOccurrencesOfString:@"@a" withString:@"@"]; + [request setValue:value forHTTPHeaderField:key]; + } + } + } + return request; +} + @end diff --git a/src/ios/CDVUIInAppBrowser.h b/src/ios/CDVUIInAppBrowser.h index 0a58d2b4f..16324fb2f 100644 --- a/src/ios/CDVUIInAppBrowser.h +++ b/src/ios/CDVUIInAppBrowser.h @@ -81,7 +81,7 @@ @property (nonatomic) NSURL* currentURL; - (void)close; -- (void)navigateTo:(NSURL*)url; +- (void)navigateTo:(NSURL*)url headers:(NSString *)headers; - (void)showLocationBar:(BOOL)show; - (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition; - (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex; diff --git a/src/ios/CDVUIInAppBrowser.m b/src/ios/CDVUIInAppBrowser.m index a294a2b2b..32e970fcb 100644 --- a/src/ios/CDVUIInAppBrowser.m +++ b/src/ios/CDVUIInAppBrowser.m @@ -93,6 +93,7 @@ - (void)open:(CDVInvokedUrlCommand*)command NSString* url = [command argumentAtIndex:0]; NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; + NSString* headers = [command argumentAtIndex:3 withDefault:@"" andClass:[NSString class]]; self.callbackId = command.callbackId; @@ -109,11 +110,11 @@ - (void)open:(CDVInvokedUrlCommand*)command } if ([target isEqualToString:kInAppBrowserTargetSelf]) { - [self openInCordovaWebView:absoluteUrl withOptions:options]; + [self openInCordovaWebView:absoluteUrl withOptions:options withHeaders:headers]; } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { [self openInSystem:absoluteUrl]; } else { // _blank or anything else - [self openInInAppBrowser:absoluteUrl withOptions:options]; + [self openInInAppBrowser:absoluteUrl withOptions:options withHeaders:headers]; } pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; @@ -125,7 +126,7 @@ - (void)open:(CDVInvokedUrlCommand*)command [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options +- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options withHeaders:(NSString*)headers { CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; @@ -227,7 +228,7 @@ - (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options } _waitForBeforeload = ![_beforeload isEqualToString:@""]; - [self.inAppBrowserViewController navigateTo:url]; + [self.inAppBrowserViewController navigateTo:url headers:headers]; if (!browserOptions.hidden) { [self show:nil]; } @@ -296,9 +297,9 @@ - (void)hide:(CDVInvokedUrlCommand*)command }); } -- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options +- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options withHeaders:(NSString*)headers { - NSURLRequest* request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [CDVInAppBrowserOptions createRequest:url headers:headers]; #ifdef __CORDOVA_4_0_0 // the webview engine itself will filter for this according to policy @@ -339,7 +340,7 @@ - (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command NSURL* url = [NSURL URLWithString:urlStr]; _waitForBeforeload = NO; - [self.inAppBrowserViewController navigateTo:url]; + [self.inAppBrowserViewController navigateTo:url headers:nil]; } -(void)createIframeBridge @@ -960,9 +961,9 @@ - (void)close }); } -- (void)navigateTo:(NSURL*)url +- (void)navigateTo:(NSURL*)url headers:(NSString*)headers { - NSURLRequest* request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [CDVInAppBrowserOptions createRequest:url headers:headers]; if (_userAgentLockToken != 0) { [self.webView loadRequest:request]; diff --git a/src/ios/CDVWKInAppBrowser.h b/src/ios/CDVWKInAppBrowser.h index 1f359b171..ab9343d21 100644 --- a/src/ios/CDVWKInAppBrowser.h +++ b/src/ios/CDVWKInAppBrowser.h @@ -70,7 +70,7 @@ @property (nonatomic) NSURL* currentURL; - (void)close; -- (void)navigateTo:(NSURL*)url; +- (void)navigateTo:(NSURL*)url headers:(NSString *)headers; - (void)showLocationBar:(BOOL)show; - (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition; - (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex; diff --git a/src/ios/CDVWKInAppBrowser.m b/src/ios/CDVWKInAppBrowser.m index 3b039f50b..4b4a2770b 100644 --- a/src/ios/CDVWKInAppBrowser.m +++ b/src/ios/CDVWKInAppBrowser.m @@ -100,6 +100,7 @@ - (void)open:(CDVInvokedUrlCommand*)command NSString* url = [command argumentAtIndex:0]; NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; + NSString* headers = [command argumentAtIndex:3 withDefault:@"" andClass:[NSString class]]; self.callbackId = command.callbackId; @@ -116,11 +117,11 @@ - (void)open:(CDVInvokedUrlCommand*)command } if ([target isEqualToString:kInAppBrowserTargetSelf]) { - [self openInCordovaWebView:absoluteUrl withOptions:options]; + [self openInCordovaWebView:absoluteUrl withOptions:options withHeaders:headers]; } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { [self openInSystem:absoluteUrl]; } else { // _blank or anything else - [self openInInAppBrowser:absoluteUrl withOptions:options]; + [self openInInAppBrowser:absoluteUrl withOptions:options withHeaders:headers]; } pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; @@ -132,7 +133,7 @@ - (void)open:(CDVInvokedUrlCommand*)command [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options +- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options withHeaders:(NSString*)headers { CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; @@ -274,7 +275,7 @@ - (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options } _waitForBeforeload = ![_beforeload isEqualToString:@""]; - [self.inAppBrowserViewController navigateTo:url]; + [self.inAppBrowserViewController navigateTo:url headers:headers]; [self show:nil withNoAnimate:browserOptions.hidden]; } @@ -357,9 +358,9 @@ - (void)hide:(CDVInvokedUrlCommand*)command }); } -- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options +- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options withHeaders:(NSString*)headers { - NSURLRequest* request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [CDVInAppBrowserOptions createRequest:url headers:headers]; #ifdef __CORDOVA_4_0_0 // the webview engine itself will filter for this according to policy @@ -369,7 +370,7 @@ - (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options if ([self.commandDelegate URLIsWhitelisted:url]) { [self.webView loadRequest:request]; } else { // this assumes the InAppBrowser can be excepted from the white-list - [self openInInAppBrowser:url withOptions:options]; + [self openInInAppBrowser:url withOptions:options withHeaders:headers]; } #endif } @@ -399,7 +400,7 @@ - (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command NSURL* url = [NSURL URLWithString:urlStr]; //_beforeload = @""; _waitForBeforeload = NO; - [self.inAppBrowserViewController navigateTo:url]; + [self.inAppBrowserViewController navigateTo:url headers:nil]; } // This is a helper method for the inject{Script|Style}{Code|File} API calls, which @@ -1077,9 +1078,9 @@ - (void)close }); } -- (void)navigateTo:(NSURL*)url +- (void)navigateTo:(NSURL*)url headers:(NSString*)headers { - NSURLRequest* request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [CDVInAppBrowserOptions createRequest:url headers:headers]; if (_userAgentLockToken != 0) { [self.webView loadRequest:request]; diff --git a/www/inappbrowser.js b/www/inappbrowser.js index 9ef96184f..5d4539697 100644 --- a/www/inappbrowser.js +++ b/www/inappbrowser.js @@ -98,7 +98,7 @@ } }; - module.exports = function (strUrl, strWindowName, strWindowFeatures, callbacks) { + module.exports = function (strUrl, strWindowName, strWindowFeatures, windowHeaders, callbacks) { // Don't catch calls that write to existing frames (e.g. named iframes). if (window.frames && window.frames[strWindowName]) { var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open'); @@ -116,10 +116,29 @@ var cb = function (eventname) { iab._eventHandler(eventname); }; - + var strWindowHeaders = ''; + if (windowHeaders) { + if (typeof windowHeaders === 'string' || windowHeaders instanceof String) { + strWindowHeaders = windowHeaders.replace(/@/gi, '@a'); + } else { + var first = true; + for (var k in windowHeaders) { + if (windowHeaders.hasOwnProperty(k)) { + var key = k.replace(/@/gi, '@a').replace(/,/gi, '@c').replace(/=/gi, '@e'); + var value = windowHeaders[k].toString().replace(/@/gi, '@a').replace(/,/gi, '@c').replace(/=/gi, '@e'); + if (first) { + first = false; + } else { + strWindowHeaders += ','; + } + strWindowHeaders += key + '=' + value; + } + } + } + } strWindowFeatures = strWindowFeatures || ''; - exec(cb, cb, 'InAppBrowser', 'open', [strUrl, strWindowName, strWindowFeatures]); + exec(cb, cb, 'InAppBrowser', 'open', [strUrl, strWindowName, strWindowFeatures, strWindowHeaders]); return iab; }; })();