diff --git a/CHANGELOG.md b/CHANGELOG.md index a846529..b607b9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Fixed #204: broken support for cordova-android < 7.0 +- :warning: **Deprecation**: Deprecated "disableRedirect" in favor of "setFollowRedirect" + ## 2.0.8 - Fixed #198: cookie header is always passed even if there is no cookie diff --git a/README.md b/README.md index 16eca22..5934acb 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,13 @@ Set how long to wait for a request to respond, in seconds. cordova.plugin.http.setRequestTimeout(5.0); ``` +### setFollowRedirect +Configure if it should follow redirects automatically. This defaults to true. + +```js +cordova.plugin.setFollowRedirect(true); +``` + ### getCookieString Returns saved cookies (as string) matching given URL. @@ -163,6 +170,9 @@ cordova.plugin.http.setServerTrustMode('nocheck', function() { }); ``` +### disableRedirect (deprecated) +This function was deprecated in 2.0.9. Use ["setFollowRedirect"](#setFollowRedirect) instead. + ### setSSLCertMode (deprecated) This function was deprecated in 2.0.8. Use ["setServerTrustMode"](#setServerTrustMode) instead. @@ -175,17 +185,6 @@ This function was removed in 2.0.0. Use ["setServerTrustMode"](#setServerTrustMo ### validateDomainName (obsolete) This function was removed in v1.6.2. Domain name validation is disabled automatically when you set server trust mode to "nocheck". -### disableRedirect -If set to `true`, it won't follow redirects automatically. This defaults to false. - -```js -cordova.plugin.http.disableRedirect(true, function() { - console.log('success!'); -}, function() { - console.log('error :('); -}); -``` - ### removeCookies Remove all cookies associated with a given URL. @@ -204,6 +203,7 @@ The options object contains following keys: * `params`: query params to be appended to the URL (only applicable on `get`, `head`, `delete`, `upload` or `download` methods) * `serializer`: data serializer to be used (only applicable on `post`, `put` or `patch` methods), defaults to global serializer value, see [setDataSerializer](#setDataSerializer) for supported values * `timeout`: timeout value for the request in seconds, defaults to global timeout value +* `followRedirect`: enable or disable automatically following redirects * `headers`: headers object (key value pair), will be merged with global values * `filePath`: filePath to be used during upload and download see [uploadFile](#uploadFile) and [downloadFile](#downloadFile) for detailed information * `name`: name to be used during upload see [uploadFile](#uploadFile) for detailed information diff --git a/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java b/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java index 06af026..43ccd56 100644 --- a/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java +++ b/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java @@ -20,7 +20,6 @@ import javax.net.ssl.TrustManagerFactory; public class CordovaHttpPlugin extends CordovaPlugin { private static final String TAG = "Cordova-Plugin-HTTP"; - private boolean followRedirects = true; private TLSConfiguration tlsConfiguration; @Override @@ -72,8 +71,6 @@ public class CordovaHttpPlugin extends CordovaPlugin { return this.setServerTrustMode(args, callbackContext); } else if ("setClientAuthMode".equals(action)) { return this.setClientAuthMode(args, callbackContext); - } else if ("disableRedirect".equals(action)) { - return this.disableRedirect(args, callbackContext); } else { return false; } @@ -85,9 +82,10 @@ public class CordovaHttpPlugin extends CordovaPlugin { String url = args.getString(0); JSONObject headers = args.getJSONObject(1); int timeout = args.getInt(2) * 1000; + boolean followRedirect = args.getBoolean(3); - CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, headers, timeout, - this.followRedirects, this.tlsConfiguration, callbackContext); + CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, headers, timeout, followRedirect, + this.tlsConfiguration, callbackContext); cordova.getThreadPool().execute(request); @@ -102,9 +100,10 @@ public class CordovaHttpPlugin extends CordovaPlugin { String serializer = args.getString(2); JSONObject headers = args.getJSONObject(3); int timeout = args.getInt(4) * 1000; + boolean followRedirect = args.getBoolean(5); CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, serializer, data, headers, - timeout, this.followRedirects, this.tlsConfiguration, callbackContext); + timeout, followRedirect, this.tlsConfiguration, callbackContext); cordova.getThreadPool().execute(request); @@ -117,8 +116,9 @@ public class CordovaHttpPlugin extends CordovaPlugin { String filePath = args.getString(2); String uploadName = args.getString(3); int timeout = args.getInt(4) * 1000; + boolean followRedirect = args.getBoolean(5); - CordovaHttpUpload upload = new CordovaHttpUpload(url, headers, filePath, uploadName, timeout, this.followRedirects, + CordovaHttpUpload upload = new CordovaHttpUpload(url, headers, filePath, uploadName, timeout, followRedirect, this.tlsConfiguration, callbackContext); cordova.getThreadPool().execute(upload); @@ -131,8 +131,9 @@ public class CordovaHttpPlugin extends CordovaPlugin { JSONObject headers = args.getJSONObject(1); String filePath = args.getString(2); int timeout = args.getInt(3) * 1000; + boolean followRedirect = args.getBoolean(4); - CordovaHttpDownload download = new CordovaHttpDownload(url, headers, filePath, timeout, this.followRedirects, + CordovaHttpDownload download = new CordovaHttpDownload(url, headers, filePath, timeout, followRedirect, this.tlsConfiguration, callbackContext); cordova.getThreadPool().execute(download); @@ -160,12 +161,4 @@ public class CordovaHttpPlugin extends CordovaPlugin { return true; } - - private boolean disableRedirect(final JSONArray args, final CallbackContext callbackContext) throws JSONException { - this.followRedirects = !args.getBoolean(0); - - callbackContext.success(); - - return true; - } } diff --git a/src/ios/CordovaHttpPlugin.h b/src/ios/CordovaHttpPlugin.h index 7db8989..e9daee1 100644 --- a/src/ios/CordovaHttpPlugin.h +++ b/src/ios/CordovaHttpPlugin.h @@ -5,7 +5,6 @@ @interface CordovaHttpPlugin : CDVPlugin - (void)setServerTrustMode:(CDVInvokedUrlCommand*)command; -- (void)disableRedirect:(CDVInvokedUrlCommand*)command; - (void)post:(CDVInvokedUrlCommand*)command; - (void)get:(CDVInvokedUrlCommand*)command; - (void)put:(CDVInvokedUrlCommand*)command; diff --git a/src/ios/CordovaHttpPlugin.m b/src/ios/CordovaHttpPlugin.m index 5ec9b33..ac1c99b 100644 --- a/src/ios/CordovaHttpPlugin.m +++ b/src/ios/CordovaHttpPlugin.m @@ -13,18 +13,16 @@ - (NSNumber*)getStatusCode:(NSError*) error; - (NSMutableDictionary*)copyHeaderFields:(NSDictionary*)headerFields; - (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager; -- (void)setRedirect:(AFHTTPSessionManager*)manager; +- (void)setRedirect:(bool)redirect forManager:(AFHTTPSessionManager*)manager; @end @implementation CordovaHttpPlugin { AFSecurityPolicy *securityPolicy; - bool redirect; } - (void)pluginInitialize { securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; - redirect = true; } - (void)setRequestSerializer:(NSString*)serializerName forManager:(AFHTTPSessionManager*)manager { @@ -43,9 +41,11 @@ }]; } -- (void)setRedirect:(AFHTTPSessionManager*)manager { - [manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest * _Nonnull request) { - if (redirect) { +- (void)setRedirect:(bool)followRedirect forManager:(AFHTTPSessionManager*)manager { + [manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest * _Nonnull(NSURLSession * _Nonnull session, + NSURLSessionTask * _Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest * _Nonnull request) { + + if (followRedirect) { return request; } else { return nil; @@ -53,6 +53,10 @@ }]; } +- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager { + [manager.requestSerializer setTimeoutInterval:timeout]; +} + - (void)handleSuccess:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response andData:(id)data { if (response != nil) { [dictionary setValue:response.URL.absoluteString forKey:@"url"]; @@ -149,20 +153,6 @@ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager { - [manager.requestSerializer setTimeoutInterval:timeout]; -} - -- (void)disableRedirect:(CDVInvokedUrlCommand*)command { - CDVPluginResult* pluginResult = nil; - bool disable = [[command.arguments objectAtIndex:0] boolValue]; - - redirect = !disable; - - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - - (void)get:(CDVInvokedUrlCommand*)command { AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.securityPolicy = securityPolicy; @@ -170,11 +160,12 @@ NSString *url = [command.arguments objectAtIndex:0]; NSDictionary *headers = [command.arguments objectAtIndex:1]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:3] boolValue]; [self setRequestSerializer: @"default" forManager: manager]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [TextResponseSerializer serializer]; @@ -210,10 +201,11 @@ NSString *url = [command.arguments objectAtIndex:0]; NSDictionary *headers = [command.arguments objectAtIndex:1]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:3] boolValue]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; @@ -250,11 +242,12 @@ NSString *url = [command.arguments objectAtIndex:0]; NSDictionary *headers = [command.arguments objectAtIndex:1]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:3] boolValue]; [self setRequestSerializer: @"default" forManager: manager]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [TextResponseSerializer serializer]; @@ -292,11 +285,12 @@ NSString *serializerName = [command.arguments objectAtIndex:2]; NSDictionary *headers = [command.arguments objectAtIndex:3]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:5] boolValue]; [self setRequestSerializer: serializerName forManager: manager]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [TextResponseSerializer serializer]; @@ -334,11 +328,12 @@ NSString *serializerName = [command.arguments objectAtIndex:2]; NSDictionary *headers = [command.arguments objectAtIndex:3]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:5] boolValue]; [self setRequestSerializer: serializerName forManager: manager]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [TextResponseSerializer serializer]; @@ -376,11 +371,12 @@ NSString *serializerName = [command.arguments objectAtIndex:2]; NSDictionary *headers = [command.arguments objectAtIndex:3]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:5] boolValue]; [self setRequestSerializer: serializerName forManager: manager]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [TextResponseSerializer serializer]; @@ -418,12 +414,13 @@ NSString *filePath = [command.arguments objectAtIndex: 2]; NSString *name = [command.arguments objectAtIndex: 3]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:5] boolValue]; NSURL *fileURL = [NSURL URLWithString: filePath]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; CordovaHttpPlugin* __weak weakSelf = self; manager.responseSerializer = [TextResponseSerializer serializer]; @@ -472,10 +469,11 @@ NSDictionary *headers = [command.arguments objectAtIndex:1]; NSString *filePath = [command.arguments objectAtIndex: 2]; NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:3] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:4] boolValue]; [self setRequestHeaders: headers forManager: manager]; [self setTimeout:timeoutInSeconds forManager:manager]; - [self setRedirect: manager]; + [self setRedirect:followRedirect forManager:manager]; if ([filePath hasPrefix:@"file://"]) { filePath = [filePath substringFromIndex:7]; diff --git a/test/e2e-app-template/www/index.js b/test/e2e-app-template/www/index.js index 04d0a63..40cb0c6 100644 --- a/test/e2e-app-template/www/index.js +++ b/test/e2e-app-template/www/index.js @@ -118,26 +118,6 @@ const app = { onSuccessFactory([execBeforeEachTest, execBeforeTest, execTest])(); }, - onBeforeTest: function (testIndex, resolve, reject) { - const runBeforeEachTest = function (resolve, reject) { - if (!hooks || !hooks.onBeforeEachTest) return resolve(); - - hooks.onBeforeEachTest(resolve, reject); - }; - - const runBeforeTest = function (testIndex, resolve, reject) { - if (!tests[testIndex].before) return resolve(); - - tests[testIndex].before(resolve, reject); - }; - - app.lastResult = null; - - runBeforeEachTest(function () { - runBeforeTest(testIndex, resolve); - }, reject); - }, - onFinishedAllTests: function () { const titleText = 'No more tests'; const expectedText = 'You have run all available tests.'; diff --git a/test/e2e-specs.js b/test/e2e-specs.js index d1df44c..1ae7695 100644 --- a/test/e2e-specs.js +++ b/test/e2e-specs.js @@ -1,11 +1,14 @@ const hooks = { onBeforeEachTest: function (resolve, reject) { cordova.plugin.http.clearCookies(); - helpers.setDefaultServerTrustMode(function () { - // @TODO: not ready yet - // helpers.setNoneClientAuthMode(resolve, reject); - resolve(); - }, reject); + + helpers.enableFollowingRedirect(function() { + helpers.setDefaultServerTrustMode(function () { + // @TODO: not ready yet + // helpers.setNoneClientAuthMode(resolve, reject); + resolve(); + }, reject); + }); } }; @@ -25,6 +28,8 @@ const helpers = { setJsonSerializer: function (resolve) { resolve(cordova.plugin.http.setDataSerializer('json')); }, setUtf8StringSerializer: function (resolve) { resolve(cordova.plugin.http.setDataSerializer('utf8')); }, setUrlEncodedSerializer: function (resolve) { resolve(cordova.plugin.http.setDataSerializer('urlencoded')); }, + disableFollowingRedirect: function (resolve) { resolve(cordova.plugin.http.setFollowRedirect(false)); }, + enableFollowingRedirect: function(resolve) { resolve(cordova.plugin.http.setFollowRedirect(true)); }, getWithXhr: function (done, url, type) { var xhr = new XMLHttpRequest(); @@ -266,6 +271,16 @@ const tests = [ result.data.url.should.be.equal('http://httpbin.org/anything'); } }, + { + description: 'should not follow 302 redirect when following redirects is disabled', + expected: 'rejected: {"status": 302, ...', + before: function(resolve, reject) { cordova.plugin.http.disableRedirect(true, resolve, reject)}, + func: function (resolve, reject) { cordova.plugin.http.get('http://httpbin.org/redirect-to?url=http://httpbin.org/anything', {}, {}, resolve, reject); }, + validationFunc: function (driver, result) { + result.type.should.be.equal('rejected'); + result.data.status.should.be.equal(302); + } + }, { description: 'should download a file from given URL to given path in local filesystem', expected: 'resolved: {"content": "\\n\\n" ...', diff --git a/test/js-specs.js b/test/js-specs.js index f8d024d..eb4c1c4 100644 --- a/test/js-specs.js +++ b/test/js-specs.js @@ -3,12 +3,12 @@ const mock = require('mock-require'); const should = chai.should(); describe('Advanced HTTP public interface', function () { + const messages = require('../www/messages'); let http = {}; const noop = () => { /* intentionally doing nothing */ }; const getDependenciesBlueprint = () => { - const messages = require('../www/messages'); const globalConfigs = require('../www/global-configs'); const jsUtil = require('../www/js-util'); const ToughCookie = require('../www/umd-tough-cookie'); @@ -127,7 +127,25 @@ describe('Advanced HTTP public interface', function () { }); it('throws an Error when you try to add a cookie by using "setHeader" #46', () => { - (function () { http.setHeader('*', 'cookie', 'value') }).should.throw(); + (function () { http.setHeader('*', 'cookie', 'value'); }).should.throw(); + }); + + it('configures global timeout value correctly with given valid value', () => { + http.setRequestTimeout(10); + http.getRequestTimeout().should.equal(10); + }); + + it('throws an Error when you try to configure global timeout with a string', () => { + (function () { http.setRequestTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE); + }); + + it('sets global option for following redirects correctly', () => { + http.setFollowRedirect(false); + http.getFollowRedirect().should.equal(false); + }); + + it('throws an Error when you try to configure global option for following redirects with a string', () => { + (function () { http.setFollowRedirect('myString'); }).should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE); }); }); diff --git a/www/helpers.js b/www/helpers.js index 9edca46..9e9127c 100644 --- a/www/helpers.js +++ b/www/helpers.js @@ -12,6 +12,8 @@ module.exports = function init(jsUtil, cookieHandler, messages) { checkClientAuthOptions: checkClientAuthOptions, checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey, checkForInvalidHeaderValue: checkForInvalidHeaderValue, + checkTimeoutValue: checkTimeoutValue, + checkFollowRedirectValue: checkFollowRedirectValue, injectCookieHandler: injectCookieHandler, injectFileEntryHandler: injectFileEntryHandler, getMergedHeaders: getMergedHeaders, @@ -26,7 +28,6 @@ module.exports = function init(jsUtil, cookieHandler, messages) { interface.checkForValidStringValue = checkForValidStringValue; interface.checkKeyValuePairObject = checkKeyValuePairObject; interface.checkHttpMethod = checkHttpMethod; - interface.checkTimeoutValue = checkTimeoutValue; interface.checkHeadersObject = checkHeadersObject; interface.checkParamsObject = checkParamsObject; interface.resolveCookieString = resolveCookieString; diff --git a/www/public-interface.js b/www/public-interface.js index 80261c4..60c850c 100644 --- a/www/public-interface.js +++ b/www/public-interface.js @@ -12,8 +12,11 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf getCookieString: getCookieString, getRequestTimeout: getRequestTimeout, setRequestTimeout: setRequestTimeout, + getFollowRedirect: getFollowRedirect, + setFollowRedirect: setFollowRedirect, + // @DEPRECATED disableRedirect: disableRedirect, - // for being backward compatible + // @DEPRECATED setSSLCertMode: setServerTrustMode, setServerTrustMode: setServerTrustMode, setClientAuthMode: setClientAuthMode, @@ -88,7 +91,7 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf } function setRequestTimeout(timeout) { - globalConfigs.timeout = timeout; + globalConfigs.timeout = helpers.checkTimeoutValue(timeout); } function getFollowRedirect() { @@ -96,14 +99,15 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf } function setFollowRedirect(follow) { - globalConfigs.followRedirect = follow; + globalConfigs.followRedirect = helpers.checkFollowRedirectValue(follow); } - // @TODO replace this one by "setFollowRedirect()" + // @DEPRECATED function disableRedirect(disable, success, failure) { helpers.handleMissingCallbacks(success, failure); - return exec(success, failure, 'CordovaHttpPlugin', 'disableRedirect', [!!disable]); + setFollowRedirect(!disable); + success(); } function setServerTrustMode(mode, success, failure) {