-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add StellarTomlResolver timeout option #166
Changes from 4 commits
717772a
96acbe2
6aa24d6
bb82eed
d8529c8
acf091c
2e3c769
236c473
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
import clone from 'lodash/clone'; | ||
|
||
let defaultConfig = { | ||
allowHttp: false | ||
allowHttp: false, | ||
timeout: 0 | ||
}; | ||
|
||
let config = clone(defaultConfig); | ||
|
@@ -13,11 +14,13 @@ let config = clone(defaultConfig); | |
* ``` | ||
* import {Config} from 'stellar-sdk'; | ||
* Config.setAllowHttp(true); | ||
* Config.setTimout(5000); | ||
* ``` | ||
* | ||
* Usage browser: | ||
* ``` | ||
* StellarSdk.Config.setAllowHttp(true); | ||
* StellarSdk.Config.setTimout(5000); | ||
* ``` | ||
* @static | ||
*/ | ||
|
@@ -32,6 +35,16 @@ class Config { | |
config.allowHttp = value; | ||
} | ||
|
||
/** | ||
* Sets `timeout` flag globally. When set to anything besides 0, StellarTOMLResolver will timeout after specified time (ms). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update the comment. It's not |
||
* Default: 0. | ||
* @param {number} value | ||
* @static | ||
*/ | ||
static setTimeout(value) { | ||
config.timeout = value; | ||
} | ||
|
||
/** | ||
* Returns the value of `allowHttp` flag. | ||
* @static | ||
|
@@ -40,6 +53,14 @@ class Config { | |
return clone(config.allowHttp); | ||
} | ||
|
||
/** | ||
* Returns the value of `timeout` flag. | ||
* @static | ||
*/ | ||
static getTimeout() { | ||
return clone(config.timeout); | ||
} | ||
|
||
/** | ||
* Sets all global config flags to default values. | ||
* @static | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ export const FEDERATION_RESPONSE_MAX_SIZE = 100 * 1024; | |
* @param {string} domain Domain this server represents | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! You can also use {@link Config} class to set this globally. | ||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. In ms. | ||
*/ | ||
export class FederationServer { | ||
constructor(serverURL, domain, opts = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Static method instantiate this class but |
||
|
@@ -71,6 +72,7 @@ export class FederationServer { | |
* @param {string} value Stellar Address (ex. `bob*stellar.org`) | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! | ||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. Allows user to avoid nasty lag due to TOML resolve issue. | ||
* @returns {Promise} | ||
*/ | ||
static resolve(value, opts = {}) { | ||
|
@@ -109,10 +111,11 @@ export class FederationServer { | |
* @param {string} domain Domain to get federation server for | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! | ||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. Allows user to avoid nasty lag due to TOML resolve issue. | ||
* @returns {Promise} | ||
*/ | ||
static createForDomain(domain, opts = {}) { | ||
return StellarTomlResolver.resolve(domain) | ||
return StellarTomlResolver.resolve(domain, opts) | ||
.then(tomlObject => { | ||
if (!tomlObject.FEDERATION_SERVER) { | ||
return Promise.reject(new Error('stellar.toml does not contain FEDERATION_SERVER field')); | ||
|
@@ -125,43 +128,62 @@ export class FederationServer { | |
* Returns a Promise that resolves to federation record if the user was found for a given Stellar address. | ||
* @see <a href="https://www.stellar.org/developers/learn/concepts/federation.html" target="_blank">Federation doc</a> | ||
* @param {string} address Stellar address (ex. `bob*stellar.org`). If `FederationServer` was instantiated with `domain` param only username (ex. `bob`) can be passed. | ||
* @returns {Promise} | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! | ||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. In ms. | ||
*/ | ||
resolveAddress(address) { | ||
resolveAddress(address, opts = {}) { | ||
if (address.indexOf('*') < 0) { | ||
if (!this.domain) { | ||
return Promise.reject(new Error('Unknown domain. Make sure `address` contains a domain (ex. `bob*stellar.org`) or pass `domain` parameter when instantiating the server object.')); | ||
} | ||
address = `${address}*${this.domain}`; | ||
} | ||
let url = this.serverURL.query({type: 'name', q: address}); | ||
return this._sendRequest(url); | ||
return this._sendRequest(url, opts); | ||
} | ||
|
||
/** | ||
* Returns a Promise that resolves to federation record if the user was found for a given account ID. | ||
* @see <a href="https://www.stellar.org/developers/learn/concepts/federation.html" target="_blank">Federation doc</a> | ||
* @param {string} accountId Account ID (ex. `GBYNR2QJXLBCBTRN44MRORCMI4YO7FZPFBCNOKTOBCAAFC7KC3LNPRYS`) | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! | ||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. In ms. | ||
* @returns {Promise} | ||
*/ | ||
resolveAccountId(accountId) { | ||
resolveAccountId(accountId, opts = {}) { | ||
let url = this.serverURL.query({type: 'id', q: accountId}); | ||
return this._sendRequest(url); | ||
return this._sendRequest(url, opts); | ||
} | ||
|
||
/** | ||
* Returns a Promise that resolves to federation record if the sender of the transaction was found for a given transaction ID. | ||
* @see <a href="https://www.stellar.org/developers/learn/concepts/federation.html" target="_blank">Federation doc</a> | ||
* @param {string} transactionId Transaction ID (ex. `3389e9f0f1a65f19736cacf544c2e825313e8447f569233bb8db39aa607c8889`) | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. In ms. | ||
* @returns {Promise} | ||
*/ | ||
resolveTransactionId(transactionId) { | ||
resolveTransactionId(transactionId, opts = {}) { | ||
let url = this.serverURL.query({type: 'txid', q: transactionId}); | ||
return this._sendRequest(url); | ||
return this._sendRequest(url, opts); | ||
} | ||
|
||
_sendRequest(url) { | ||
return axios.get(url.toString(), {maxContentLength: FEDERATION_RESPONSE_MAX_SIZE}) | ||
_sendRequest(url, opts = {}) { | ||
let allowHttp = Config.isAllowHttp(); | ||
let timeout = Config.getTimeout(); | ||
|
||
if (typeof opts.allowHttp !== 'undefined') { | ||
allowHttp = opts.allowHttp; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for |
||
|
||
if (typeof opts.timeout === 'number') { | ||
timeout = opts.timeout; | ||
} | ||
|
||
return axios.get(url.toString(), {maxContentLength: FEDERATION_RESPONSE_MAX_SIZE, timeout}) | ||
.then(response => { | ||
if (typeof response.data.memo != "undefined" && typeof response.data.memo != 'string') { | ||
throw new Error("memo value should be of type string"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ export const SUBMIT_TRANSACTION_TIMEOUT = 60*1000; | |
* @param {string} serverURL Horizon Server URL (ex. `https://horizon-testnet.stellar.org`). | ||
* @param {object} [opts] | ||
* @param {boolean} [opts.allowHttp] - Allow connecting to http servers, default: `false`. This must be set to false in production deployments! You can also use {@link Config} class to set this globally. | ||
* @param {number} [opts.timeout] - Allow a timeout, default: 0. In ms. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not passed to |
||
*/ | ||
export class Server { | ||
constructor(serverURL, opts = {}) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,5 +106,44 @@ FEDERATION_SERVER="https://api.stellar.org/federation" | |
.then(() => tempServer.close()); | ||
}); | ||
}); | ||
|
||
it("rejects after given timeout when global Config.timeout flag is set", function (done) { | ||
StellarSdk.Config.setTimeout(1000); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add |
||
|
||
if (typeof window != 'undefined') { | ||
return done(); | ||
} | ||
var response = Array(StellarSdk.STELLAR_TOML_MAX_SIZE+10).join('a'); | ||
let tempServer = http.createServer((req, res) => { | ||
setTimeout(() => { | ||
res.setHeader('Content-Type', 'text/x-toml; charset=UTF-8'); | ||
res.end(response); | ||
}, 10000); | ||
}).listen(4444, () => { | ||
StellarSdk.StellarTomlResolver.resolve("localhost:4444", {allowHttp: true}) | ||
.should.be.rejectedWith(/timeout of 1000ms exceeded/) | ||
.notify(done) | ||
.then(() => tempServer.close()); | ||
}); | ||
}); | ||
|
||
it("rejects after given timeout when timeout specified in StellarTomlResolver opts param", function (done) { | ||
// Unable to create temp server in a browser | ||
if (typeof window != 'undefined') { | ||
return done(); | ||
} | ||
var response = Array(StellarSdk.STELLAR_TOML_MAX_SIZE+10).join('a'); | ||
let tempServer = http.createServer((req, res) => { | ||
setTimeout(() => { | ||
res.setHeader('Content-Type', 'text/x-toml; charset=UTF-8'); | ||
res.end(response); | ||
}, 10000); | ||
}).listen(4444, () => { | ||
StellarSdk.StellarTomlResolver.resolve("localhost:4444", {allowHttp: true, timeout: 1000}) | ||
.should.be.rejectedWith(/timeout of 1000ms exceeded/) | ||
.notify(done) | ||
.then(() => tempServer.close()); | ||
}); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default here should be a global setting so
Config.getTimeout()
.