diff --git a/README.md b/README.md index 096497e..3755b6d 100644 --- a/README.md +++ b/README.md @@ -124,12 +124,25 @@ This defaults to `urlencoded`. You can also override the default content type he :warning: `multipart` depends on several Web API standards which need to be supported in your web view. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info. ### setRequestTimeout -Set the "read" timeout in seconds. This is the timeout interval to use when waiting for additional data. - +Set how long to wait for a request to respond, in seconds. +For Android, this will set both [connectTimeout](https://developer.android.com/reference/java/net/URLConnection#getConnectTimeout()) and [readTimeout](https://developer.android.com/reference/java/net/URLConnection#setReadTimeout(int)) +For iOS, this will set [timeout interval](https://developer.apple.com/documentation/foundation/nsmutableurlrequest/1414063-timeoutinterval) ```js cordova.plugin.http.setRequestTimeout(5.0); ``` +### setConnectTimeout (Android Only) +Set connect timeout for Android +```js +cordova.plugin.http.setRequestTimeout(5.0); +``` + +### setReadTimeout (Android Only) +Set read timeout for Android +```js +cordova.plugin.http.setReadTimeout(5.0); +``` + ### setFollowRedirect Configure if it should follow redirects automatically. This defaults to true. diff --git a/src/android/com/silkimen/cordovahttp/CordovaHttpBase.java b/src/android/com/silkimen/cordovahttp/CordovaHttpBase.java index 3802e75..aded979 100644 --- a/src/android/com/silkimen/cordovahttp/CordovaHttpBase.java +++ b/src/android/com/silkimen/cordovahttp/CordovaHttpBase.java @@ -35,13 +35,14 @@ abstract class CordovaHttpBase implements Runnable { protected String responseType; protected Object data; protected JSONObject headers; - protected int timeout; + protected int connectTimeout; + protected int readTimeout; protected boolean followRedirects; protected TLSConfiguration tlsConfiguration; protected CordovaObservableCallbackContext callbackContext; - public CordovaHttpBase(String method, String url, String serializer, Object data, JSONObject headers, int timeout, - boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, + public CordovaHttpBase(String method, String url, String serializer, Object data, JSONObject headers, int connectTimeout, + int readTimeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) { this.method = method; @@ -49,20 +50,22 @@ abstract class CordovaHttpBase implements Runnable { this.serializer = serializer; this.data = data; this.headers = headers; - this.timeout = timeout; + this.connectTimeout = connectTimeout; + this.readTimeout = readTimeout; this.followRedirects = followRedirects; this.responseType = responseType; this.tlsConfiguration = tlsConfiguration; this.callbackContext = callbackContext; } - public CordovaHttpBase(String method, String url, JSONObject headers, int timeout, boolean followRedirects, + public CordovaHttpBase(String method, String url, JSONObject headers, int connectTimeout, int readTimeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) { this.method = method; this.url = url; this.headers = headers; - this.timeout = timeout; + this.connectTimeout = connectTimeout; + this.readTimeout = readTimeout; this.followRedirects = followRedirects; this.responseType = responseType; this.tlsConfiguration = tlsConfiguration; @@ -128,7 +131,8 @@ abstract class CordovaHttpBase implements Runnable { protected void prepareRequest(HttpRequest request) throws JSONException, IOException { request.followRedirects(this.followRedirects); - request.readTimeout(this.timeout); + request.connectTimeout(this.connectTimeout); + request.readTimeout(this.readTimeout); request.acceptCharset("UTF-8"); request.uncompress(true); diff --git a/src/android/com/silkimen/cordovahttp/CordovaHttpDownload.java b/src/android/com/silkimen/cordovahttp/CordovaHttpDownload.java index 975f5cc..69b1fa5 100644 --- a/src/android/com/silkimen/cordovahttp/CordovaHttpDownload.java +++ b/src/android/com/silkimen/cordovahttp/CordovaHttpDownload.java @@ -15,10 +15,10 @@ import org.json.JSONObject; class CordovaHttpDownload extends CordovaHttpBase { private String filePath; - public CordovaHttpDownload(String url, JSONObject headers, String filePath, int timeout, boolean followRedirects, - TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) { + public CordovaHttpDownload(String url, JSONObject headers, String filePath, int connectTimeout, int readTimeout, + boolean followRedirects, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) { - super("GET", url, headers, timeout, followRedirects, "text", tlsConfiguration, callbackContext); + super("GET", url, headers, connectTimeout, readTimeout, followRedirects, "text", tlsConfiguration, callbackContext); this.filePath = filePath; } diff --git a/src/android/com/silkimen/cordovahttp/CordovaHttpOperation.java b/src/android/com/silkimen/cordovahttp/CordovaHttpOperation.java index 6eacca5..d24ac8e 100644 --- a/src/android/com/silkimen/cordovahttp/CordovaHttpOperation.java +++ b/src/android/com/silkimen/cordovahttp/CordovaHttpOperation.java @@ -9,16 +9,16 @@ import org.json.JSONObject; class CordovaHttpOperation extends CordovaHttpBase { public CordovaHttpOperation(String method, String url, String serializer, Object data, JSONObject headers, - int timeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, + int connectTimeout, int readTimeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) { - super(method, url, serializer, data, headers, timeout, followRedirects, responseType, tlsConfiguration, + super(method, url, serializer, data, headers, connectTimeout, readTimeout, followRedirects, responseType, tlsConfiguration, callbackContext); } - public CordovaHttpOperation(String method, String url, JSONObject headers, int timeout, boolean followRedirects, + public CordovaHttpOperation(String method, String url, JSONObject headers, int connectTimeout, int readTimeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) { - super(method, url, headers, timeout, followRedirects, responseType, tlsConfiguration, callbackContext); + super(method, url, headers, connectTimeout, readTimeout, followRedirects, responseType, tlsConfiguration, callbackContext); } } diff --git a/src/android/com/silkimen/cordovahttp/CordovaHttpUpload.java b/src/android/com/silkimen/cordovahttp/CordovaHttpUpload.java index a62a98a..d37464d 100644 --- a/src/android/com/silkimen/cordovahttp/CordovaHttpUpload.java +++ b/src/android/com/silkimen/cordovahttp/CordovaHttpUpload.java @@ -25,11 +25,11 @@ class CordovaHttpUpload extends CordovaHttpBase { private JSONArray uploadNames; private Context applicationContext; - public CordovaHttpUpload(String url, JSONObject headers, JSONArray filePaths, JSONArray uploadNames, int timeout, + public CordovaHttpUpload(String url, JSONObject headers, JSONArray filePaths, JSONArray uploadNames, int connectTimeout, int readTimeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration, Context applicationContext, CordovaObservableCallbackContext callbackContext) { - super("POST", url, headers, timeout, followRedirects, responseType, tlsConfiguration, callbackContext); + super("POST", url, headers, connectTimeout, readTimeout, followRedirects, responseType, tlsConfiguration, callbackContext); this.filePaths = filePaths; this.uploadNames = uploadNames; this.applicationContext = applicationContext; diff --git a/src/ios/CordovaHttpPlugin.m b/src/ios/CordovaHttpPlugin.m index 5d26567..b4f04b4 100644 --- a/src/ios/CordovaHttpPlugin.m +++ b/src/ios/CordovaHttpPlugin.m @@ -197,15 +197,16 @@ 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]; - NSString *responseType = [command.arguments objectAtIndex:4]; - NSNumber *reqId = [command.arguments objectAtIndex:5]; + NSTimeInterval connectTimeout = [[command.arguments objectAtIndex:2] doubleValue]; + NSTimeInterval readTimeout = [[command.arguments objectAtIndex:3] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:4] boolValue]; + NSString *responseType = [command.arguments objectAtIndex:5]; + NSNumber *reqId = [command.arguments objectAtIndex:6]; [self setRequestSerializer: @"default" forManager: manager]; [self setupAuthChallengeBlock: manager]; [self setRequestHeaders: headers forManager: manager]; - [self setTimeout:timeoutInSeconds forManager:manager]; + [self setTimeout:readTimeout forManager:manager]; [self setRedirect:followRedirect forManager:manager]; [self setResponseSerializer:responseType forManager:manager]; @@ -259,15 +260,16 @@ NSDictionary *data = [command.arguments objectAtIndex:1]; 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]; - NSString *responseType = [command.arguments objectAtIndex:6]; - NSNumber *reqId = [command.arguments objectAtIndex:7]; + NSTimeInterval connectTimeout = [[command.arguments objectAtIndex:4] doubleValue]; + NSTimeInterval readTimeout = [[command.arguments objectAtIndex:5] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:6] boolValue]; + NSString *responseType = [command.arguments objectAtIndex:7]; + NSNumber *reqId = [command.arguments objectAtIndex:8]; [self setRequestSerializer: serializerName forManager: manager]; [self setupAuthChallengeBlock: manager]; [self setRequestHeaders: headers forManager: manager]; - [self setTimeout:timeoutInSeconds forManager:manager]; + [self setTimeout:readTimeout forManager:manager]; [self setRedirect:followRedirect forManager:manager]; [self setResponseSerializer:responseType forManager:manager]; @@ -448,14 +450,14 @@ NSDictionary *headers = [command.arguments objectAtIndex:1]; NSArray *filePaths = [command.arguments objectAtIndex: 2]; NSArray *names = [command.arguments objectAtIndex: 3]; - NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue]; - bool followRedirect = [[command.arguments objectAtIndex:5] boolValue]; - NSString *responseType = [command.arguments objectAtIndex:6]; - NSNumber *reqId = [command.arguments objectAtIndex:7]; + NSTimeInterval connectTimeout = [[command.arguments objectAtIndex:4] doubleValue]; + NSTimeInterval readTimeout = [[command.arguments objectAtIndex:5] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:6] boolValue]; + NSString *responseType = [command.arguments objectAtIndex:7]; + NSNumber *reqId = [command.arguments objectAtIndex:8]; [self setRequestHeaders: headers forManager: manager]; - [self setupAuthChallengeBlock: manager]; - [self setTimeout:timeoutInSeconds forManager:manager]; + [self setTimeout:readTimeout forManager:manager]; [self setRedirect:followRedirect forManager:manager]; [self setResponseSerializer:responseType forManager:manager]; @@ -516,13 +518,14 @@ NSString *url = [command.arguments objectAtIndex:0]; 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]; - NSNumber *reqId = [command.arguments objectAtIndex:5]; + NSTimeInterval connectTimeout = [[command.arguments objectAtIndex:3] doubleValue]; + NSTimeInterval readTimeout = [[command.arguments objectAtIndex:4] doubleValue]; + bool followRedirect = [[command.arguments objectAtIndex:5] boolValue]; + NSNumber *reqId = [command.arguments objectAtIndex:6]; [self setRequestHeaders: headers forManager: manager]; [self setupAuthChallengeBlock: manager]; - [self setTimeout:timeoutInSeconds forManager:manager]; + [self setTimeout:readTimeout forManager:manager]; [self setRedirect:followRedirect forManager:manager]; if ([filePath hasPrefix:@"file://"]) { diff --git a/test/js-specs.js b/test/js-specs.js index 384a846..6dc4fb3 100644 --- a/test/js-specs.js +++ b/test/js-specs.js @@ -148,12 +148,32 @@ describe('Advanced HTTP public interface', function () { it('configures global timeout value correctly with given valid value', () => { http.setRequestTimeout(10); http.getRequestTimeout().should.equal(10); + http.getConnectTimeout().should.equal(10); + http.getReadTimeout().should.equal(10); }); it('throws an Error when you try to configure global timeout with a string', () => { (() => { http.setRequestTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE); }); + it('configures connect timeout value correctly with given valid value', () => { + http.setConnectTimeout(10); + http.getConnectTimeout().should.equal(10); + }) + + it('throws an Error when you try to configure connect timeout with a string', () => { + (() => { http.setConnectTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE); + }) + + it('configures read timeout value correctly with given valid value', () => { + http.setReadTimeout(10); + http.getReadTimeout().should.equal(10); + }) + + it('throws an Error when you try to configure connect timeout with a string', () => { + (() => { http.setReadTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE); + }) + it('sets global option for following redirects correctly', () => { http.setFollowRedirect(false); http.getFollowRedirect().should.equal(false); @@ -381,6 +401,8 @@ describe('Common helpers', function () { serializer: 'urlencoded', followRedirect: true, timeout: 60.0, + connectTimeout: 30.0, + readTimeout: 30.0 } it('adds missing "followRedirect" option correctly', () => { diff --git a/www/global-configs.js b/www/global-configs.js index c920a9b..7f43baa 100644 --- a/www/global-configs.js +++ b/www/global-configs.js @@ -3,6 +3,8 @@ var globalConfigs = { serializer: 'urlencoded', followRedirect: true, timeout: 60.0, + connectTimeout: 60.0, + readTimeout: 60.0 }; module.exports = globalConfigs; diff --git a/www/helpers.js b/www/helpers.js index 19ad259..5fefebf 100644 --- a/www/helpers.js +++ b/www/helpers.js @@ -505,7 +505,9 @@ module.exports = function init(global, jsUtil, cookieHandler, messages, base64, params: checkParamsObject(options.params || {}), responseType: checkResponseType(options.responseType || validResponseTypes[0]), serializer: checkSerializer(options.serializer || globals.serializer), - timeout: checkTimeoutValue(options.timeout || globals.timeout), + connectTimeout: checkTimeoutValue(options.connectTimeout || globals.connectTimeout), + readTimeout: checkTimeoutValue(options.readTimeout || globals.readTimeout), + timeout: checkTimeoutValue(options.timeout || globals.timeout) }; } }; diff --git a/www/public-interface.js b/www/public-interface.js index 650b5fa..7b32ddb 100644 --- a/www/public-interface.js +++ b/www/public-interface.js @@ -14,6 +14,12 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf setRequestTimeout: setRequestTimeout, getFollowRedirect: getFollowRedirect, setFollowRedirect: setFollowRedirect, + // @Android Only + getConnectTimeout: getConnectTimeout, + // @Android Only + setConnectTimeout: setConnectTimeout, + getReadTimeout: getReadTimeout, + setReadTimeout: setReadTimeout, setServerTrustMode: setServerTrustMode, setClientAuthMode: setClientAuthMode, sendRequest: sendRequest, @@ -97,6 +103,24 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf function setRequestTimeout(timeout) { globalConfigs.timeout = helpers.checkTimeoutValue(timeout); + globalConfigs.connectTimeout = helpers.checkTimeoutValue(timeout); + globalConfigs.readTimeout = helpers.checkTimeoutValue(timeout); + } + + function getConnectTimeout() { + return globalConfigs.connectTimeout; + } + + function setConnectTimeout(timeout) { + globalConfigs.connectTimeout = helpers.checkTimeoutValue(timeout); + } + + function getReadTimeout() { + return globalConfigs.readTimeout; + } + + function setReadTimeout(timeout) { + globalConfigs.readTimeout = helpers.checkTimeoutValue(timeout); } function getFollowRedirect() { @@ -151,21 +175,18 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf case 'put': case 'patch': helpers.processData(options.data, options.serializer, function (data) { - exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.timeout, options.followRedirect, options.responseType, reqId]); + exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.connectTimeout, options.readTimeout, options.followRedirect, options.responseType, reqId]); }); break; case 'upload': var fileOptions = helpers.checkUploadFileOptions(options.filePath, options.name); - exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFiles', [url, headers, fileOptions.filePaths, fileOptions.names, options.timeout, options.followRedirect, options.responseType, reqId]); - break; + exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFiles', [url, headers, fileOptions.filePaths, fileOptions.names, options.connectTimeout, options.readTimeout, options.followRedirect, options.responseType, reqId]); case 'download': var filePath = helpers.checkDownloadFilePath(options.filePath); var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success)); - exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, filePath, options.timeout, options.followRedirect, reqId]); - break; + exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, filePath, options.connectTimeout, options.readTimeout, options.followRedirect, reqId]); default: - exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, headers, options.timeout, options.followRedirect, options.responseType, reqId]); - break; + exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, headers, options.connectTimeout, options.readTimeout, options.followRedirect, options.responseType, reqId]); } return reqId;