forked from tornadocash/tornado-cli
Fix gas issues: add correct estimation for relayer withdrawal, add L1 fee fetching for Optimism, correct gas price estimation
This commit is contained in:
parent
7243803b21
commit
ac0ccbb787
151
build/contracts/OptimismL1GasPriceOracle.json
Normal file
151
build/contracts/OptimismL1GasPriceOracle.json
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "address", "name": "_owner", "type": "address" }],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"name": "DecimalsUpdated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"name": "GasPriceUpdated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"name": "L1BaseFeeUpdated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"name": "OverheadUpdated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{ "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" },
|
||||||
|
{ "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" }
|
||||||
|
],
|
||||||
|
"name": "OwnershipTransferred",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"name": "ScalarUpdated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "decimals",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "gasPrice",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "bytes", "name": "_data", "type": "bytes" }],
|
||||||
|
"name": "getL1Fee",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "bytes", "name": "_data", "type": "bytes" }],
|
||||||
|
"name": "getL1GasUsed",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "l1BaseFee",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "overhead",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "owner",
|
||||||
|
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "renounceOwnership",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "scalar",
|
||||||
|
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "uint256", "name": "_decimals", "type": "uint256" }],
|
||||||
|
"name": "setDecimals",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "uint256", "name": "_gasPrice", "type": "uint256" }],
|
||||||
|
"name": "setGasPrice",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "uint256", "name": "_baseFee", "type": "uint256" }],
|
||||||
|
"name": "setL1BaseFee",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "uint256", "name": "_overhead", "type": "uint256" }],
|
||||||
|
"name": "setOverhead",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "uint256", "name": "_scalar", "type": "uint256" }],
|
||||||
|
"name": "setScalar",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
|
||||||
|
"name": "transferOwnership",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
150
cli.js
150
cli.js
@ -11,6 +11,7 @@ const bigInt = snarkjs.bigInt;
|
|||||||
const merkleTree = require('@tornado/fixed-merkle-tree');
|
const merkleTree = require('@tornado/fixed-merkle-tree');
|
||||||
const Web3 = require('web3');
|
const Web3 = require('web3');
|
||||||
const Web3HttpProvider = require('@tornado/web3-providers-http');
|
const Web3HttpProvider = require('@tornado/web3-providers-http');
|
||||||
|
const { serialize } = require('@ethersproject/transactions');
|
||||||
const buildGroth16 = require('@tornado/websnark/src/groth16');
|
const buildGroth16 = require('@tornado/websnark/src/groth16');
|
||||||
const websnarkUtils = require('@tornado/websnark/src/utils');
|
const websnarkUtils = require('@tornado/websnark/src/utils');
|
||||||
const { toWei, fromWei, toBN, BN } = require('web3-utils');
|
const { toWei, fromWei, toBN, BN } = require('web3-utils');
|
||||||
@ -32,7 +33,7 @@ let web3,
|
|||||||
tornadoContract,
|
tornadoContract,
|
||||||
tornadoInstance,
|
tornadoInstance,
|
||||||
circuit,
|
circuit,
|
||||||
proving_key,
|
provingKey,
|
||||||
groth16,
|
groth16,
|
||||||
erc20,
|
erc20,
|
||||||
senderAccount,
|
senderAccount,
|
||||||
@ -40,13 +41,13 @@ let web3,
|
|||||||
netName,
|
netName,
|
||||||
netSymbol,
|
netSymbol,
|
||||||
multiCall,
|
multiCall,
|
||||||
|
userAction,
|
||||||
subgraph;
|
subgraph;
|
||||||
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY;
|
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY;
|
||||||
|
|
||||||
/** Command state parameters */
|
/** Command state parameters */
|
||||||
let preferenceSpeed = gasSpeedPreferences[0];
|
let preferenceSpeed = gasSpeedPreferences[0];
|
||||||
let isTestRPC,
|
let isTestRPC = false;
|
||||||
eipGasSupport = false;
|
|
||||||
let shouldPromptConfirmation = true;
|
let shouldPromptConfirmation = true;
|
||||||
let doNotSubmitTx, privateRpc;
|
let doNotSubmitTx, privateRpc;
|
||||||
/** ----------------------------------------- **/
|
/** ----------------------------------------- **/
|
||||||
@ -178,9 +179,43 @@ async function estimateGas(from, to, nonce, encodedData, value = 0) {
|
|||||||
return bumped;
|
return bumped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchL1Fee({ gasPrice, gasLimit }) {
|
||||||
|
const DUMMY_NONCE = '0x1111111111111111111111111111111111111111111111111111111111111111';
|
||||||
|
|
||||||
|
const DUMMY_WITHDRAW_DATA =
|
||||||
|
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111';
|
||||||
|
|
||||||
|
if (netId === 10) {
|
||||||
|
const ovmGasPriceOracleContractAddress = '0x420000000000000000000000000000000000000F';
|
||||||
|
const optimismL1GasPriceOracleABI = require('./build/contracts/OptimismL1GasPriceOracle.json');
|
||||||
|
const oracleInstance = new web3.eth.Contract(optimismL1GasPriceOracleABI, ovmGasPriceOracleContractAddress);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tx = serialize({
|
||||||
|
type: 0,
|
||||||
|
gasLimit,
|
||||||
|
chainId: netId,
|
||||||
|
nonce: DUMMY_NONCE,
|
||||||
|
data: DUMMY_WITHDRAW_DATA,
|
||||||
|
gasPrice,
|
||||||
|
to: tornadoProxyAddress
|
||||||
|
});
|
||||||
|
|
||||||
|
const l1Fee = await oracleInstance.methods.getL1Fee(tx).call();
|
||||||
|
|
||||||
|
return l1Fee;
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error('Error while fetching optimism L1 fee: ' + err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
async function generateTransaction(to, encodedData, value = 0) {
|
async function generateTransaction(to, encodedData, value = 0) {
|
||||||
const nonce = await web3.eth.getTransactionCount(senderAccount);
|
const nonce = await web3.eth.getTransactionCount(senderAccount);
|
||||||
let gasPrice = await fetchGasPrice();
|
let gasPrice = await fetchGasPrice();
|
||||||
|
|
||||||
let gasLimit;
|
let gasLimit;
|
||||||
|
|
||||||
if (encodedData) {
|
if (encodedData) {
|
||||||
@ -192,12 +227,16 @@ async function generateTransaction(to, encodedData, value = 0) {
|
|||||||
|
|
||||||
const isNumRString = typeof value == 'string' || typeof value == 'number';
|
const isNumRString = typeof value == 'string' || typeof value == 'number';
|
||||||
const valueCost = isNumRString ? toBN(value) : value;
|
const valueCost = isNumRString ? toBN(value) : value;
|
||||||
const gasCosts = toBN(gasPrice).mul(toBN(gasLimit));
|
|
||||||
|
const additionalFees = userAction === 'withdrawal' ? await fetchL1Fee({ gasPrice, gasLimit }) : 0;
|
||||||
|
const gasCosts = toBN(gasPrice).mul(toBN(gasLimit)).add(toBN(additionalFees));
|
||||||
const totalCosts = valueCost.add(gasCosts);
|
const totalCosts = valueCost.add(gasCosts);
|
||||||
|
|
||||||
/** Transaction details */
|
/** Transaction details */
|
||||||
console.log('Gas price: ', web3.utils.hexToNumber(gasPrice));
|
console.log('Gas price: ', web3.utils.hexToNumber(gasPrice));
|
||||||
console.log('Gas limit: ', web3.utils.hexToNumber(gasLimit));
|
console.log('Gas limit: ', web3.utils.hexToNumber(gasLimit));
|
||||||
|
if (additionalFees != 0)
|
||||||
|
console.log('Additional gas fees (like L1 data fee): ', rmDecimalBN(fromWei(additionalFees), 12), `${netSymbol}`);
|
||||||
console.log('Transaction fee: ', rmDecimalBN(fromWei(gasCosts), 12), `${netSymbol}`);
|
console.log('Transaction fee: ', rmDecimalBN(fromWei(gasCosts), 12), `${netSymbol}`);
|
||||||
console.log('Transaction cost: ', rmDecimalBN(fromWei(totalCosts), 12), `${netSymbol}`);
|
console.log('Transaction cost: ', rmDecimalBN(fromWei(totalCosts), 12), `${netSymbol}`);
|
||||||
/** ----------------------------------------- **/
|
/** ----------------------------------------- **/
|
||||||
@ -463,7 +502,7 @@ async function generateProof({ deposit, currency, amount, recipient, relayerAddr
|
|||||||
|
|
||||||
console.log('Generating SNARK proof');
|
console.log('Generating SNARK proof');
|
||||||
console.time('Proof time');
|
console.time('Proof time');
|
||||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key);
|
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, provingKey);
|
||||||
const { proof } = websnarkUtils.toSolidityInput(proofData);
|
const { proof } = websnarkUtils.toSolidityInput(proofData);
|
||||||
console.timeEnd('Proof time');
|
console.timeEnd('Proof time');
|
||||||
|
|
||||||
@ -520,7 +559,7 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
|||||||
const merkleWithdrawalProof = await generateMerkleProof(deposit, currency, amount);
|
const merkleWithdrawalProof = await generateMerkleProof(deposit, currency, amount);
|
||||||
|
|
||||||
async function calculateDataForRelayer(gasLimit) {
|
async function calculateDataForRelayer(gasLimit) {
|
||||||
const { desiredFee: totalFee, feePercent: relayerFee } = calculateRelayerWithdrawFee({
|
const { desiredFee: totalFee, feePercent: relayerFee } = await calculateRelayerWithdrawFee({
|
||||||
currency,
|
currency,
|
||||||
gasPrice,
|
gasPrice,
|
||||||
amount,
|
amount,
|
||||||
@ -550,8 +589,9 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
|||||||
const { proof, args, totalFee, relayerFee } = await calculateDataForRelayer(realGasLimit);
|
const { proof, args, totalFee, relayerFee } = await calculateDataForRelayer(realGasLimit);
|
||||||
|
|
||||||
console.log('Sending withdraw transaction through relay');
|
console.log('Sending withdraw transaction through relay');
|
||||||
|
const l1Fee = await fetchL1Fee({ gasPrice, gasLimit: realGasLimit });
|
||||||
const gasCosts = toBN(gasPrice).mul(toBN(realGasLimit));
|
console.log(l1Fee);
|
||||||
|
const gasCosts = toBN(gasPrice).mul(toBN(realGasLimit)).add(toBN(l1Fee));
|
||||||
|
|
||||||
/** Relayer fee details **/
|
/** Relayer fee details **/
|
||||||
console.log('Transaction fee: ', rmDecimalBN(fromWei(gasCosts), 12), `${netSymbol}`);
|
console.log('Transaction fee: ', rmDecimalBN(fromWei(gasCosts), 12), `${netSymbol}`);
|
||||||
@ -864,37 +904,31 @@ function getCurrentNetworkSymbol() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function gasPricesETH(value = 80) {
|
|
||||||
const tenPercent = (Number(value) * 5) / 100;
|
|
||||||
const max = Math.max(tenPercent, 3);
|
|
||||||
const bumped = Math.floor(Number(value) + max);
|
|
||||||
return toHex(toWei(bumped.toString(), 'gwei'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function gasPrices(value = 5) {
|
|
||||||
return toHex(toWei(value.toString(), 'gwei'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchGasPrice() {
|
async function fetchGasPrice() {
|
||||||
try {
|
try {
|
||||||
/** Gas preferences **/
|
/** Gas preferences **/
|
||||||
console.log('Gas speed preference: ', preferenceSpeed);
|
console.log('Gas speed preference: ', preferenceSpeed);
|
||||||
/** ----------------------------------------------- **/
|
/** ----------------------------------------------- **/
|
||||||
|
|
||||||
try {
|
// Extra bump estimated gas price for Polygon and Goerli
|
||||||
const isLegacy = !eipGasSupport;
|
const bumpPercent = netId === 137 || netId === 5 ? 30 : 10;
|
||||||
const oracleOptions = { chainId: netId, defaultRpc: web3.currentProvider.host };
|
|
||||||
const oracle = new GasPriceOracle(oracleOptions);
|
|
||||||
const gas = await oracle.gasPrices({ isLegacy });
|
|
||||||
|
|
||||||
if (netId === 1) {
|
try {
|
||||||
return gasPricesETH(gas[preferenceSpeed]);
|
const oracleOptions = {
|
||||||
} else {
|
chainId: netId,
|
||||||
return gasPrices(gas[preferenceSpeed]);
|
defaultRpc: web3.currentProvider.host,
|
||||||
}
|
minPriority: netId === 1 ? 3 : 0.05,
|
||||||
|
percentile: 5,
|
||||||
|
blocksCount: 20
|
||||||
|
};
|
||||||
|
const oracle = new GasPriceOracle(oracleOptions);
|
||||||
|
const { maxFeePerGas, gasPrice } = await oracle.getTxGasParams({ legacySpeed: preferenceSpeed, bumpPercent });
|
||||||
|
|
||||||
|
return maxFeePerGas || gasPrice;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const wei = await web3.eth.getGasPrice();
|
const wei = toBN(await web3.eth.getGasPrice());
|
||||||
return wei / web3.utils.unitMap.gwei;
|
const bumped = wei.add(wei.mul(toBN(bumpPercent)).div(toBN(100)));
|
||||||
|
return toHex(bumped);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`Method fetchGasPrice has error ${err.message}`);
|
throw new Error(`Method fetchGasPrice has error ${err.message}`);
|
||||||
@ -936,13 +970,26 @@ async function estimateWithdrawGasLimit({ relayer, proof, callArgs }) {
|
|||||||
return gasLimit;
|
return gasLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateRelayerWithdrawFee({ currency, gasPrice, amount, refund, ethPrices, relayerServiceFee, decimals, gasLimit }) {
|
async function calculateRelayerWithdrawFee({
|
||||||
|
currency,
|
||||||
|
gasPrice,
|
||||||
|
amount,
|
||||||
|
refund,
|
||||||
|
ethPrices,
|
||||||
|
relayerServiceFee,
|
||||||
|
decimals,
|
||||||
|
gasLimit
|
||||||
|
}) {
|
||||||
const decimalsPoint =
|
const decimalsPoint =
|
||||||
Math.floor(relayerServiceFee) === Number(relayerServiceFee) ? 0 : relayerServiceFee.toString().split('.')[1].length;
|
Math.floor(relayerServiceFee) === Number(relayerServiceFee) ? 0 : relayerServiceFee.toString().split('.')[1].length;
|
||||||
const roundDecimal = 10 ** decimalsPoint;
|
const roundDecimal = 10 ** decimalsPoint;
|
||||||
const total = toBN(fromDecimals({ amount, decimals }));
|
const total = toBN(fromDecimals({ amount, decimals }));
|
||||||
const feePercent = total.mul(toBN(relayerServiceFee * roundDecimal)).div(toBN(roundDecimal * 100));
|
const feePercent = total.mul(toBN(relayerServiceFee * roundDecimal)).div(toBN(roundDecimal * 100));
|
||||||
const expense = toBN(gasPrice).mul(toBN(gasLimit || getHardcodedWithdrawGasLimit(netId)));
|
const l1Fee = await fetchL1Fee({ gasPrice, gasLimit });
|
||||||
|
const expense = toBN(gasPrice)
|
||||||
|
.mul(toBN(gasLimit || getHardcodedWithdrawGasLimit(netId)))
|
||||||
|
.add(toBN(l1Fee));
|
||||||
|
|
||||||
let desiredFee;
|
let desiredFee;
|
||||||
switch (currency) {
|
switch (currency) {
|
||||||
case netSymbol.toLowerCase(): {
|
case netSymbol.toLowerCase(): {
|
||||||
@ -1010,7 +1057,7 @@ function filterZeroEvents(events) {
|
|||||||
|
|
||||||
function loadCachedEvents({ type, currency, amount }) {
|
function loadCachedEvents({ type, currency, amount }) {
|
||||||
try {
|
try {
|
||||||
const module = require(`./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`);
|
const module = require(`./cache/${netName.toLowerCase()}/${type}s_${currency.toLowerCase()}_${amount}.json`);
|
||||||
|
|
||||||
if (module) {
|
if (module) {
|
||||||
const events = module;
|
const events = module;
|
||||||
@ -1042,11 +1089,13 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
console.log('Fetching', amount, currency.toUpperCase(), type, 'events for', netName, 'network');
|
console.log('Fetching', amount, currency.toUpperCase(), type, 'events for', netName, 'network');
|
||||||
|
|
||||||
async function updateCache(fetchedEvents) {
|
async function updateCache(fetchedEvents) {
|
||||||
|
if (type === 'deposit') fetchedEvents.sort((firstLeaf, secondLeaf) => firstLeaf.leafIndex - secondLeaf.leafIndex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`;
|
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency.toLowerCase()}_${amount}.json`;
|
||||||
const localEvents = await initJson(fileName);
|
const localEvents = await initJson(fileName);
|
||||||
const events = filterZeroEvents(localEvents).concat(fetchedEvents);
|
const events = filterZeroEvents(localEvents).concat(fetchedEvents);
|
||||||
await fs.writeFileSync(fileName, JSON.stringify(events, null, 2), 'utf8');
|
fs.writeFileSync(fileName, JSON.stringify(events, null, 2), 'utf8');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('Writing cache file failed:', error);
|
throw new Error('Writing cache file failed:', error);
|
||||||
}
|
}
|
||||||
@ -1056,7 +1105,7 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
* Adds an zero (empty) event to the end of the events list
|
* Adds an zero (empty) event to the end of the events list
|
||||||
* If tornado transactions on the selected currency/amount are rare and the last one was much earlier than the current block,
|
* If tornado transactions on the selected currency/amount are rare and the last one was much earlier than the current block,
|
||||||
* it helps to quickly synchronize the events tree
|
* it helps to quickly synchronize the events tree
|
||||||
* @param blockNumber Latest block number on selected chain
|
* @param {number} blockNumber Latest block number on selected chain
|
||||||
*/
|
*/
|
||||||
async function addZeroEvent(blockNumber) {
|
async function addZeroEvent(blockNumber) {
|
||||||
const zeroEvent = { blockNumber, transactionHash: null };
|
const zeroEvent = { blockNumber, transactionHash: null };
|
||||||
@ -1068,7 +1117,7 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
async function syncEvents() {
|
async function syncEvents() {
|
||||||
try {
|
try {
|
||||||
let targetBlock = await web3.eth.getBlockNumber();
|
let targetBlock = await web3.eth.getBlockNumber();
|
||||||
let chunks = 1000;
|
let chunks = 10000;
|
||||||
console.log('Querying latest events from RPC');
|
console.log('Querying latest events from RPC');
|
||||||
|
|
||||||
for (let i = startBlock; i < targetBlock; i += chunks) {
|
for (let i = startBlock; i < targetBlock; i += chunks) {
|
||||||
@ -1138,8 +1187,6 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
await fetchWeb3Events(i);
|
await fetchWeb3Events(i);
|
||||||
await updateCache(fetchedEvents);
|
await updateCache(fetchedEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
await addZeroEvent(targetBlock);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
throw new Error('Error while updating cache');
|
throw new Error('Error while updating cache');
|
||||||
@ -1158,9 +1205,10 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
async function queryLatestTimestamp() {
|
async function queryLatestTimestamp() {
|
||||||
try {
|
try {
|
||||||
const variables = {
|
const variables = {
|
||||||
currency: currency.toString(),
|
currency: currency.toString().toLowerCase(),
|
||||||
amount: amount.toString()
|
amount: amount.toString().toLowerCase()
|
||||||
};
|
};
|
||||||
|
console.log(variables);
|
||||||
if (type === 'deposit') {
|
if (type === 'deposit') {
|
||||||
const query = {
|
const query = {
|
||||||
query: `
|
query: `
|
||||||
@ -1201,11 +1249,12 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
async function queryFromGraph(timestamp) {
|
async function queryFromGraph(timestamp) {
|
||||||
try {
|
try {
|
||||||
const variables = {
|
const variables = {
|
||||||
currency: currency.toString(),
|
currency: currency.toString().toLowerCase(),
|
||||||
amount: amount.toString(),
|
amount: amount.toString().toLowerCase(),
|
||||||
timestamp: timestamp
|
timestamp: timestamp
|
||||||
};
|
};
|
||||||
if (type === 'deposit') {
|
if (type === 'deposit') {
|
||||||
|
console.log(variables);
|
||||||
const query = {
|
const query = {
|
||||||
query: `
|
query: `
|
||||||
query($currency: String, $amount: String, $timestamp: Int){
|
query($currency: String, $amount: String, $timestamp: Int){
|
||||||
@ -1228,7 +1277,7 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
transactionHash,
|
transactionHash,
|
||||||
commitment,
|
commitment,
|
||||||
leafIndex: Number(index),
|
leafIndex: Number(index),
|
||||||
timestamp
|
timestamp: Number(timestamp)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return mapResult;
|
return mapResult;
|
||||||
@ -1299,18 +1348,20 @@ async function fetchEvents({ type, currency, amount, filterEvents }) {
|
|||||||
}
|
}
|
||||||
await fetchGraphEvents();
|
await fetchGraphEvents();
|
||||||
}
|
}
|
||||||
if (!privateRpc && subgraph && !isTestRPC) {
|
if (!privateRpc && !subgraph && !isTestRPC) {
|
||||||
await syncGraphEvents();
|
await syncGraphEvents();
|
||||||
} else {
|
} else {
|
||||||
await syncEvents();
|
await syncEvents();
|
||||||
}
|
}
|
||||||
|
await addZeroEvent(await web3.eth.getBlockNumber());
|
||||||
|
|
||||||
async function loadUpdatedEvents() {
|
async function loadUpdatedEvents() {
|
||||||
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`;
|
// Don't use loadCachedEvents function, because we need to check zero event block (to which block we updated)
|
||||||
|
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency.toLowerCase()}_${amount}.json`;
|
||||||
const updatedEvents = await initJson(fileName);
|
const updatedEvents = await initJson(fileName);
|
||||||
const updatedBlock = updatedEvents[updatedEvents.length - 1].blockNumber;
|
const updatedBlock = updatedEvents[updatedEvents.length - 1].blockNumber;
|
||||||
console.log('Cache updated for Tornado', type, amount, currency, 'instance to block', updatedBlock, 'successfully');
|
console.log('Cache updated for Tornado', type, amount, currency, 'instance to block', updatedBlock, 'successfully');
|
||||||
console.log(`Total ${type}s:`, updatedEvents.length);
|
console.log(`Total ${type}s:`, updatedEvents.length - 1);
|
||||||
return updatedEvents;
|
return updatedEvents;
|
||||||
}
|
}
|
||||||
const events = await loadUpdatedEvents();
|
const events = await loadUpdatedEvents();
|
||||||
@ -1510,7 +1561,7 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceC
|
|||||||
contractJson = require('./build/contracts/TornadoProxy.abi.json');
|
contractJson = require('./build/contracts/TornadoProxy.abi.json');
|
||||||
instanceJson = require('./build/contracts/Instance.abi.json');
|
instanceJson = require('./build/contracts/Instance.abi.json');
|
||||||
circuit = require('./build/circuits/tornado.json');
|
circuit = require('./build/circuits/tornado.json');
|
||||||
proving_key = fs.readFileSync('build/circuits/tornadoProvingKey.bin').buffer;
|
provingKey = fs.readFileSync('build/circuits/tornadoProvingKey.bin').buffer;
|
||||||
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20;
|
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20;
|
||||||
ETH_AMOUNT = process.env.ETH_AMOUNT;
|
ETH_AMOUNT = process.env.ETH_AMOUNT;
|
||||||
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT;
|
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT;
|
||||||
@ -1642,6 +1693,7 @@ async function main() {
|
|||||||
statePreferences(program);
|
statePreferences(program);
|
||||||
|
|
||||||
const { currency, amount, netId, deposit } = parseNote(noteString);
|
const { currency, amount, netId, deposit } = parseNote(noteString);
|
||||||
|
userAction = 'withdrawal';
|
||||||
|
|
||||||
await init({
|
await init({
|
||||||
rpc: program.rpc,
|
rpc: program.rpc,
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
# web3-providers-http
|
|
||||||
|
|
||||||
[![NPM Package][npm-image]][npm-url] [![Dependency Status][deps-image]][deps-url] [![Dev Dependency Status][deps-dev-image]][deps-dev-url]
|
|
||||||
|
|
||||||
Package forked from https://github.com/ChainSafe/web3.js/tree/v1.6.1/packages/web3-providers-http to change http headers
|
|
||||||
|
|
||||||
This is a HTTP provider sub-package for [web3.js][repo].
|
|
||||||
|
|
||||||
Please read the [documentation][docs] for more.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Node.js
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install web3-providers-http
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
const http = require('http');
|
|
||||||
const Web3HttpProvider = require('web3-providers-http');
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
keepAlive: true,
|
|
||||||
timeout: 20000, // milliseconds,
|
|
||||||
headers: [{name: 'Access-Control-Allow-Origin', value: '*'},{...}],
|
|
||||||
withCredentials: false,
|
|
||||||
agent: {http: http.Agent(...), baseUrl: ''}
|
|
||||||
};
|
|
||||||
|
|
||||||
const provider = new Web3HttpProvider('http://localhost:8545', options);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Types
|
|
||||||
|
|
||||||
All the TypeScript typings are placed in the `types` folder.
|
|
||||||
|
|
||||||
[docs]: http://web3js.readthedocs.io/en/1.0/
|
|
||||||
[repo]: https://github.com/ethereum/web3.js
|
|
||||||
[npm-image]: https://img.shields.io/npm/dm/web3-providers-http.svg
|
|
||||||
[npm-url]: https://npmjs.org/package/web3-providers-http
|
|
||||||
[deps-image]: https://david-dm.org/ethereum/web3.js/1.x/status.svg?path=packages/web3-providers-http
|
|
||||||
[deps-url]: https://david-dm.org/ethereum/web3.js/1.x?path=packages/web3-providers-http
|
|
||||||
[deps-dev-image]: https://david-dm.org/ethereum/web3.js/1.x/dev-status.svg?path=packages/web3-providers-http
|
|
||||||
[deps-dev-url]: https://david-dm.org/ethereum/web3.js/1.x?type=dev&path=packages/web3-providers-http
|
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of web3.js.
|
|
||||||
|
|
||||||
web3.js is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
web3.js is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/** @file httpprovider.js
|
|
||||||
* @authors:
|
|
||||||
* Marek Kotewicz <marek@parity.io>
|
|
||||||
* Marian Oancea
|
|
||||||
* Fabian Vogelsteller <fabian@ethereum.org>
|
|
||||||
* @date 2015
|
|
||||||
*/
|
|
||||||
var errors = require('web3-core-helpers').errors;
|
|
||||||
var XHR2 = require('xhr2-cookies').XMLHttpRequest; // jshint ignore: line
|
|
||||||
var http = require('http');
|
|
||||||
var https = require('https');
|
|
||||||
/**
|
|
||||||
* HttpProvider should be used to send rpc calls over http
|
|
||||||
*/
|
|
||||||
var HttpProvider = function HttpProvider(host, options) {
|
|
||||||
options = options || {};
|
|
||||||
this.withCredentials = options.withCredentials || false;
|
|
||||||
this.timeout = options.timeout || 0;
|
|
||||||
this.headers = options.headers;
|
|
||||||
this.agent = options.agent;
|
|
||||||
this.connected = false;
|
|
||||||
// keepAlive is true unless explicitly set to false
|
|
||||||
const keepAlive = options.keepAlive !== false;
|
|
||||||
this.host = host || 'http://localhost:8545';
|
|
||||||
if (!this.agent) {
|
|
||||||
if (this.host.substring(0, 5) === "https") {
|
|
||||||
this.httpsAgent = new https.Agent({ keepAlive });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.httpAgent = new http.Agent({ keepAlive });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
HttpProvider.prototype._prepareRequest = function () {
|
|
||||||
var request;
|
|
||||||
// the current runtime is a browser
|
|
||||||
if (typeof XMLHttpRequest !== 'undefined') {
|
|
||||||
request = new XMLHttpRequest();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
request = new XHR2();
|
|
||||||
var agents = { httpsAgent: this.httpsAgent, httpAgent: this.httpAgent, baseUrl: this.baseUrl };
|
|
||||||
if (this.agent) {
|
|
||||||
agents.httpsAgent = this.agent.https;
|
|
||||||
agents.httpAgent = this.agent.http;
|
|
||||||
agents.baseUrl = this.agent.baseUrl;
|
|
||||||
}
|
|
||||||
request.nodejsSet(agents);
|
|
||||||
}
|
|
||||||
request.open('POST', this.host, true);
|
|
||||||
request.setRequestHeader('Content-Type', 'application/json');
|
|
||||||
request.timeout = this.timeout;
|
|
||||||
request.withCredentials = this.withCredentials;
|
|
||||||
if (this.headers) {
|
|
||||||
this.headers.forEach(function (header) {
|
|
||||||
request.setRequestHeader(header.name, header.value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return request;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Should be used to make async request
|
|
||||||
*
|
|
||||||
* @method send
|
|
||||||
* @param {Object} payload
|
|
||||||
* @param {Function} callback triggered on end with (err, result)
|
|
||||||
*/
|
|
||||||
HttpProvider.prototype.send = function (payload, callback) {
|
|
||||||
var _this = this;
|
|
||||||
var request = this._prepareRequest();
|
|
||||||
request.onreadystatechange = function () {
|
|
||||||
if (request.readyState === 4 && request.timeout !== 1) {
|
|
||||||
var result = request.responseText;
|
|
||||||
var error = null;
|
|
||||||
try {
|
|
||||||
result = JSON.parse(result);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
error = errors.InvalidResponse(request.responseText);
|
|
||||||
}
|
|
||||||
_this.connected = true;
|
|
||||||
callback(error, result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request.ontimeout = function () {
|
|
||||||
_this.connected = false;
|
|
||||||
callback(errors.ConnectionTimeout(this.timeout));
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
request.send(JSON.stringify(payload));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
this.connected = false;
|
|
||||||
callback(errors.InvalidConnection(this.host));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
HttpProvider.prototype.disconnect = function () {
|
|
||||||
//NO OP
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Returns the desired boolean.
|
|
||||||
*
|
|
||||||
* @method supportsSubscriptions
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
HttpProvider.prototype.supportsSubscriptions = function () {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
module.exports = HttpProvider;
|
|
@ -1,4 +0,0 @@
|
|||||||
node_modules
|
|
||||||
yarn-error.log
|
|
||||||
.idea
|
|
||||||
!wallaby.js
|
|
@ -1,4 +0,0 @@
|
|||||||
*
|
|
||||||
.idea
|
|
||||||
!dist/*
|
|
||||||
!package.json
|
|
@ -1,30 +0,0 @@
|
|||||||
# XMLHttpRequest polyfill for node.js
|
|
||||||
|
|
||||||
Based on [https://github.com/pwnall/node-xhr2/tree/bd6d48431ad93c8073811e5d4b77394dd637a85a](https://github.com/pwnall/node-xhr2/tree/bd6d48431ad93c8073811e5d4b77394dd637a85a)
|
|
||||||
|
|
||||||
* Adds support for cookies
|
|
||||||
* Adds in-project TypeScript type definitions
|
|
||||||
* Switched to TypeScript
|
|
||||||
|
|
||||||
### Cookies
|
|
||||||
|
|
||||||
* saved in `XMLHttpRequest.cookieJar`
|
|
||||||
* saved between redirects
|
|
||||||
* saved between requests
|
|
||||||
* can be cleared by doing:
|
|
||||||
```typescript
|
|
||||||
import * as Cookie from 'cookiejar';
|
|
||||||
XMLHttpRequest.cookieJar = Cookie.CookieJar();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Aims
|
|
||||||
|
|
||||||
* Provide full XMLHttpRequest features to Angular Universal HttpClient &
|
|
||||||
`node-angular-http-client`
|
|
||||||
|
|
||||||
### Changelog
|
|
||||||
|
|
||||||
#### `1.1.0`
|
|
||||||
* added saving of cookies between requests, not just redirects
|
|
||||||
* bug fixes
|
|
||||||
* most tests from `xhr2` ported over and passing
|
|
@ -1,8 +0,0 @@
|
|||||||
export declare class SecurityError extends Error {
|
|
||||||
}
|
|
||||||
export declare class InvalidStateError extends Error {
|
|
||||||
}
|
|
||||||
export declare class NetworkError extends Error {
|
|
||||||
}
|
|
||||||
export declare class SyntaxError extends Error {
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __extends = (this && this.__extends) || (function () {
|
|
||||||
var extendStatics = Object.setPrototypeOf ||
|
|
||||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
||||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
||||||
return function (d, b) {
|
|
||||||
extendStatics(d, b);
|
|
||||||
function __() { this.constructor = d; }
|
|
||||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
var SecurityError = /** @class */ (function (_super) {
|
|
||||||
__extends(SecurityError, _super);
|
|
||||||
function SecurityError() {
|
|
||||||
return _super !== null && _super.apply(this, arguments) || this;
|
|
||||||
}
|
|
||||||
return SecurityError;
|
|
||||||
}(Error));
|
|
||||||
exports.SecurityError = SecurityError;
|
|
||||||
var InvalidStateError = /** @class */ (function (_super) {
|
|
||||||
__extends(InvalidStateError, _super);
|
|
||||||
function InvalidStateError() {
|
|
||||||
return _super !== null && _super.apply(this, arguments) || this;
|
|
||||||
}
|
|
||||||
return InvalidStateError;
|
|
||||||
}(Error));
|
|
||||||
exports.InvalidStateError = InvalidStateError;
|
|
||||||
var NetworkError = /** @class */ (function (_super) {
|
|
||||||
__extends(NetworkError, _super);
|
|
||||||
function NetworkError() {
|
|
||||||
return _super !== null && _super.apply(this, arguments) || this;
|
|
||||||
}
|
|
||||||
return NetworkError;
|
|
||||||
}(Error));
|
|
||||||
exports.NetworkError = NetworkError;
|
|
||||||
var SyntaxError = /** @class */ (function (_super) {
|
|
||||||
__extends(SyntaxError, _super);
|
|
||||||
function SyntaxError() {
|
|
||||||
return _super !== null && _super.apply(this, arguments) || this;
|
|
||||||
}
|
|
||||||
return SyntaxError;
|
|
||||||
}(Error));
|
|
||||||
exports.SyntaxError = SyntaxError;
|
|
||||||
//# sourceMappingURL=errors.js.map
|
|
@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../errors.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;IAAmC,iCAAK;IAAxC;;IAA0C,CAAC;IAAD,oBAAC;AAAD,CAAC,AAA3C,CAAmC,KAAK,GAAG;AAA9B,sCAAa;AAC1B;IAAuC,qCAAK;IAA5C;;IAA8C,CAAC;IAAD,wBAAC;AAAD,CAAC,AAA/C,CAAuC,KAAK,GAAG;AAAlC,8CAAiB;AAC9B;IAAkC,gCAAK;IAAvC;;IAAyC,CAAC;IAAD,mBAAC;AAAD,CAAC,AAA1C,CAAkC,KAAK,GAAG;AAA7B,oCAAY;AACzB;IAAiC,+BAAK;IAAtC;;IAAwC,CAAC;IAAD,kBAAC;AAAD,CAAC,AAAzC,CAAiC,KAAK,GAAG;AAA5B,kCAAW"}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './xml-http-request';
|
|
||||||
export { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
@ -1,9 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
function __export(m) {
|
|
||||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
|
||||||
}
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
__export(require("./xml-http-request"));
|
|
||||||
var xml_http_request_event_target_1 = require("./xml-http-request-event-target");
|
|
||||||
exports.XMLHttpRequestEventTarget = xml_http_request_event_target_1.XMLHttpRequestEventTarget;
|
|
||||||
//# sourceMappingURL=index.js.map
|
|
@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;AAAA,wCAAmC;AACnC,iFAA4E;AAAnE,oEAAA,yBAAyB,CAAA"}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
||||||
export declare class ProgressEvent {
|
|
||||||
type: string;
|
|
||||||
bubbles: boolean;
|
|
||||||
cancelable: boolean;
|
|
||||||
target: XMLHttpRequestEventTarget;
|
|
||||||
loaded: number;
|
|
||||||
lengthComputable: boolean;
|
|
||||||
total: number;
|
|
||||||
constructor(type: string);
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
var ProgressEvent = /** @class */ (function () {
|
|
||||||
function ProgressEvent(type) {
|
|
||||||
this.type = type;
|
|
||||||
this.bubbles = false;
|
|
||||||
this.cancelable = false;
|
|
||||||
this.loaded = 0;
|
|
||||||
this.lengthComputable = false;
|
|
||||||
this.total = 0;
|
|
||||||
}
|
|
||||||
return ProgressEvent;
|
|
||||||
}());
|
|
||||||
exports.ProgressEvent = ProgressEvent;
|
|
||||||
//# sourceMappingURL=progress-event.js.map
|
|
@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"progress-event.js","sourceRoot":"","sources":["../progress-event.ts"],"names":[],"mappings":";;AAEA;IAQC,uBAAoB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QAPhC,YAAO,GAAG,KAAK,CAAC;QAChB,eAAU,GAAG,KAAK,CAAC;QAEnB,WAAM,GAAG,CAAC,CAAC;QACX,qBAAgB,GAAG,KAAK,CAAC;QACzB,UAAK,GAAG,CAAC,CAAC;IAEyB,CAAC;IACrC,oBAAC;AAAD,CAAC,AATD,IASC;AATY,sCAAa"}
|
|
19
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-event-target.d.ts
vendored
19
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-event-target.d.ts
vendored
@ -1,19 +0,0 @@
|
|||||||
import { ProgressEvent } from './progress-event';
|
|
||||||
export declare type ProgressEventListener = (event: ProgressEvent) => void;
|
|
||||||
export declare type ProgressEventListenerObject = {
|
|
||||||
handleEvent(event: ProgressEvent): void;
|
|
||||||
};
|
|
||||||
export declare type ProgressEventListenerOrEventListenerObject = ProgressEventListener | ProgressEventListenerObject;
|
|
||||||
export declare class XMLHttpRequestEventTarget {
|
|
||||||
onloadstart: ProgressEventListener | null;
|
|
||||||
onprogress: ProgressEventListener | null;
|
|
||||||
onabort: ProgressEventListener | null;
|
|
||||||
onerror: ProgressEventListener | null;
|
|
||||||
onload: ProgressEventListener | null;
|
|
||||||
ontimeout: ProgressEventListener | null;
|
|
||||||
onloadend: ProgressEventListener | null;
|
|
||||||
private listeners;
|
|
||||||
addEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject): void;
|
|
||||||
removeEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject): void;
|
|
||||||
dispatchEvent(event: ProgressEvent): boolean;
|
|
||||||
}
|
|
41
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-event-target.js
vendored
41
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-event-target.js
vendored
@ -1,41 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
var XMLHttpRequestEventTarget = /** @class */ (function () {
|
|
||||||
function XMLHttpRequestEventTarget() {
|
|
||||||
this.listeners = {};
|
|
||||||
}
|
|
||||||
XMLHttpRequestEventTarget.prototype.addEventListener = function (eventType, listener) {
|
|
||||||
eventType = eventType.toLowerCase();
|
|
||||||
this.listeners[eventType] = this.listeners[eventType] || [];
|
|
||||||
this.listeners[eventType].push(listener.handleEvent || listener);
|
|
||||||
};
|
|
||||||
XMLHttpRequestEventTarget.prototype.removeEventListener = function (eventType, listener) {
|
|
||||||
eventType = eventType.toLowerCase();
|
|
||||||
if (!this.listeners[eventType]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var index = this.listeners[eventType].indexOf(listener.handleEvent || listener);
|
|
||||||
if (index < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.listeners[eventType].splice(index, 1);
|
|
||||||
};
|
|
||||||
XMLHttpRequestEventTarget.prototype.dispatchEvent = function (event) {
|
|
||||||
var eventType = event.type.toLowerCase();
|
|
||||||
event.target = this; // TODO: set event.currentTarget?
|
|
||||||
if (this.listeners[eventType]) {
|
|
||||||
for (var _i = 0, _a = this.listeners[eventType]; _i < _a.length; _i++) {
|
|
||||||
var listener_1 = _a[_i];
|
|
||||||
listener_1.call(this, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var listener = this["on" + eventType];
|
|
||||||
if (listener) {
|
|
||||||
listener.call(this, event);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
return XMLHttpRequestEventTarget;
|
|
||||||
}());
|
|
||||||
exports.XMLHttpRequestEventTarget = XMLHttpRequestEventTarget;
|
|
||||||
//# sourceMappingURL=xml-http-request-event-target.js.map
|
|
@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"xml-http-request-event-target.js","sourceRoot":"","sources":["../xml-http-request-event-target.ts"],"names":[],"mappings":";;AAMA;IAAA;QASS,cAAS,GAAmD,EAAE,CAAC;IAiCxE,CAAC;IA/BA,oDAAgB,GAAhB,UAAiB,SAAiB,EAAE,QAAqD;QACxF,SAAS,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAE,QAAwC,CAAC,WAAW,IAAK,QAAkC,CAAC,CAAC;IAC9H,CAAC;IACD,uDAAmB,GAAnB,UAAoB,SAAiB,EAAE,QAAqD;QAC3F,SAAS,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACpC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM,CAAC;QAAC,CAAC;QAE3C,IAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAE,QAAwC,CAAC,WAAW,IAAK,QAAkC,CAAC,CAAC;QAC9I,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM,CAAC;QAAC,CAAC;QAE1B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,iDAAa,GAAb,UAAc,KAAoB;QACjC,IAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC3C,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,iCAAiC;QAEtD,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC/B,GAAG,CAAC,CAAiB,UAAyB,EAAzB,KAAA,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAzB,cAAyB,EAAzB,IAAyB;gBAAzC,IAAI,UAAQ,SAAA;gBAChB,UAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;aAC3B;QACF,CAAC;QAED,IAAM,QAAQ,GAAG,IAAI,CAAC,OAAK,SAAW,CAAC,CAAC;QACxC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;IACb,CAAC;IACF,gCAAC;AAAD,CAAC,AA1CD,IA0CC;AA1CY,8DAAyB"}
|
|
12
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.d.ts
vendored
12
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.d.ts
vendored
@ -1,12 +0,0 @@
|
|||||||
/// <reference types="node" />
|
|
||||||
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
||||||
import { ClientRequest } from 'http';
|
|
||||||
export declare class XMLHttpRequestUpload extends XMLHttpRequestEventTarget {
|
|
||||||
private _contentType;
|
|
||||||
private _body;
|
|
||||||
constructor();
|
|
||||||
_reset(): void;
|
|
||||||
_setData(data?: string | Buffer | ArrayBuffer | ArrayBufferView): void;
|
|
||||||
_finalizeHeaders(headers: object, loweredHeaders: object): void;
|
|
||||||
_startUpload(request: ClientRequest): void;
|
|
||||||
}
|
|
78
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.js
vendored
78
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.js
vendored
@ -1,78 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __extends = (this && this.__extends) || (function () {
|
|
||||||
var extendStatics = Object.setPrototypeOf ||
|
|
||||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
||||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
||||||
return function (d, b) {
|
|
||||||
extendStatics(d, b);
|
|
||||||
function __() { this.constructor = d; }
|
|
||||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
var xml_http_request_event_target_1 = require("./xml-http-request-event-target");
|
|
||||||
var XMLHttpRequestUpload = /** @class */ (function (_super) {
|
|
||||||
__extends(XMLHttpRequestUpload, _super);
|
|
||||||
function XMLHttpRequestUpload() {
|
|
||||||
var _this = _super.call(this) || this;
|
|
||||||
_this._contentType = null;
|
|
||||||
_this._body = null;
|
|
||||||
_this._reset();
|
|
||||||
return _this;
|
|
||||||
}
|
|
||||||
XMLHttpRequestUpload.prototype._reset = function () {
|
|
||||||
this._contentType = null;
|
|
||||||
this._body = null;
|
|
||||||
};
|
|
||||||
XMLHttpRequestUpload.prototype._setData = function (data) {
|
|
||||||
if (data == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
if (data.length !== 0) {
|
|
||||||
this._contentType = 'text/plain;charset=UTF-8';
|
|
||||||
}
|
|
||||||
this._body = Buffer.from(data, 'utf-8');
|
|
||||||
}
|
|
||||||
else if (Buffer.isBuffer(data)) {
|
|
||||||
this._body = data;
|
|
||||||
}
|
|
||||||
else if (data instanceof ArrayBuffer) {
|
|
||||||
var body = Buffer.alloc(data.byteLength);
|
|
||||||
var view = new Uint8Array(data);
|
|
||||||
for (var i = 0; i < data.byteLength; i++) {
|
|
||||||
body[i] = view[i];
|
|
||||||
}
|
|
||||||
this._body = body;
|
|
||||||
}
|
|
||||||
else if (data.buffer && data.buffer instanceof ArrayBuffer) {
|
|
||||||
var body = Buffer.alloc(data.byteLength);
|
|
||||||
var offset = data.byteOffset;
|
|
||||||
var view = new Uint8Array(data.buffer);
|
|
||||||
for (var i = 0; i < data.byteLength; i++) {
|
|
||||||
body[i] = view[i + offset];
|
|
||||||
}
|
|
||||||
this._body = body;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error("Unsupported send() data " + data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequestUpload.prototype._finalizeHeaders = function (headers, loweredHeaders) {
|
|
||||||
if (this._contentType && !loweredHeaders['content-type']) {
|
|
||||||
headers['Content-Type'] = this._contentType;
|
|
||||||
}
|
|
||||||
if (this._body) {
|
|
||||||
headers['Content-Length'] = this._body.length.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequestUpload.prototype._startUpload = function (request) {
|
|
||||||
if (this._body) {
|
|
||||||
request.write(this._body);
|
|
||||||
}
|
|
||||||
request.end();
|
|
||||||
};
|
|
||||||
return XMLHttpRequestUpload;
|
|
||||||
}(xml_http_request_event_target_1.XMLHttpRequestEventTarget));
|
|
||||||
exports.XMLHttpRequestUpload = XMLHttpRequestUpload;
|
|
||||||
//# sourceMappingURL=xml-http-request-upload.js.map
|
|
1
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.js.map
vendored
1
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.js.map
vendored
@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"xml-http-request-upload.js","sourceRoot":"","sources":["../xml-http-request-upload.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,iFAA4E;AAG5E;IAA0C,wCAAyB;IAIlE;QAAA,YACC,iBAAO,SAEP;QANO,kBAAY,GAAkB,IAAI,CAAC;QACnC,WAAK,GAAG,IAAI,CAAC;QAIpB,KAAI,CAAC,MAAM,EAAE,CAAC;;IACf,CAAC;IAED,qCAAM,GAAN;QACC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,uCAAQ,GAAR,UAAS,IAAsD;QAC9D,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;YAAC,MAAM,CAAC;QAAC,CAAC;QAE7B,EAAE,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC;YAC9B,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,CAAC,YAAY,GAAG,0BAA0B,CAAC;YAChD,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,YAAY,WAAW,CAAC,CAAC,CAAC;YACxC,IAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3C,IAAM,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;YAClC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;gBAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAChE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,YAAY,WAAW,CAAC,CAAC,CAAC;YAC9D,IAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3C,IAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;YAC/B,IAAM,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;gBAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;YAAC,CAAC;YACzE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;QAAC,IAAI,CAAC,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,6BAA2B,IAAM,CAAC,CAAC;QACpD,CAAC;IACF,CAAC;IAED,+CAAgB,GAAhB,UAAiB,OAAe,EAAE,cAAsB;QACvD,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;YAC1D,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;QAC7C,CAAC;QACD,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAChB,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC1D,CAAC;IACF,CAAC;IAED,2CAAY,GAAZ,UAAa,OAAsB;QAClC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;IACF,2BAAC;AAAD,CAAC,AArDD,CAA0C,yDAAyB,GAqDlE;AArDY,oDAAoB"}
|
|
102
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request.d.ts
vendored
102
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request.d.ts
vendored
@ -1,102 +0,0 @@
|
|||||||
/// <reference types="node" />
|
|
||||||
import { ProgressEvent } from './progress-event';
|
|
||||||
import { InvalidStateError, NetworkError, SecurityError, SyntaxError } from './errors';
|
|
||||||
import { ProgressEventListener, XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
||||||
import { XMLHttpRequestUpload } from './xml-http-request-upload';
|
|
||||||
import { Url } from 'url';
|
|
||||||
import { Agent as HttpAgent } from 'http';
|
|
||||||
import { Agent as HttpsAgent } from 'https';
|
|
||||||
export interface XMLHttpRequestOptions {
|
|
||||||
anon?: boolean;
|
|
||||||
}
|
|
||||||
export interface XHRUrl extends Url {
|
|
||||||
method?: string;
|
|
||||||
}
|
|
||||||
export declare class XMLHttpRequest extends XMLHttpRequestEventTarget {
|
|
||||||
static ProgressEvent: typeof ProgressEvent;
|
|
||||||
static InvalidStateError: typeof InvalidStateError;
|
|
||||||
static NetworkError: typeof NetworkError;
|
|
||||||
static SecurityError: typeof SecurityError;
|
|
||||||
static SyntaxError: typeof SyntaxError;
|
|
||||||
static XMLHttpRequestUpload: typeof XMLHttpRequestUpload;
|
|
||||||
static UNSENT: number;
|
|
||||||
static OPENED: number;
|
|
||||||
static HEADERS_RECEIVED: number;
|
|
||||||
static LOADING: number;
|
|
||||||
static DONE: number;
|
|
||||||
static cookieJar: any;
|
|
||||||
UNSENT: number;
|
|
||||||
OPENED: number;
|
|
||||||
HEADERS_RECEIVED: number;
|
|
||||||
LOADING: number;
|
|
||||||
DONE: number;
|
|
||||||
onreadystatechange: ProgressEventListener | null;
|
|
||||||
readyState: number;
|
|
||||||
response: string | ArrayBuffer | Buffer | object | null;
|
|
||||||
responseText: string;
|
|
||||||
responseType: string;
|
|
||||||
status: number;
|
|
||||||
statusText: string;
|
|
||||||
timeout: number;
|
|
||||||
upload: XMLHttpRequestUpload;
|
|
||||||
responseUrl: string;
|
|
||||||
withCredentials: boolean;
|
|
||||||
nodejsHttpAgent: HttpsAgent;
|
|
||||||
nodejsHttpsAgent: HttpsAgent;
|
|
||||||
nodejsBaseUrl: string | null;
|
|
||||||
private _anonymous;
|
|
||||||
private _method;
|
|
||||||
private _url;
|
|
||||||
private _sync;
|
|
||||||
private _headers;
|
|
||||||
private _loweredHeaders;
|
|
||||||
private _mimeOverride;
|
|
||||||
private _request;
|
|
||||||
private _response;
|
|
||||||
private _responseParts;
|
|
||||||
private _responseHeaders;
|
|
||||||
private _aborting;
|
|
||||||
private _error;
|
|
||||||
private _loadedBytes;
|
|
||||||
private _totalBytes;
|
|
||||||
private _lengthComputable;
|
|
||||||
private _restrictedMethods;
|
|
||||||
private _restrictedHeaders;
|
|
||||||
private _privateHeaders;
|
|
||||||
private _userAgent;
|
|
||||||
constructor(options?: XMLHttpRequestOptions);
|
|
||||||
open(method: string, url: string, async?: boolean, user?: string, password?: string): void;
|
|
||||||
setRequestHeader(name: string, value: any): void;
|
|
||||||
send(data?: string | Buffer | ArrayBuffer | ArrayBufferView): void;
|
|
||||||
abort(): void;
|
|
||||||
getResponseHeader(name: string): string;
|
|
||||||
getAllResponseHeaders(): string;
|
|
||||||
overrideMimeType(mimeType: string): void;
|
|
||||||
nodejsSet(options: {
|
|
||||||
httpAgent?: HttpAgent;
|
|
||||||
httpsAgent?: HttpsAgent;
|
|
||||||
baseUrl?: string;
|
|
||||||
}): void;
|
|
||||||
static nodejsSet(options: {
|
|
||||||
httpAgent?: HttpAgent;
|
|
||||||
httpsAgent?: HttpsAgent;
|
|
||||||
baseUrl?: string;
|
|
||||||
}): void;
|
|
||||||
private _setReadyState(readyState);
|
|
||||||
private _sendFile(data);
|
|
||||||
private _sendHttp(data?);
|
|
||||||
private _sendHxxpRequest();
|
|
||||||
private _finalizeHeaders();
|
|
||||||
private _onHttpResponse(request, response);
|
|
||||||
private _onHttpResponseData(response, data);
|
|
||||||
private _onHttpResponseEnd(response);
|
|
||||||
private _onHttpResponseClose(response);
|
|
||||||
private _onHttpTimeout(request);
|
|
||||||
private _onHttpRequestError(request, error);
|
|
||||||
private _dispatchProgress(eventType);
|
|
||||||
private _setError();
|
|
||||||
private _parseUrl(urlString, user?, password?);
|
|
||||||
private _parseResponseHeaders(response);
|
|
||||||
private _parseResponse();
|
|
||||||
private _parseResponseEncoding();
|
|
||||||
}
|
|
@ -1,448 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __extends = (this && this.__extends) || (function () {
|
|
||||||
var extendStatics = Object.setPrototypeOf ||
|
|
||||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
||||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
||||||
return function (d, b) {
|
|
||||||
extendStatics(d, b);
|
|
||||||
function __() { this.constructor = d; }
|
|
||||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
var __assign = (this && this.__assign) || Object.assign || function(t) {
|
|
||||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
||||||
s = arguments[i];
|
|
||||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
||||||
t[p] = s[p];
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
var http = require("http");
|
|
||||||
var https = require("https");
|
|
||||||
var url = require("url");
|
|
||||||
var progress_event_1 = require("./progress-event");
|
|
||||||
var errors_1 = require("./errors");
|
|
||||||
var xml_http_request_event_target_1 = require("./xml-http-request-event-target");
|
|
||||||
var xml_http_request_upload_1 = require("./xml-http-request-upload");
|
|
||||||
var Cookie = require("cookiejar");
|
|
||||||
var XMLHttpRequest = /** @class */ (function (_super) {
|
|
||||||
__extends(XMLHttpRequest, _super);
|
|
||||||
function XMLHttpRequest(options) {
|
|
||||||
if (options === void 0) { options = {}; }
|
|
||||||
var _this = _super.call(this) || this;
|
|
||||||
_this.UNSENT = XMLHttpRequest.UNSENT;
|
|
||||||
_this.OPENED = XMLHttpRequest.OPENED;
|
|
||||||
_this.HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED;
|
|
||||||
_this.LOADING = XMLHttpRequest.LOADING;
|
|
||||||
_this.DONE = XMLHttpRequest.DONE;
|
|
||||||
_this.onreadystatechange = null;
|
|
||||||
_this.readyState = XMLHttpRequest.UNSENT;
|
|
||||||
_this.response = null;
|
|
||||||
_this.responseText = '';
|
|
||||||
_this.responseType = '';
|
|
||||||
_this.status = 0; // TODO: UNSENT?
|
|
||||||
_this.statusText = '';
|
|
||||||
_this.timeout = 0;
|
|
||||||
_this.upload = new xml_http_request_upload_1.XMLHttpRequestUpload();
|
|
||||||
_this.responseUrl = '';
|
|
||||||
_this.withCredentials = false;
|
|
||||||
_this._method = null;
|
|
||||||
_this._url = null;
|
|
||||||
_this._sync = false;
|
|
||||||
_this._headers = {};
|
|
||||||
_this._loweredHeaders = {};
|
|
||||||
_this._mimeOverride = null; // TODO: is type right?
|
|
||||||
_this._request = null;
|
|
||||||
_this._response = null;
|
|
||||||
_this._responseParts = null;
|
|
||||||
_this._responseHeaders = null;
|
|
||||||
_this._aborting = null; // TODO: type?
|
|
||||||
_this._error = null; // TODO: type?
|
|
||||||
_this._loadedBytes = 0;
|
|
||||||
_this._totalBytes = 0;
|
|
||||||
_this._lengthComputable = false;
|
|
||||||
_this._restrictedMethods = { CONNECT: true, TRACE: true, TRACK: true };
|
|
||||||
_this._restrictedHeaders = {
|
|
||||||
'accept-charset': true,
|
|
||||||
'accept-encoding': true,
|
|
||||||
'access-control-request-headers': true,
|
|
||||||
'access-control-request-method': true,
|
|
||||||
connection: true,
|
|
||||||
'content-length': true,
|
|
||||||
cookie: true,
|
|
||||||
cookie2: true,
|
|
||||||
date: true,
|
|
||||||
dnt: true,
|
|
||||||
expect: true,
|
|
||||||
host: true,
|
|
||||||
'keep-alive': true,
|
|
||||||
origin: true,
|
|
||||||
referer: true,
|
|
||||||
te: true,
|
|
||||||
trailer: true,
|
|
||||||
'transfer-encoding': true,
|
|
||||||
upgrade: true,
|
|
||||||
'user-agent': true,
|
|
||||||
via: true
|
|
||||||
};
|
|
||||||
_this._privateHeaders = { 'set-cookie': true, 'set-cookie2': true };
|
|
||||||
//Redacted private information (${os.type()} ${os.arch()}) node.js/${process.versions.node} v8/${process.versions.v8} from the original version @ github
|
|
||||||
//Pretend to be tor-browser https://blog.torproject.org/browser-fingerprinting-introduction-and-challenges-ahead/
|
|
||||||
_this._userAgent = "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
|
|
||||||
_this._anonymous = options.anon || false;
|
|
||||||
return _this;
|
|
||||||
}
|
|
||||||
XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
|
|
||||||
if (async === void 0) { async = true; }
|
|
||||||
method = method.toUpperCase();
|
|
||||||
if (this._restrictedMethods[method]) {
|
|
||||||
throw new XMLHttpRequest.SecurityError("HTTP method " + method + " is not allowed in XHR");
|
|
||||||
}
|
|
||||||
;
|
|
||||||
var xhrUrl = this._parseUrl(url, user, password);
|
|
||||||
if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED || this.readyState === XMLHttpRequest.LOADING) {
|
|
||||||
// TODO(pwnall): terminate abort(), terminate send()
|
|
||||||
}
|
|
||||||
this._method = method;
|
|
||||||
this._url = xhrUrl;
|
|
||||||
this._sync = !async;
|
|
||||||
this._headers = {};
|
|
||||||
this._loweredHeaders = {};
|
|
||||||
this._mimeOverride = null;
|
|
||||||
this._setReadyState(XMLHttpRequest.OPENED);
|
|
||||||
this._request = null;
|
|
||||||
this._response = null;
|
|
||||||
this.status = 0;
|
|
||||||
this.statusText = '';
|
|
||||||
this._responseParts = [];
|
|
||||||
this._responseHeaders = null;
|
|
||||||
this._loadedBytes = 0;
|
|
||||||
this._totalBytes = 0;
|
|
||||||
this._lengthComputable = false;
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
|
|
||||||
if (this.readyState !== XMLHttpRequest.OPENED) {
|
|
||||||
throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED');
|
|
||||||
}
|
|
||||||
var loweredName = name.toLowerCase();
|
|
||||||
if (this._restrictedHeaders[loweredName] || /^sec-/.test(loweredName) || /^proxy-/.test(loweredName)) {
|
|
||||||
console.warn("Refused to set unsafe header \"" + name + "\"");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
value = value.toString();
|
|
||||||
if (this._loweredHeaders[loweredName] != null) {
|
|
||||||
name = this._loweredHeaders[loweredName];
|
|
||||||
this._headers[name] = this._headers[name] + ", " + value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._loweredHeaders[loweredName] = name;
|
|
||||||
this._headers[name] = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.send = function (data) {
|
|
||||||
if (this.readyState !== XMLHttpRequest.OPENED) {
|
|
||||||
throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED');
|
|
||||||
}
|
|
||||||
if (this._request) {
|
|
||||||
throw new XMLHttpRequest.InvalidStateError('send() already called');
|
|
||||||
}
|
|
||||||
switch (this._url.protocol) {
|
|
||||||
case 'file:':
|
|
||||||
return this._sendFile(data);
|
|
||||||
case 'http:':
|
|
||||||
case 'https:':
|
|
||||||
return this._sendHttp(data);
|
|
||||||
default:
|
|
||||||
throw new XMLHttpRequest.NetworkError("Unsupported protocol " + this._url.protocol);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.abort = function () {
|
|
||||||
if (this._request == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._request.abort();
|
|
||||||
this._setError();
|
|
||||||
this._dispatchProgress('abort');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.getResponseHeader = function (name) {
|
|
||||||
if (this._responseHeaders == null || name == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var loweredName = name.toLowerCase();
|
|
||||||
return this._responseHeaders.hasOwnProperty(loweredName)
|
|
||||||
? this._responseHeaders[name.toLowerCase()]
|
|
||||||
: null;
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.getAllResponseHeaders = function () {
|
|
||||||
var _this = this;
|
|
||||||
if (this._responseHeaders == null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return Object.keys(this._responseHeaders).map(function (key) { return key + ": " + _this._responseHeaders[key]; }).join('\r\n');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.overrideMimeType = function (mimeType) {
|
|
||||||
if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) {
|
|
||||||
throw new XMLHttpRequest.InvalidStateError('overrideMimeType() not allowed in LOADING or DONE');
|
|
||||||
}
|
|
||||||
this._mimeOverride = mimeType.toLowerCase();
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype.nodejsSet = function (options) {
|
|
||||||
this.nodejsHttpAgent = options.httpAgent || this.nodejsHttpAgent;
|
|
||||||
this.nodejsHttpsAgent = options.httpsAgent || this.nodejsHttpsAgent;
|
|
||||||
if (options.hasOwnProperty('baseUrl')) {
|
|
||||||
if (options.baseUrl != null) {
|
|
||||||
var parsedUrl = url.parse(options.baseUrl, false, true);
|
|
||||||
if (!parsedUrl.protocol) {
|
|
||||||
throw new XMLHttpRequest.SyntaxError("baseUrl must be an absolute URL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.nodejsBaseUrl = options.baseUrl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequest.nodejsSet = function (options) {
|
|
||||||
XMLHttpRequest.prototype.nodejsSet(options);
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._setReadyState = function (readyState) {
|
|
||||||
this.readyState = readyState;
|
|
||||||
this.dispatchEvent(new progress_event_1.ProgressEvent('readystatechange'));
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._sendFile = function (data) {
|
|
||||||
// TODO
|
|
||||||
throw new Error('Protocol file: not implemented');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._sendHttp = function (data) {
|
|
||||||
if (this._sync) {
|
|
||||||
throw new Error('Synchronous XHR processing not implemented');
|
|
||||||
}
|
|
||||||
if (data && (this._method === 'GET' || this._method === 'HEAD')) {
|
|
||||||
console.warn("Discarding entity body for " + this._method + " requests");
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data = data || '';
|
|
||||||
}
|
|
||||||
this.upload._setData(data);
|
|
||||||
this._finalizeHeaders();
|
|
||||||
this._sendHxxpRequest();
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._sendHxxpRequest = function () {
|
|
||||||
var _this = this;
|
|
||||||
if (this.withCredentials) {
|
|
||||||
var cookie = XMLHttpRequest.cookieJar
|
|
||||||
.getCookies(Cookie.CookieAccessInfo(this._url.hostname, this._url.pathname, this._url.protocol === 'https:')).toValueString();
|
|
||||||
this._headers.cookie = this._headers.cookie2 = cookie;
|
|
||||||
}
|
|
||||||
var _a = this._url.protocol === 'http:' ? [http, this.nodejsHttpAgent] : [https, this.nodejsHttpsAgent], hxxp = _a[0], agent = _a[1];
|
|
||||||
var requestMethod = hxxp.request.bind(hxxp);
|
|
||||||
var request = requestMethod({
|
|
||||||
hostname: this._url.hostname,
|
|
||||||
port: +this._url.port,
|
|
||||||
path: this._url.path,
|
|
||||||
auth: this._url.auth,
|
|
||||||
method: this._method,
|
|
||||||
headers: this._headers,
|
|
||||||
agent: agent
|
|
||||||
});
|
|
||||||
this._request = request;
|
|
||||||
if (this.timeout) {
|
|
||||||
request.setTimeout(this.timeout, function () { return _this._onHttpTimeout(request); });
|
|
||||||
}
|
|
||||||
request.on('response', function (response) { return _this._onHttpResponse(request, response); });
|
|
||||||
request.on('error', function (error) { return _this._onHttpRequestError(request, error); });
|
|
||||||
this.upload._startUpload(request);
|
|
||||||
if (this._request === request) {
|
|
||||||
this._dispatchProgress('loadstart');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._finalizeHeaders = function () {
|
|
||||||
this._headers = __assign({}, this._headers, { Connection: 'keep-alive', Host: this._url.host, 'User-Agent': this._userAgent }, this._anonymous ? { Referer: 'about:blank' } : {});
|
|
||||||
this.upload._finalizeHeaders(this._headers, this._loweredHeaders);
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._onHttpResponse = function (request, response) {
|
|
||||||
var _this = this;
|
|
||||||
if (this._request !== request) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.withCredentials && (response.headers['set-cookie'] || response.headers['set-cookie2'])) {
|
|
||||||
XMLHttpRequest.cookieJar
|
|
||||||
.setCookies(response.headers['set-cookie'] || response.headers['set-cookie2']);
|
|
||||||
}
|
|
||||||
if ([301, 302, 303, 307, 308].indexOf(response.statusCode) >= 0) {
|
|
||||||
this._url = this._parseUrl(response.headers.location);
|
|
||||||
this._method = 'GET';
|
|
||||||
if (this._loweredHeaders['content-type']) {
|
|
||||||
delete this._headers[this._loweredHeaders['content-type']];
|
|
||||||
delete this._loweredHeaders['content-type'];
|
|
||||||
}
|
|
||||||
if (this._headers['Content-Type'] != null) {
|
|
||||||
delete this._headers['Content-Type'];
|
|
||||||
}
|
|
||||||
delete this._headers['Content-Length'];
|
|
||||||
this.upload._reset();
|
|
||||||
this._finalizeHeaders();
|
|
||||||
this._sendHxxpRequest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._response = response;
|
|
||||||
this._response.on('data', function (data) { return _this._onHttpResponseData(response, data); });
|
|
||||||
this._response.on('end', function () { return _this._onHttpResponseEnd(response); });
|
|
||||||
this._response.on('close', function () { return _this._onHttpResponseClose(response); });
|
|
||||||
this.responseUrl = this._url.href.split('#')[0];
|
|
||||||
this.status = response.statusCode;
|
|
||||||
this.statusText = http.STATUS_CODES[this.status];
|
|
||||||
this._parseResponseHeaders(response);
|
|
||||||
var lengthString = this._responseHeaders['content-length'] || '';
|
|
||||||
this._totalBytes = +lengthString;
|
|
||||||
this._lengthComputable = !!lengthString;
|
|
||||||
this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._onHttpResponseData = function (response, data) {
|
|
||||||
if (this._response !== response) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._responseParts.push(Buffer.from(data));
|
|
||||||
this._loadedBytes += data.length;
|
|
||||||
if (this.readyState !== XMLHttpRequest.LOADING) {
|
|
||||||
this._setReadyState(XMLHttpRequest.LOADING);
|
|
||||||
}
|
|
||||||
this._dispatchProgress('progress');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._onHttpResponseEnd = function (response) {
|
|
||||||
if (this._response !== response) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._parseResponse();
|
|
||||||
this._request = null;
|
|
||||||
this._response = null;
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
this._dispatchProgress('load');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._onHttpResponseClose = function (response) {
|
|
||||||
if (this._response !== response) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var request = this._request;
|
|
||||||
this._setError();
|
|
||||||
request.abort();
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
this._dispatchProgress('error');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._onHttpTimeout = function (request) {
|
|
||||||
if (this._request !== request) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._setError();
|
|
||||||
request.abort();
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
this._dispatchProgress('timeout');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._onHttpRequestError = function (request, error) {
|
|
||||||
if (this._request !== request) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._setError();
|
|
||||||
request.abort();
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
this._dispatchProgress('error');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._dispatchProgress = function (eventType) {
|
|
||||||
var event = new XMLHttpRequest.ProgressEvent(eventType);
|
|
||||||
event.lengthComputable = this._lengthComputable;
|
|
||||||
event.loaded = this._loadedBytes;
|
|
||||||
event.total = this._totalBytes;
|
|
||||||
this.dispatchEvent(event);
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._setError = function () {
|
|
||||||
this._request = null;
|
|
||||||
this._response = null;
|
|
||||||
this._responseHeaders = null;
|
|
||||||
this._responseParts = null;
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._parseUrl = function (urlString, user, password) {
|
|
||||||
var absoluteUrl = this.nodejsBaseUrl == null ? urlString : url.resolve(this.nodejsBaseUrl, urlString);
|
|
||||||
var xhrUrl = url.parse(absoluteUrl, false, true);
|
|
||||||
xhrUrl.hash = null;
|
|
||||||
var _a = (xhrUrl.auth || '').split(':'), xhrUser = _a[0], xhrPassword = _a[1];
|
|
||||||
if (xhrUser || xhrPassword || user || password) {
|
|
||||||
xhrUrl.auth = (user || xhrUser || '') + ":" + (password || xhrPassword || '');
|
|
||||||
}
|
|
||||||
return xhrUrl;
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._parseResponseHeaders = function (response) {
|
|
||||||
this._responseHeaders = {};
|
|
||||||
for (var name_1 in response.headers) {
|
|
||||||
var loweredName = name_1.toLowerCase();
|
|
||||||
if (this._privateHeaders[loweredName]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
this._responseHeaders[loweredName] = response.headers[name_1];
|
|
||||||
}
|
|
||||||
if (this._mimeOverride != null) {
|
|
||||||
this._responseHeaders['content-type'] = this._mimeOverride;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._parseResponse = function () {
|
|
||||||
var buffer = Buffer.concat(this._responseParts);
|
|
||||||
this._responseParts = null;
|
|
||||||
switch (this.responseType) {
|
|
||||||
case 'json':
|
|
||||||
this.responseText = null;
|
|
||||||
try {
|
|
||||||
this.response = JSON.parse(buffer.toString('utf-8'));
|
|
||||||
}
|
|
||||||
catch (_a) {
|
|
||||||
this.response = null;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case 'buffer':
|
|
||||||
this.responseText = null;
|
|
||||||
this.response = buffer;
|
|
||||||
return;
|
|
||||||
case 'arraybuffer':
|
|
||||||
this.responseText = null;
|
|
||||||
var arrayBuffer = new ArrayBuffer(buffer.length);
|
|
||||||
var view = new Uint8Array(arrayBuffer);
|
|
||||||
for (var i = 0; i < buffer.length; i++) {
|
|
||||||
view[i] = buffer[i];
|
|
||||||
}
|
|
||||||
this.response = arrayBuffer;
|
|
||||||
return;
|
|
||||||
case 'text':
|
|
||||||
default:
|
|
||||||
try {
|
|
||||||
this.responseText = buffer.toString(this._parseResponseEncoding());
|
|
||||||
}
|
|
||||||
catch (_b) {
|
|
||||||
this.responseText = buffer.toString('binary');
|
|
||||||
}
|
|
||||||
this.response = this.responseText;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XMLHttpRequest.prototype._parseResponseEncoding = function () {
|
|
||||||
return /;\s*charset=(.*)$/.exec(this._responseHeaders['content-type'] || '')[1] || 'utf-8';
|
|
||||||
};
|
|
||||||
XMLHttpRequest.ProgressEvent = progress_event_1.ProgressEvent;
|
|
||||||
XMLHttpRequest.InvalidStateError = errors_1.InvalidStateError;
|
|
||||||
XMLHttpRequest.NetworkError = errors_1.NetworkError;
|
|
||||||
XMLHttpRequest.SecurityError = errors_1.SecurityError;
|
|
||||||
XMLHttpRequest.SyntaxError = errors_1.SyntaxError;
|
|
||||||
XMLHttpRequest.XMLHttpRequestUpload = xml_http_request_upload_1.XMLHttpRequestUpload;
|
|
||||||
XMLHttpRequest.UNSENT = 0;
|
|
||||||
XMLHttpRequest.OPENED = 1;
|
|
||||||
XMLHttpRequest.HEADERS_RECEIVED = 2;
|
|
||||||
XMLHttpRequest.LOADING = 3;
|
|
||||||
XMLHttpRequest.DONE = 4;
|
|
||||||
XMLHttpRequest.cookieJar = Cookie.CookieJar();
|
|
||||||
return XMLHttpRequest;
|
|
||||||
}(xml_http_request_event_target_1.XMLHttpRequestEventTarget));
|
|
||||||
exports.XMLHttpRequest = XMLHttpRequest;
|
|
||||||
XMLHttpRequest.prototype.nodejsHttpAgent = http.globalAgent;
|
|
||||||
XMLHttpRequest.prototype.nodejsHttpsAgent = https.globalAgent;
|
|
||||||
XMLHttpRequest.prototype.nodejsBaseUrl = null;
|
|
||||||
//# sourceMappingURL=xml-http-request.js.map
|
|
1
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request.js.map
vendored
1
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request.js.map
vendored
File diff suppressed because one or more lines are too long
@ -1,4 +0,0 @@
|
|||||||
export class SecurityError extends Error {}
|
|
||||||
export class InvalidStateError extends Error {}
|
|
||||||
export class NetworkError extends Error {}
|
|
||||||
export class SyntaxError extends Error {}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './xml-http-request';
|
|
||||||
export { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "xhr2-cookies",
|
|
||||||
"version": "1.1.0",
|
|
||||||
"author": "Ionut Costica <ionut.costica@gmail.com>",
|
|
||||||
"license": "MIT",
|
|
||||||
"description": "XMLHttpRequest polyfill for node.js",
|
|
||||||
"repository": "git://github.com/souldreamer/xhr2-cookies.git",
|
|
||||||
"keywords": [
|
|
||||||
"XMLHttpRequest",
|
|
||||||
"cookies",
|
|
||||||
"xhr2"
|
|
||||||
],
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"dependencies": {
|
|
||||||
"cookiejar": "^2.1.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/body-parser": "^1.16.8",
|
|
||||||
"@types/cookie-parser": "^1.4.1",
|
|
||||||
"@types/express": "^4.0.39",
|
|
||||||
"@types/morgan": "^1.7.35",
|
|
||||||
"@types/node": "^6",
|
|
||||||
"ava": "^0.23.0",
|
|
||||||
"ava-ts": "^0.23.0",
|
|
||||||
"body-parser": "^1.18.2",
|
|
||||||
"cookie-parser": "^1.4.3",
|
|
||||||
"express": "^4.16.2",
|
|
||||||
"morgan": "^1.9.0",
|
|
||||||
"ts-loader": "^2.3.4",
|
|
||||||
"ts-node": "^3.3.0",
|
|
||||||
"typescript": "^2.5.2",
|
|
||||||
"webpack": "^3.5.5"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"prepare": "tsc",
|
|
||||||
"test": "tsc -p ./test && ava-ts -v"
|
|
||||||
},
|
|
||||||
"ava": {
|
|
||||||
"files": [
|
|
||||||
"test/*.spec.ts"
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"*.ts",
|
|
||||||
"!dist/**/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
||||||
|
|
||||||
export class ProgressEvent {
|
|
||||||
bubbles = false;
|
|
||||||
cancelable = false;
|
|
||||||
target: XMLHttpRequestEventTarget;
|
|
||||||
loaded = 0;
|
|
||||||
lengthComputable = false;
|
|
||||||
total = 0;
|
|
||||||
|
|
||||||
constructor (public type: string) {}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
import * as Cookie from 'cookiejar';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
XMLHttpRequest.cookieJar = Cookie.CookieJar();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest sets cookies and passes them on on redirect', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.plan(1);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect-cookie/test/works`);
|
|
||||||
xhr.withCredentials = true;
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.responseText, 'works');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest sets cookies and uses them for subsequent calls', async t => {
|
|
||||||
let xhr = t.context.xhr;
|
|
||||||
t.plan(1);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/set-cookie/second-test/works`);
|
|
||||||
xhr.withCredentials = true;
|
|
||||||
xhr.onload = resolve;
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
xhr = new XMLHttpRequest();
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/print-cookie/second-test`);
|
|
||||||
xhr.withCredentials = true;
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.responseText, 'works');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,101 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { ProgressEvent } from '../progress-event';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest(),
|
|
||||||
loadEvent: new ProgressEvent('load')
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
t.context.loadEvent = new ProgressEvent('load');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget dispatchEvent works with a DOM0 listener', t => {
|
|
||||||
t.plan(1);
|
|
||||||
t.context.xhr.onload = () => t.pass();
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget dispatchEvent works with a DOM2 listener', t => {
|
|
||||||
t.plan(1);
|
|
||||||
t.context.xhr.addEventListener('load', () => t.pass());
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget dispatchEvent executes DOM2 listeners in order', t => {
|
|
||||||
t.plan(1);
|
|
||||||
let firstExecuted = false;
|
|
||||||
t.context.xhr.addEventListener('load', () => firstExecuted = true);
|
|
||||||
t.context.xhr.addEventListener('load', () => {
|
|
||||||
if (firstExecuted) { t.pass(); }
|
|
||||||
});
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget removes a DOM2 listener correctly', t => {
|
|
||||||
t.plan(1);
|
|
||||||
const listener = () => t.pass();
|
|
||||||
t.context.xhr.addEventListener('load', listener);
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
t.context.xhr.removeEventListener('load', listener);
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget binds this correctly in a DOM0 listener', t => {
|
|
||||||
t.plan(1);
|
|
||||||
t.context.xhr.onload = function () { if (this === t.context.xhr) { t.pass(); } };
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget binds this correctly in a DOM2 listener', t => {
|
|
||||||
t.plan(1);
|
|
||||||
t.context.xhr.addEventListener('load', function () { if (this === t.context.xhr) { t.pass(); } });
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget sets target correctly in a DOM0 listener', t => {
|
|
||||||
t.plan(1);
|
|
||||||
t.context.xhr.onload = function (event) { if (event.target === t.context.xhr) { t.pass(); } };
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget sets target correctly in a DOM2 listener', t => {
|
|
||||||
t.plan(1);
|
|
||||||
t.context.xhr.addEventListener('load', function (event) { if (event.target === t.context.xhr) { t.pass(); } });
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget works with a DOM0 and two DOM2 listeners', t => {
|
|
||||||
t.plan(3);
|
|
||||||
t.context.xhr.addEventListener('load', () => t.pass());
|
|
||||||
t.context.xhr.onload = () => t.pass();
|
|
||||||
t.context.xhr.addEventListener('load', () => t.pass());
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget does not invoke a DOM0 listener for a different event', t => {
|
|
||||||
t.plan(0);
|
|
||||||
['onerror', 'onloadstart', 'onprogress', 'onabort', 'ontimeout', 'onloadend']
|
|
||||||
.forEach(eventType => t.context.xhr[eventType] = () => t.pass());
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequestEventTarget does not invoke a DOM2 listener for a different event', t => {
|
|
||||||
t.plan(0);
|
|
||||||
['error', 'loadstart', 'progress', 'abort', 'timeout', 'loadend']
|
|
||||||
.forEach(eventType => t.context.xhr.addEventListener(eventType, () => t.pass()));
|
|
||||||
t.context.xhr.dispatchEvent(t.context.loadEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// * remove event listener from an event that had no listeners
|
|
||||||
// * remove non-existent event listener from an event that had listeners
|
|
@ -1,249 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest(),
|
|
||||||
dripUrl: `http://localhost:${HttpServer.port}/_/drip`,
|
|
||||||
dripJson: {drips: 3, size: 1000, ms: 50, length: true},
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
|
|
||||||
XMLHttpRequest.nodejsSet({
|
|
||||||
baseUrl: HttpServer.testUrl().replace('https://', 'http://')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('level 2 events for a successful fetch with Content-Length set', async t => {
|
|
||||||
let endFired = false;
|
|
||||||
let intermediateProgressFired = false;
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
['loadstart', 'progress', 'load', 'loadend', 'error', 'abort'].forEach(addCheckedEvent);
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
endFired = true;
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.addEventListener('error', () => resolve());
|
|
||||||
|
|
||||||
xhr.open('POST', t.context.dripUrl);
|
|
||||||
xhr.send(JSON.stringify(t.context.dripJson));
|
|
||||||
});
|
|
||||||
|
|
||||||
t.true(intermediateProgressFired, 'at least one intermediate progress event was fired');
|
|
||||||
|
|
||||||
function addCheckedEvent(eventType: string) {
|
|
||||||
xhr.addEventListener(eventType, event => {
|
|
||||||
t.is(event.type, eventType, `event type is ${eventType}`);
|
|
||||||
t.is(event.target, xhr, 'event has correct target');
|
|
||||||
t.false(endFired, 'end is not fired');
|
|
||||||
t.false(event.bubbles, 'event does not bubble');
|
|
||||||
t.false(event.cancelable, 'event is not cancelable');
|
|
||||||
|
|
||||||
switch (eventType) {
|
|
||||||
case 'loadstart':
|
|
||||||
t.is(event.loaded, 0, 'on loadstart loaded = 0');
|
|
||||||
t.false(event.lengthComputable, 'on loadstart length is not computable');
|
|
||||||
t.is(event.total, 0, 'on loadstart event total is 0');
|
|
||||||
break;
|
|
||||||
case 'load':
|
|
||||||
case 'loadend':
|
|
||||||
t.is(event.loaded, 3000, 'on load/loadend loaded = 3000');
|
|
||||||
t.true(event.lengthComputable, 'on load/loadend length is computable');
|
|
||||||
t.is(event.total, 3000, 'on load/loadend event total is 0');
|
|
||||||
break;
|
|
||||||
case 'progress':
|
|
||||||
t.true(event.loaded >= 0, 'on progress: loaded >= 0');
|
|
||||||
t.true(event.loaded <= 3000, 'on progress: loaded <= 3000');
|
|
||||||
if (event.lengthComputable) {
|
|
||||||
t.is(event.total, 3000, 'on progress event when length is computable total is 3000');
|
|
||||||
} else {
|
|
||||||
t.is(event.total, 0, 'on progress event when length is not computable total is 0');
|
|
||||||
}
|
|
||||||
if (event.loaded > 0 && event.loaded < 3000) { intermediateProgressFired = true; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('level 2 events for a successful fetch without Content-Length set', async t => {
|
|
||||||
let endFired = false;
|
|
||||||
let intermediateProgressFired = false;
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.context.dripJson = {...t.context.dripJson, length: false};
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
['loadstart', 'progress', 'load', 'loadend', 'error', 'abort'].forEach(addCheckedEvent);
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
endFired = true;
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.open('POST', t.context.dripUrl);
|
|
||||||
xhr.send(JSON.stringify(t.context.dripJson));
|
|
||||||
});
|
|
||||||
|
|
||||||
t.true(intermediateProgressFired, 'at least one intermediate progress event was fired');
|
|
||||||
|
|
||||||
function addCheckedEvent(eventType: string) {
|
|
||||||
xhr.addEventListener(eventType, event => {
|
|
||||||
t.is(event.type, eventType, `event type is ${eventType}`);
|
|
||||||
t.is(event.target, xhr, 'event has correct target');
|
|
||||||
t.false(endFired, 'end is not fired');
|
|
||||||
t.false(event.bubbles, 'event does not bubble');
|
|
||||||
t.false(event.cancelable, 'event is not cancelable');
|
|
||||||
t.false(event.lengthComputable, 'length is not computable');
|
|
||||||
t.is(event.total, 0, 'when length is not computable total is 0');
|
|
||||||
|
|
||||||
switch (eventType) {
|
|
||||||
case 'loadstart':
|
|
||||||
t.is(event.loaded, 0, 'on loadstart loaded = 0');
|
|
||||||
break;
|
|
||||||
case 'load':
|
|
||||||
case 'loadend':
|
|
||||||
t.is(event.loaded, 3000, 'on load/loadend loaded = 3000');
|
|
||||||
break;
|
|
||||||
case 'progress':
|
|
||||||
t.true(event.loaded >= 0, 'on progress: loaded >= 0');
|
|
||||||
t.true(event.loaded <= 3000, 'on progress: loaded <= 3000');
|
|
||||||
if (event.loaded > 0 && event.loaded < 3000) { intermediateProgressFired = true; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('level 2 events for a network error due to bad DNS', async t => {
|
|
||||||
let errorFired = false;
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
['loadstart', 'progress', 'load', 'loadend', 'error', 'abort'].forEach(addCheckedEvent);
|
|
||||||
xhr.addEventListener('loadend', () => resolve());
|
|
||||||
|
|
||||||
xhr.open('GET', 'https://broken.to.cause.an.xhrnetworkerror.com.a.com');
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
|
|
||||||
t.true(errorFired, 'an error event was fired');
|
|
||||||
|
|
||||||
function addCheckedEvent(eventType: string) {
|
|
||||||
xhr.addEventListener(eventType, () => {
|
|
||||||
switch (eventType) {
|
|
||||||
case 'load':
|
|
||||||
case 'progress':
|
|
||||||
t.fail();
|
|
||||||
break;
|
|
||||||
case 'error':
|
|
||||||
errorFired = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('readystatechange for a successful fetch with Content-Length set', async t => {
|
|
||||||
let doneFired = false;
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
const states = [];
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('readystatechange', event => {
|
|
||||||
t.is(event.type, 'readystatechange', 'event type is correct');
|
|
||||||
t.false(doneFired, 'no readystatechange events after DONE');
|
|
||||||
t.is(event.target, xhr, 'event has correct target');
|
|
||||||
t.false(event.bubbles, 'event does not bubble');
|
|
||||||
t.false(event.cancelable, 'event is not cancelable');
|
|
||||||
|
|
||||||
states.push((event.target as XMLHttpRequest).readyState);
|
|
||||||
if ((event.target as XMLHttpRequest).readyState === XMLHttpRequest.DONE) {
|
|
||||||
doneFired = true;
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.open('POST', t.context.dripUrl);
|
|
||||||
xhr.send(JSON.stringify(t.context.dripJson));
|
|
||||||
});
|
|
||||||
|
|
||||||
t.deepEqual(states, [
|
|
||||||
XMLHttpRequest.OPENED,
|
|
||||||
XMLHttpRequest.HEADERS_RECEIVED,
|
|
||||||
XMLHttpRequest.LOADING,
|
|
||||||
XMLHttpRequest.DONE
|
|
||||||
], 'right order of ready states');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('readystatechange for a successful fetch without Content-Length set', async t => {
|
|
||||||
let doneFired = false;
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
const states = [];
|
|
||||||
t.context.dripJson = {...t.context.dripJson, length: false};
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('readystatechange', event => {
|
|
||||||
t.is(event.type, 'readystatechange', 'event type is correct');
|
|
||||||
t.false(doneFired, 'no readystatechange events after DONE');
|
|
||||||
t.is(event.target, xhr, 'event has correct target');
|
|
||||||
t.false(event.bubbles, 'event does not bubble');
|
|
||||||
t.false(event.cancelable, 'event is not cancelable');
|
|
||||||
t.false(event.lengthComputable, 'length is not computable');
|
|
||||||
t.is(event.total, 0, 'when length is not computable total is 0');
|
|
||||||
|
|
||||||
states.push((event.target as XMLHttpRequest).readyState);
|
|
||||||
if ((event.target as XMLHttpRequest).readyState === XMLHttpRequest.DONE) {
|
|
||||||
doneFired = true;
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.open('POST', t.context.dripUrl);
|
|
||||||
xhr.send(JSON.stringify(t.context.dripJson));
|
|
||||||
});
|
|
||||||
|
|
||||||
t.deepEqual(states, [
|
|
||||||
XMLHttpRequest.OPENED,
|
|
||||||
XMLHttpRequest.HEADERS_RECEIVED,
|
|
||||||
XMLHttpRequest.LOADING,
|
|
||||||
XMLHttpRequest.DONE
|
|
||||||
], 'right order of ready states');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('readystatechange for a network error due to bad DNS', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
const states = [];
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('readystatechange', event => {
|
|
||||||
t.is(event.type, 'readystatechange', 'event type is correct');
|
|
||||||
t.is(event.target, xhr, 'event has correct target');
|
|
||||||
t.false(event.bubbles, 'event does not bubble');
|
|
||||||
t.false(event.cancelable, 'event is not cancelable');
|
|
||||||
|
|
||||||
states.push((event.target as XMLHttpRequest).readyState);
|
|
||||||
if ((event.target as XMLHttpRequest).readyState === XMLHttpRequest.DONE) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.open('GET', 'https://broken.to.cause.an.xhrnetworkerror.com.a.com');
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
|
|
||||||
t.deepEqual(states, [
|
|
||||||
XMLHttpRequest.OPENED,
|
|
||||||
XMLHttpRequest.DONE
|
|
||||||
], 'right order of ready states');
|
|
||||||
});
|
|
Binary file not shown.
Before Width: | Height: | Size: 119 B |
@ -1,189 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
|
|
||||||
XMLHttpRequest.nodejsSet({
|
|
||||||
baseUrl: HttpServer.testUrl().replace('https://', 'http://')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#setRequestHeader with allowed headers should send the headers', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
|
|
||||||
xhr.responseType = 'text';
|
|
||||||
|
|
||||||
xhr.setRequestHeader('Authorization', 'lol');
|
|
||||||
xhr.setRequestHeader('X-Answer', '42');
|
|
||||||
xhr.setRequestHeader('X-Header-Name', 'value');
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.true(headers.hasOwnProperty('authorization'), 'headers have authorization header');
|
|
||||||
t.is(headers.authorization, 'lol', 'authorization header is correct');
|
|
||||||
t.true(headers.hasOwnProperty('x-answer'), 'headers have x-answer header');
|
|
||||||
t.is(headers['x-answer'], '42', 'x-answer header is correct');
|
|
||||||
t.true(headers.hasOwnProperty('x-header-name'), 'headers have x-header-name header');
|
|
||||||
t.is(headers['x-header-name'], 'value', 'x-header-name header is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#setRequestHeader with a mix of allowed and forbidden headers should only send the allowed headers', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
|
|
||||||
xhr.responseType = 'text';
|
|
||||||
|
|
||||||
xhr.setRequestHeader('Authorization', 'lol');
|
|
||||||
xhr.setRequestHeader('Proxy-Authorization', 'evil:kitten');
|
|
||||||
xhr.setRequestHeader('Sec-Breach', 'yes please');
|
|
||||||
xhr.setRequestHeader('Host', 'www.google.com');
|
|
||||||
xhr.setRequestHeader('Origin', 'https://www.google.com');
|
|
||||||
xhr.setRequestHeader('X-Answer', '42');
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.true(headers.hasOwnProperty('authorization'), 'headers have authorization header');
|
|
||||||
t.is(headers['authorization'], 'lol', 'authorization header is correct');
|
|
||||||
t.false(headers.hasOwnProperty('proxy-authorization'), 'headers do not have proxy-authorization header');
|
|
||||||
t.false(headers.hasOwnProperty('sec-breach'), 'headers do not have sec-breach header');
|
|
||||||
t.notRegex(headers['origin'] || '', /www\.google\.com/, 'header "origin" should not contain www.google.com');
|
|
||||||
t.notRegex(headers['host'] || '', /www\.google\.com/, 'header "host" should not contain www.google.com');
|
|
||||||
t.true(headers.hasOwnProperty('x-answer'), 'headers have x-answer header');
|
|
||||||
t.is(headers['x-answer'], '42', 'x-answer header is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#setRequestHeader with repeated headers should send all headers', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
|
|
||||||
xhr.responseType = 'text';
|
|
||||||
|
|
||||||
xhr.setRequestHeader('Authorization', 'troll');
|
|
||||||
xhr.setRequestHeader('Authorization', 'lol');
|
|
||||||
xhr.setRequestHeader('Authorization', 'lol');
|
|
||||||
xhr.setRequestHeader('X-Answer', '42');
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.true(headers.hasOwnProperty('authorization'), 'headers have authorization header');
|
|
||||||
t.is(headers['authorization'], 'troll, lol, lol', 'authorization header is correct');
|
|
||||||
t.true(headers.hasOwnProperty('x-answer'), 'headers have x-answer header');
|
|
||||||
t.is(headers['x-answer'], '42', 'x-answer header is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#setRequestHeader with no headers should set the protected headers correctly', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
|
|
||||||
xhr.responseType = 'text';
|
|
||||||
|
|
||||||
xhr.setRequestHeader('Authorization', 'troll');
|
|
||||||
xhr.setRequestHeader('Authorization', 'lol');
|
|
||||||
xhr.setRequestHeader('Authorization', 'lol');
|
|
||||||
xhr.setRequestHeader('X-Answer', '42');
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.true(headers.hasOwnProperty('connection'), 'headers have connection header');
|
|
||||||
t.is(headers['connection'], 'keep-alive', 'connection header is correct');
|
|
||||||
t.true(headers.hasOwnProperty('host'), 'headers have host header');
|
|
||||||
t.is(headers['host'], `localhost:${HttpServer.port}`, 'host header is correct');
|
|
||||||
t.true(headers.hasOwnProperty('user-agent'), 'headers have user-agent header');
|
|
||||||
t.regex(headers['user-agent'], /^Mozilla\//, 'user-agent header is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#getResponseHeader returns accessible headers, returns null for private headers, has headers on HEADERS_RECEIVED readyState', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/get-headers`);
|
|
||||||
const headerJson = `{
|
|
||||||
"Accept-Ranges": "bytes",
|
|
||||||
"Content-Type": "application/xhr2; charset=utf-1337",
|
|
||||||
"Set-Cookie": "UserID=JohnDoe; Max-Age=3600; Version=1",
|
|
||||||
"X-Header": "one, more, value"
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onloadend = () => {
|
|
||||||
t.is(xhr.getResponseHeader('AccEPt-RANgeS'), 'bytes', 'AccEPt-RANgeS works correctly');
|
|
||||||
t.is(xhr.getResponseHeader('content-Type'), 'application/xhr2; charset=utf-1337', 'content-Type works correctly');
|
|
||||||
t.is(xhr.getResponseHeader('X-Header'), 'one, more, value', 'X-Header works correctly');
|
|
||||||
t.is(xhr.getResponseHeader('set-cookie'), null, 'set-cookie works correctly');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState !== XMLHttpRequest.HEADERS_RECEIVED) { return; }
|
|
||||||
t.is(xhr.getResponseHeader('AccEPt-RANgeS'), 'bytes', 'AccEPt-RANgeS works correctly when HEADERS_RECEIVED ready state');
|
|
||||||
};
|
|
||||||
xhr.send(headerJson);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#getAllResponseHeaders contains accessible headers, does not contain private headers, has headers on HEADERS_RECEIVED readyState', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/get-headers`);
|
|
||||||
const headerJson = `{
|
|
||||||
"Accept-Ranges": "bytes",
|
|
||||||
"Content-Type": "application/xhr2; charset=utf-1337",
|
|
||||||
"Set-Cookie": "UserID=JohnDoe; Max-Age=3600; Version=1",
|
|
||||||
"X-Header": "one, more, value"
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onloadend = () => {
|
|
||||||
const headers = xhr.getAllResponseHeaders();
|
|
||||||
t.regex(headers, /(\A|\r\n)accept-ranges: bytes(\r\n|\Z)/mi);
|
|
||||||
t.regex(headers, /(\A|\r\n)content-type: application\/xhr2; charset=utf-1337(\r\n|\Z)/mi);
|
|
||||||
t.regex(headers, /(\A|\r\n)X-Header: one, more, value(\r\n|\Z)/mi);
|
|
||||||
t.notRegex(headers, /(\A|\r\n)set-cookie:/mi);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState !== XMLHttpRequest.HEADERS_RECEIVED) { return; }
|
|
||||||
const headers = xhr.getAllResponseHeaders();
|
|
||||||
t.regex(headers, /(\A|\r\n)accept-ranges: bytes(\r\n|\Z)/mi);
|
|
||||||
};
|
|
||||||
xhr.send(headerJson);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// * set request header after request opened should throw InvalidStateError
|
|
||||||
// *
|
|
@ -1,50 +0,0 @@
|
|||||||
export const certificate = `-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDXjCCAkYCCQCgZ4DViKxZtTANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJS
|
|
||||||
TzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTALBgNV
|
|
||||||
BAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYIWEBY
|
|
||||||
WC5YWFgwHhcNMTcxMTEzMTQzMTE2WhcNMjAwOTAyMTQzMTE2WjBxMQswCQYDVQQG
|
|
||||||
EwJSTzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTAL
|
|
||||||
BgNVBAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYI
|
|
||||||
WEBYWC5YWFgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyJ+21siOW
|
|
||||||
oRkgVSpQMaUAw/R54GG98k9IEMQnGBoD7HlnX4avgz0fNaA/xNdQuKVZqR0oshCx
|
|
||||||
6ks6mX4z/nYHh4SNmQVmAH7mJnT5aqHVs4OplVU5ZmZNsBx7+7JEFk64G7k011rI
|
|
||||||
76MVjLrNYJSTlgrtYOcNJle6awCwmI2nsrHSJJeyMVOGUK8H9RDzsPPZIQS0u4wJ
|
|
||||||
P8mIAoln/mpgP5I2lNTM2FaokmQq4mEYErUsWf+DhSlmnbZFxt5V3r/xHWVrouig
|
|
||||||
RsjhFxoGRg3p0HoUR79Rc8LqbbMtibh1qSkXcHjue1rBcSYurQNPzdbf3R4WuUyb
|
|
||||||
lxhui0rfu8fFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABphKcUJbdEhUpWF4EZE
|
|
||||||
BBl/uzE4/WXtQZdgz3fGpvpzmXZBRtbkdPR3jxBW1c9asCfb366dXRb8im6/p6ae
|
|
||||||
sAxZINMKIQ8KCIEb+StVMc4MvxASMm1SSz/kFuTCA2Q8vD5sHJrFcoKk6HKNEOLu
|
|
||||||
dALKpO8ZDuxjv036sCnjfyDue9psSccsLuAhfr2NLL5Ky9lWrJFi3b35D5UHrlK/
|
|
||||||
9mb9izRgZSC9+sZgpSyvIK6idKoWB4s9RpCn8itucFHHUDOvv8DdwvsF/5iVyWz7
|
|
||||||
R5uR4/qA8k7lbHHLosu2ELyx3N6Go0AskjxzsONPOKNlGIDllTx21mkIvTkGlJgs
|
|
||||||
8/4=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
`;
|
|
||||||
export const key = `-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEowIBAAKCAQEAsifttbIjlqEZIFUqUDGlAMP0eeBhvfJPSBDEJxgaA+x5Z1+G
|
|
||||||
r4M9HzWgP8TXULilWakdKLIQsepLOpl+M/52B4eEjZkFZgB+5iZ0+Wqh1bODqZVV
|
|
||||||
OWZmTbAce/uyRBZOuBu5NNdayO+jFYy6zWCUk5YK7WDnDSZXumsAsJiNp7Kx0iSX
|
|
||||||
sjFThlCvB/UQ87Dz2SEEtLuMCT/JiAKJZ/5qYD+SNpTUzNhWqJJkKuJhGBK1LFn/
|
|
||||||
g4UpZp22RcbeVd6/8R1la6LooEbI4RcaBkYN6dB6FEe/UXPC6m2zLYm4dakpF3B4
|
|
||||||
7ntawXEmLq0DT83W390eFrlMm5cYbotK37vHxQIDAQABAoIBAEUu8EbA2MUj5kgC
|
|
||||||
Cp59yN/VONkjY5GJyXPo3uN3npKrgDG+jOUXh+LYxlQ9MogsTDnXTHWDQKx2maQ1
|
|
||||||
+yZhyJ//5l++brQ/uQfTI1XALPx568UtMp1JwKymmUkkYwPBzev9CB0XDDA/rwst
|
|
||||||
TVV4DfqKJ9Aq807N9v9zkh8B/vCB9Ecvfco7Q2+AgrsLoaUDR9IwbiQXLqrqLA/F
|
|
||||||
tXh29Okwt7A3cv2C7Yd0rWyZLJi5iyH/lzcu33xGfaIAeN0fHtefKEhPU/yS69VM
|
|
||||||
9HbdDC44h0/psNyBt0dlrUYx32oYzF8EV4brrqcZTVUJNfCEqA16nTMKSmCJQdR8
|
|
||||||
nPJCRYECgYEA3U/0MyNDVa/OphEcBGLnXhRBeBGTGIP768gkn0Fw3Fgk1v6eqfKb
|
|
||||||
JqBujdgJjxbebo32OZeRLw92RBsfNY5IyIwVUKgZbtNkysgf612IhNoeBF7Ljz3r
|
|
||||||
BbSq3gwOHuUszCjO8/SjQn9bRLxVifrRD04SdHudMN4V2g98yoBBEdUCgYEAzhRZ
|
|
||||||
BWdOlLG2gAa8waPeuHUkwGU4zKly3zLSnbNvJJJ/wSTbuGmPQhLcWXq27gepHzZf
|
|
||||||
fvVJbpHrLHksh3fwdPusmygXD/s0gxMQJqJJledk1GEUnPjuuAImKvmeJWyX5lGq
|
|
||||||
APMh+M5ZB6CBu1dqapAs7nkOLCsSDGatRwc65jECgYBGI2q/MjPK2jbhxpZchYPR
|
|
||||||
+xVsmhVGNb4HUZzZpAHCs2SphnR+Y9br/PhMl+Ufph3EZ9VbFz/57CqNFxNjA77p
|
|
||||||
YAv5Te0RhIlzAs2q6C+1+vJ8bBaTRQpQ+psUWDm5bOQvp9c+1Y9QKdChDhcF7amH
|
|
||||||
8jRDGlINBLVkMHhaLR9yKQKBgQDIBfH+D66zHucPzvpJTYAxM+qvH9CIvfP0doT9
|
|
||||||
cptvOQ7tbpQho7vcGyhrZXPHCAJ8fC8msHhM7S8B5L924dCwC1QW6UuxRFdM3iTw
|
|
||||||
Ctc3u/gfN/dlAS3bxqI7VjvNAWFSuXM0JsmTkN3TTFR/fTKaKkSiVzeNYWTMSqDn
|
|
||||||
bzoZEQKBgFZcAbn2h86jYJ2tcznBriLI8rZBkPL9MFP4QM2Ksz5/8fsJ84EPsatg
|
|
||||||
700S1yasmDwaOgBLtSKsy7Rju5E3nebaPgLw3x92LiI07F97p2Y5ftSbRgslaih4
|
|
||||||
fDBm/C82anx0q9s4psw1oNnYj20c+imPIWvM7A0W85kmqcmQvzwZ
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
`;
|
|
5
local_modules/web3-providers-http/local_modules/xhr2-cookies/test/helpers/certificates/generate.sh
5
local_modules/web3-providers-http/local_modules/xhr2-cookies/test/helpers/certificates/generate.sh
@ -1,5 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
rm localhost.key.pem localhost.cert.pem
|
|
||||||
openssl req -nodes -newkey rsa:2048 -keyout localhost.key2.pem -x509 -days 1024 -out localhost.cert.pem
|
|
||||||
openssl rsa -in localhost.key2.pem -out localhost.key.pem
|
|
@ -1,21 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDXjCCAkYCCQCgZ4DViKxZtTANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJS
|
|
||||||
TzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTALBgNV
|
|
||||||
BAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYIWEBY
|
|
||||||
WC5YWFgwHhcNMTcxMTEzMTQzMTE2WhcNMjAwOTAyMTQzMTE2WjBxMQswCQYDVQQG
|
|
||||||
EwJSTzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTAL
|
|
||||||
BgNVBAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYI
|
|
||||||
WEBYWC5YWFgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyJ+21siOW
|
|
||||||
oRkgVSpQMaUAw/R54GG98k9IEMQnGBoD7HlnX4avgz0fNaA/xNdQuKVZqR0oshCx
|
|
||||||
6ks6mX4z/nYHh4SNmQVmAH7mJnT5aqHVs4OplVU5ZmZNsBx7+7JEFk64G7k011rI
|
|
||||||
76MVjLrNYJSTlgrtYOcNJle6awCwmI2nsrHSJJeyMVOGUK8H9RDzsPPZIQS0u4wJ
|
|
||||||
P8mIAoln/mpgP5I2lNTM2FaokmQq4mEYErUsWf+DhSlmnbZFxt5V3r/xHWVrouig
|
|
||||||
RsjhFxoGRg3p0HoUR79Rc8LqbbMtibh1qSkXcHjue1rBcSYurQNPzdbf3R4WuUyb
|
|
||||||
lxhui0rfu8fFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABphKcUJbdEhUpWF4EZE
|
|
||||||
BBl/uzE4/WXtQZdgz3fGpvpzmXZBRtbkdPR3jxBW1c9asCfb366dXRb8im6/p6ae
|
|
||||||
sAxZINMKIQ8KCIEb+StVMc4MvxASMm1SSz/kFuTCA2Q8vD5sHJrFcoKk6HKNEOLu
|
|
||||||
dALKpO8ZDuxjv036sCnjfyDue9psSccsLuAhfr2NLL5Ky9lWrJFi3b35D5UHrlK/
|
|
||||||
9mb9izRgZSC9+sZgpSyvIK6idKoWB4s9RpCn8itucFHHUDOvv8DdwvsF/5iVyWz7
|
|
||||||
R5uR4/qA8k7lbHHLosu2ELyx3N6Go0AskjxzsONPOKNlGIDllTx21mkIvTkGlJgs
|
|
||||||
8/4=
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEowIBAAKCAQEAsifttbIjlqEZIFUqUDGlAMP0eeBhvfJPSBDEJxgaA+x5Z1+G
|
|
||||||
r4M9HzWgP8TXULilWakdKLIQsepLOpl+M/52B4eEjZkFZgB+5iZ0+Wqh1bODqZVV
|
|
||||||
OWZmTbAce/uyRBZOuBu5NNdayO+jFYy6zWCUk5YK7WDnDSZXumsAsJiNp7Kx0iSX
|
|
||||||
sjFThlCvB/UQ87Dz2SEEtLuMCT/JiAKJZ/5qYD+SNpTUzNhWqJJkKuJhGBK1LFn/
|
|
||||||
g4UpZp22RcbeVd6/8R1la6LooEbI4RcaBkYN6dB6FEe/UXPC6m2zLYm4dakpF3B4
|
|
||||||
7ntawXEmLq0DT83W390eFrlMm5cYbotK37vHxQIDAQABAoIBAEUu8EbA2MUj5kgC
|
|
||||||
Cp59yN/VONkjY5GJyXPo3uN3npKrgDG+jOUXh+LYxlQ9MogsTDnXTHWDQKx2maQ1
|
|
||||||
+yZhyJ//5l++brQ/uQfTI1XALPx568UtMp1JwKymmUkkYwPBzev9CB0XDDA/rwst
|
|
||||||
TVV4DfqKJ9Aq807N9v9zkh8B/vCB9Ecvfco7Q2+AgrsLoaUDR9IwbiQXLqrqLA/F
|
|
||||||
tXh29Okwt7A3cv2C7Yd0rWyZLJi5iyH/lzcu33xGfaIAeN0fHtefKEhPU/yS69VM
|
|
||||||
9HbdDC44h0/psNyBt0dlrUYx32oYzF8EV4brrqcZTVUJNfCEqA16nTMKSmCJQdR8
|
|
||||||
nPJCRYECgYEA3U/0MyNDVa/OphEcBGLnXhRBeBGTGIP768gkn0Fw3Fgk1v6eqfKb
|
|
||||||
JqBujdgJjxbebo32OZeRLw92RBsfNY5IyIwVUKgZbtNkysgf612IhNoeBF7Ljz3r
|
|
||||||
BbSq3gwOHuUszCjO8/SjQn9bRLxVifrRD04SdHudMN4V2g98yoBBEdUCgYEAzhRZ
|
|
||||||
BWdOlLG2gAa8waPeuHUkwGU4zKly3zLSnbNvJJJ/wSTbuGmPQhLcWXq27gepHzZf
|
|
||||||
fvVJbpHrLHksh3fwdPusmygXD/s0gxMQJqJJledk1GEUnPjuuAImKvmeJWyX5lGq
|
|
||||||
APMh+M5ZB6CBu1dqapAs7nkOLCsSDGatRwc65jECgYBGI2q/MjPK2jbhxpZchYPR
|
|
||||||
+xVsmhVGNb4HUZzZpAHCs2SphnR+Y9br/PhMl+Ufph3EZ9VbFz/57CqNFxNjA77p
|
|
||||||
YAv5Te0RhIlzAs2q6C+1+vJ8bBaTRQpQ+psUWDm5bOQvp9c+1Y9QKdChDhcF7amH
|
|
||||||
8jRDGlINBLVkMHhaLR9yKQKBgQDIBfH+D66zHucPzvpJTYAxM+qvH9CIvfP0doT9
|
|
||||||
cptvOQ7tbpQho7vcGyhrZXPHCAJ8fC8msHhM7S8B5L924dCwC1QW6UuxRFdM3iTw
|
|
||||||
Ctc3u/gfN/dlAS3bxqI7VjvNAWFSuXM0JsmTkN3TTFR/fTKaKkSiVzeNYWTMSqDn
|
|
||||||
bzoZEQKBgFZcAbn2h86jYJ2tcznBriLI8rZBkPL9MFP4QM2Ksz5/8fsJ84EPsatg
|
|
||||||
700S1yasmDwaOgBLtSKsy7Rju5E3nebaPgLw3x92LiI07F97p2Y5ftSbRgslaih4
|
|
||||||
fDBm/C82anx0q9s4psw1oNnYj20c+imPIWvM7A0W85kmqcmQvzwZ
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCyJ+21siOWoRkg
|
|
||||||
VSpQMaUAw/R54GG98k9IEMQnGBoD7HlnX4avgz0fNaA/xNdQuKVZqR0oshCx6ks6
|
|
||||||
mX4z/nYHh4SNmQVmAH7mJnT5aqHVs4OplVU5ZmZNsBx7+7JEFk64G7k011rI76MV
|
|
||||||
jLrNYJSTlgrtYOcNJle6awCwmI2nsrHSJJeyMVOGUK8H9RDzsPPZIQS0u4wJP8mI
|
|
||||||
Aoln/mpgP5I2lNTM2FaokmQq4mEYErUsWf+DhSlmnbZFxt5V3r/xHWVrouigRsjh
|
|
||||||
FxoGRg3p0HoUR79Rc8LqbbMtibh1qSkXcHjue1rBcSYurQNPzdbf3R4WuUyblxhu
|
|
||||||
i0rfu8fFAgMBAAECggEARS7wRsDYxSPmSAIKnn3I39U42SNjkYnJc+je43eekquA
|
|
||||||
Mb6M5ReH4tjGVD0yiCxMOddMdYNArHaZpDX7JmHIn//mX75utD+5B9MjVcAs/Hnr
|
|
||||||
xS0ynUnArKaZSSRjA8HN6/0IHRcMMD+vCy1NVXgN+oon0CrzTs32/3OSHwH+8IH0
|
|
||||||
Ry99yjtDb4CCuwuhpQNH0jBuJBcuquosD8W1eHb06TC3sDdy/YLth3StbJksmLmL
|
|
||||||
If+XNy7ffEZ9ogB43R8e158oSE9T/JLr1Uz0dt0MLjiHT+mw3IG3R2WtRjHfahjM
|
|
||||||
XwRXhuuupxlNVQk18ISoDXqdMwpKYIlB1Hyc8kJFgQKBgQDdT/QzI0NVr86mERwE
|
|
||||||
YudeFEF4EZMYg/vryCSfQXDcWCTW/p6p8psmoG6N2AmPFt5ujfY5l5EvD3ZEGx81
|
|
||||||
jkjIjBVQqBlu02TKyB/rXYiE2h4EXsuPPesFtKreDA4e5SzMKM7z9KNCf1tEvFWJ
|
|
||||||
+tEPThJ0e50w3hXaD3zKgEER1QKBgQDOFFkFZ06UsbaABrzBo964dSTAZTjMqXLf
|
|
||||||
MtKds28kkn/BJNu4aY9CEtxZerbuB6kfNl9+9UlukesseSyHd/B0+6ybKBcP+zSD
|
|
||||||
ExAmokmV52TUYRSc+O64AiYq+Z4lbJfmUaoA8yH4zlkHoIG7V2pqkCzueQ4sKxIM
|
|
||||||
Zq1HBzrmMQKBgEYjar8yM8raNuHGllyFg9H7FWyaFUY1vgdRnNmkAcKzZKmGdH5j
|
|
||||||
1uv8+EyX5R+mHcRn1VsXP/nsKo0XE2MDvulgC/lN7RGEiXMCzaroL7X68nxsFpNF
|
|
||||||
ClD6mxRYObls5C+n1z7Vj1Ap0KEOFwXtqYfyNEMaUg0EtWQweFotH3IpAoGBAMgF
|
|
||||||
8f4PrrMe5w/O+klNgDEz6q8f0Ii98/R2hP1ym285Du1ulCGju9wbKGtlc8cIAnx8
|
|
||||||
LyaweEztLwHkv3bh0LALVBbpS7FEV0zeJPAK1ze7+B8392UBLdvGojtWO80BYVK5
|
|
||||||
czQmyZOQ3dNMVH99MpoqRKJXN41hZMxKoOdvOhkRAoGAVlwBufaHzqNgna1zOcGu
|
|
||||||
IsjytkGQ8v0wU/hAzYqzPn/x+wnzgQ+xq2DvTRLXJqyYPBo6AEu1IqzLtGO7kTed
|
|
||||||
5to+AvDfH3YuIjTsX3unZjl+1JtGCyVqKHh8MGb8LzZqfHSr2zimzDWg2diPbRz6
|
|
||||||
KY8ha8zsDRbzmSapyZC/PBk=
|
|
||||||
-----END PRIVATE KEY-----
|
|
@ -1,8 +0,0 @@
|
|||||||
import * as fs from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
const PNGBuffer = fs.readFileSync(path.join(__dirname, '../fixtures/hello.png'));
|
|
||||||
const PNGUint8Array = new Uint8Array(PNGBuffer);
|
|
||||||
const PNGArrayBuffer = PNGUint8Array.buffer as ArrayBuffer;
|
|
||||||
|
|
||||||
export { PNGBuffer, PNGArrayBuffer, PNGUint8Array };
|
|
@ -1,228 +0,0 @@
|
|||||||
import * as express from 'express';
|
|
||||||
import { Application, NextFunction, Request, Response } from 'express';
|
|
||||||
import * as http from 'http';
|
|
||||||
import { Server as HttpServer } from 'http';
|
|
||||||
import * as https from 'https';
|
|
||||||
import { Server as HttpsServer } from 'https';
|
|
||||||
import * as bodyParser from 'body-parser';
|
|
||||||
import * as cookieParser from 'cookie-parser';
|
|
||||||
import { certificate, key } from './certificates/certificate';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export class XhrServer {
|
|
||||||
app: Application;
|
|
||||||
server: HttpServer | HttpsServer;
|
|
||||||
serverStarted: Promise<void>;
|
|
||||||
|
|
||||||
private setServerStarted: () => void;
|
|
||||||
|
|
||||||
constructor(public port = 8080, private useHttps = false) {
|
|
||||||
this.serverStarted = new Promise(resolve => this.setServerStarted = resolve);
|
|
||||||
this.createApp();
|
|
||||||
}
|
|
||||||
|
|
||||||
testUrl() {
|
|
||||||
return `https://localhost:${this.port}/test/html/browser_test.html`;
|
|
||||||
}
|
|
||||||
|
|
||||||
sslCertificate() {
|
|
||||||
return this.useHttps ? certificate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
sslKey() {
|
|
||||||
return this.useHttps ? key : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
createApp() {
|
|
||||||
this.app = express();
|
|
||||||
this.app.use(bodyParser.json());
|
|
||||||
this.app.use(bodyParser.urlencoded({ extended: true }));
|
|
||||||
this.app.use(cookieParser());
|
|
||||||
|
|
||||||
this.app.use((request: Request, response: Response, next: NextFunction) => {
|
|
||||||
response.header('Access-Control-Allow-Origin', '*');
|
|
||||||
response.header('Access-Control-Allow-Methods', 'DELETE,GET,POST,PUT');
|
|
||||||
response.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Cookie');
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.get('/test/fixtures/hello.txt', (request: Request, response: Response) => {
|
|
||||||
const body = 'Hello, world!';
|
|
||||||
response.header('Content-Type', 'text/plain; charset=utf-8');
|
|
||||||
response.header('Content-Length', body.length.toString());
|
|
||||||
response.end(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.get('/test/fixtures/hello.json', (request: Request, response: Response) => {
|
|
||||||
const body = '{"hello": "world", "answer": 42}\n';
|
|
||||||
response.header('Content-Type', 'application/json');
|
|
||||||
response.header('Content-Length', body.length.toString());
|
|
||||||
response.end(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.get('/test/html/browser_test.html', (request: Request, response: Response) => {
|
|
||||||
const body = '<p>Test</p>';
|
|
||||||
response.header('Content-Type', 'text/html');
|
|
||||||
response.header('Content-Length', body.length.toString());
|
|
||||||
response.end(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.all('/_/method', (request: Request, response: Response) => {
|
|
||||||
const body = request.method;
|
|
||||||
response.header('Content-Type', 'text/plain; charset=utf-8');
|
|
||||||
response.header('Content-Length', body.length.toString());
|
|
||||||
response.end(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Echoes the request body. Used to test send(data).
|
|
||||||
this.app.post('/_/echo', (request: Request, response: Response) => {
|
|
||||||
if (request.headers['content-type']) {
|
|
||||||
response.header('Content-Type', request.headers['content-type']);
|
|
||||||
}
|
|
||||||
if (request.headers['content-length']) {
|
|
||||||
response.header('Content-Length', request.headers['content-length']);
|
|
||||||
}
|
|
||||||
request.on('data', chunk => response.write(chunk));
|
|
||||||
request.on('end', () => response.end());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Lists the request headers. Used to test setRequestHeader().
|
|
||||||
this.app.all('/_/headers', (request: Request, response: Response) => {
|
|
||||||
const body = JSON.stringify(request.headers);
|
|
||||||
response.header('Content-Type', 'application/json');
|
|
||||||
response.header('Content-Length', body.length.toString());
|
|
||||||
response.end(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sets the response headers in the request. Used to test getResponse*().
|
|
||||||
this.app.post('/_/get-headers', (request: Request, response: Response) => {
|
|
||||||
let jsonString = '';
|
|
||||||
request.on('data', chunk => jsonString += chunk);
|
|
||||||
request.on('end', () => {
|
|
||||||
const headers = JSON.parse(jsonString);
|
|
||||||
for (let name in headers) {
|
|
||||||
if (headers.hasOwnProperty(name)) {
|
|
||||||
response.header(name, headers[name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response.header('Content-Length', '0');
|
|
||||||
response.end('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sets every response detail. Used for error testing.
|
|
||||||
this.app.post('/_/response', (request: Request, response: Response) => {
|
|
||||||
let jsonString = '';
|
|
||||||
request.on('data', chunk => jsonString += chunk);
|
|
||||||
request.on('end', () => {
|
|
||||||
const json = JSON.parse(jsonString);
|
|
||||||
response.writeHead(json.code, json.status, json.headers);
|
|
||||||
if (json.body) { response.write(json.body); }
|
|
||||||
response.end();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sends data in small chunks. Used for event testing.
|
|
||||||
this.app.post('/_/drip', (request: Request, response: Response) => {
|
|
||||||
request.connection.setNoDelay();
|
|
||||||
let jsonString = '';
|
|
||||||
request.on('data', chunk => jsonString += chunk);
|
|
||||||
request.on('end', () => {
|
|
||||||
const json = JSON.parse(jsonString);
|
|
||||||
let sentDrips = 0;
|
|
||||||
const drip = new Array(json.size + 1).join('.');
|
|
||||||
response.header('Content-Type', 'text/plain');
|
|
||||||
if (json.length) { response.header('Content-Length', (json.drips * json.size).toString()); }
|
|
||||||
|
|
||||||
(function sendDrip() {
|
|
||||||
response.write(drip);
|
|
||||||
sentDrips++;
|
|
||||||
if (sentDrips >= json.drips) { return response.end(); }
|
|
||||||
setTimeout(sendDrip, json.ms);
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Returns a HTTP redirect. Used to test the redirection handling code.
|
|
||||||
this.app.all('/_/redirect/:status/:next', (request: Request, response: Response) => {
|
|
||||||
response.statusCode = +request.params.status;
|
|
||||||
response.header('Location', `${request.protocol}://${request.get('host')}/_/${request.params.next}`);
|
|
||||||
const body = '<p>This is supposed to have a redirect link</p>';
|
|
||||||
response.header('Content-Type', 'text/html');
|
|
||||||
response.header('Content-Length', body.length.toString());
|
|
||||||
response.header('X-Redirect-Header', 'should not show up');
|
|
||||||
response.end(body);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sets a cookie
|
|
||||||
this.app.all('/_/set-cookie/:name/:value', (request: Request, response: Response) => {
|
|
||||||
response.cookie(request.params.name, request.params.value);
|
|
||||||
response.header('Content-Type', 'text/plain');
|
|
||||||
response.header('Content-Length', '0');
|
|
||||||
response.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Redirects and sets a cookie.
|
|
||||||
this.app.all('/_/redirect-cookie/:name/:value', (request: Request, response: Response) => {
|
|
||||||
response.cookie(request.params.name, request.params.value);
|
|
||||||
response.redirect(301,
|
|
||||||
`${request.protocol}://${request.get('host')}/_/print-cookie/${request.params.name}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Read cookie + print its value.
|
|
||||||
this.app.get('/_/print-cookie/:name', (request: Request, response: Response) => {
|
|
||||||
const cookieValue = request.cookies[request.params.name];
|
|
||||||
response.header('Content-Type', 'text/plain');
|
|
||||||
response.header('Content-Length', cookieValue.length.toString());
|
|
||||||
response.end(cookieValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Requested when the browser test suite completes.
|
|
||||||
this.app.get('/_/end', (request: Request, response: Response) => {
|
|
||||||
const failed = request.query.hasOwnProperty('failed') ? +request.query.failed : 1;
|
|
||||||
const total = request.query.hasOwnProperty('total') ? +request.query.total : 0;
|
|
||||||
const passed = total - failed;
|
|
||||||
const exitCode = failed ? 1 : 0;
|
|
||||||
console.log(`${passed} passed, ${failed} failed`);
|
|
||||||
|
|
||||||
response.header('Content-Type', 'image/png');
|
|
||||||
response.header('Content-Length', '0');
|
|
||||||
response.end('');
|
|
||||||
|
|
||||||
if (!process.env.hasOwnProperty('NO_EXIT')) {
|
|
||||||
this.server.close();
|
|
||||||
process.exit(exitCode);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.use(express.static(path.join(__dirname, '../../')));
|
|
||||||
|
|
||||||
this.createServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
createServer() {
|
|
||||||
this.server = this.useHttps
|
|
||||||
? https.createServer({
|
|
||||||
cert: this.sslCertificate(),
|
|
||||||
key: this.sslKey()
|
|
||||||
}, this.app)
|
|
||||||
: http.createServer(this.app);
|
|
||||||
|
|
||||||
this.server.on('error', (error) => {
|
|
||||||
if (error.code !== 'EADDRINUSE') { return; }
|
|
||||||
this.port += 2;
|
|
||||||
this.createServer();
|
|
||||||
});
|
|
||||||
this.server.on('listening', () => {
|
|
||||||
this.setServerStarted();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.listen(this.port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const HttpServer = new XhrServer(8900, false);
|
|
||||||
const HttpsServer = new XhrServer(8901, true);
|
|
||||||
|
|
||||||
export { HttpServer, HttpsServer };
|
|
@ -1,120 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest(),
|
|
||||||
customXhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
t.context.customXhr = new XMLHttpRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest.nodejsSet with a httpAgent option', t => {
|
|
||||||
const customAgent = {custom: 'httpAgent'};
|
|
||||||
const defaultAgent = XMLHttpRequest.prototype.nodejsHttpAgent;
|
|
||||||
const agent = {mocking: 'httpAgent'};
|
|
||||||
t.context.customXhr.nodejsHttpAgent = customAgent as any;
|
|
||||||
XMLHttpRequest.nodejsSet({httpAgent: agent} as any);
|
|
||||||
t.is(t.context.xhr.nodejsHttpAgent, agent as any, 'sets the default nodejsHttpAgent');
|
|
||||||
t.is(t.context.customXhr.nodejsHttpAgent, customAgent as any, 'does not interfere with custom nodejsHttpAgent settings');
|
|
||||||
XMLHttpRequest.nodejsSet({httpAgent: defaultAgent});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest.nodejsSet with a httpsAgent option', t => {
|
|
||||||
const customAgent = {custom: 'httpsAgent'};
|
|
||||||
const defaultAgent = XMLHttpRequest.prototype.nodejsHttpsAgent;
|
|
||||||
const agent = {mocking: 'httpsAgent'};
|
|
||||||
t.context.customXhr.nodejsHttpsAgent = customAgent as any;
|
|
||||||
XMLHttpRequest.nodejsSet({httpsAgent: agent} as any);
|
|
||||||
t.is(t.context.xhr.nodejsHttpsAgent, agent as any, 'sets the default nodejsHttpsAgent');
|
|
||||||
t.is(t.context.customXhr.nodejsHttpsAgent, customAgent as any, 'does not interfere with custom nodejsHttpsAgent settings');
|
|
||||||
XMLHttpRequest.nodejsSet({httpsAgent: defaultAgent});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest.nodejsSet with a baseUrl option', t => {
|
|
||||||
const customBaseUrl = 'http://custom.url/base';
|
|
||||||
const defaultBaseUrl = XMLHttpRequest.prototype.nodejsBaseUrl;
|
|
||||||
const baseUrl = 'http://localhost/base';
|
|
||||||
t.context.customXhr.nodejsBaseUrl = customBaseUrl;
|
|
||||||
XMLHttpRequest.nodejsSet({baseUrl});
|
|
||||||
t.is(t.context.xhr.nodejsBaseUrl, baseUrl, 'sets the default nodejsBaseUrl');
|
|
||||||
t.is(t.context.customXhr.nodejsBaseUrl, customBaseUrl, 'does not interfere with custom nodejsBaseUrl settings');
|
|
||||||
XMLHttpRequest.nodejsSet({baseUrl: defaultBaseUrl});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#nodejsSet with a httpAgent option', t => {
|
|
||||||
const customAgent = {custom: 'httpAgent'};
|
|
||||||
t.context.customXhr.nodejsSet({httpAgent: customAgent as any});
|
|
||||||
t.is(t.context.customXhr.nodejsHttpAgent, customAgent as any, 'sets nodejsHttpAgent on the XHR instance');
|
|
||||||
t.not(t.context.xhr.nodejsHttpAgent, customAgent as any, 'does not interfere with default nodejsHttpAgent settings');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#nodejsSet with a httpsAgent option', t => {
|
|
||||||
const customAgent = {custom: 'httpsAgent'};
|
|
||||||
t.context.customXhr.nodejsSet({httpsAgent: customAgent as any});
|
|
||||||
t.is(t.context.customXhr.nodejsHttpsAgent, customAgent as any, 'sets nodejsHttpsAgent on the XHR instance');
|
|
||||||
t.not(t.context.xhr.nodejsHttpsAgent, customAgent as any, 'does not interfere with default nodejsHttpsAgent settings');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('base URL parsing with null baseUrl', t => {
|
|
||||||
const xhr = t.context.xhr as any;
|
|
||||||
xhr.nodejsSet({baseUrl: null});
|
|
||||||
const parsedUrl = xhr._parseUrl('http://www.domain.com/path');
|
|
||||||
t.truthy(parsedUrl);
|
|
||||||
t.true(parsedUrl.hasOwnProperty('href'));
|
|
||||||
t.is(parsedUrl.href, 'http://www.domain.com/path');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses an absolute URL', t => {
|
|
||||||
const xhr = t.context.xhr as any;
|
|
||||||
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
|
|
||||||
const parsedUrl = xhr._parseUrl('http://www.domain.com/path');
|
|
||||||
t.truthy(parsedUrl);
|
|
||||||
t.true(parsedUrl.hasOwnProperty('href'));
|
|
||||||
t.is(parsedUrl.href, 'http://www.domain.com/path');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a path-relative URL', t => {
|
|
||||||
const xhr = t.context.xhr as any;
|
|
||||||
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
|
|
||||||
const parsedUrl = xhr._parseUrl('path/to.js');
|
|
||||||
t.truthy(parsedUrl);
|
|
||||||
t.true(parsedUrl.hasOwnProperty('href'));
|
|
||||||
t.is(parsedUrl.href, 'https://base.url/dir/path/to.js');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a path-relative URL with ..', t => {
|
|
||||||
const xhr = t.context.xhr as any;
|
|
||||||
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
|
|
||||||
const parsedUrl = xhr._parseUrl('../path/to.js');
|
|
||||||
t.truthy(parsedUrl);
|
|
||||||
t.true(parsedUrl.hasOwnProperty('href'));
|
|
||||||
t.is(parsedUrl.href, 'https://base.url/path/to.js');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a host-relative URL', t => {
|
|
||||||
const xhr = t.context.xhr as any;
|
|
||||||
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
|
|
||||||
const parsedUrl = xhr._parseUrl('/path/to.js');
|
|
||||||
t.truthy(parsedUrl);
|
|
||||||
t.true(parsedUrl.hasOwnProperty('href'));
|
|
||||||
t.is(parsedUrl.href, 'https://base.url/path/to.js');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a protocol-relative URL', t => {
|
|
||||||
const xhr = t.context.xhr as any;
|
|
||||||
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
|
|
||||||
const parsedUrl = xhr._parseUrl('//domain.com/path/to.js');
|
|
||||||
t.truthy(parsedUrl);
|
|
||||||
t.true(parsedUrl.hasOwnProperty('href'));
|
|
||||||
t.is(parsedUrl.href, 'https://domain.com/path/to.js');
|
|
||||||
});
|
|
@ -1,120 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest when redirected issues a GET for the next location', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/redirect/302/method`);
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /GET/i);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => {
|
|
||||||
t.fail();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send('This should be dropped during the redirect');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest when redirected does not return the redirect headers', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/method`);
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.getResponseHeader('Content-Type'), 'text/plain; charset=utf-8');
|
|
||||||
t.falsy(xhr.getResponseHeader('X-Redirect-Header'));
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => {
|
|
||||||
t.fail();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest when redirected persists custom request headers across redirects', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/headers`);
|
|
||||||
xhr.setRequestHeader('X-Redirect-Test', 'should be preserved');
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/);
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.is(headers.connection, 'keep-alive');
|
|
||||||
t.true(headers.hasOwnProperty('host'));
|
|
||||||
t.is(headers.host, `localhost:${HttpServer.port}`);
|
|
||||||
t.true(headers.hasOwnProperty('x-redirect-test'));
|
|
||||||
t.is(headers['x-redirect-test'], 'should be preserved');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => {
|
|
||||||
t.fail();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest when redirected drops content-related headers across redirects', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/headers`);
|
|
||||||
xhr.setRequestHeader('X-Redirect-Test', 'should be preserved');
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/);
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.is(headers.connection, 'keep-alive');
|
|
||||||
t.true(headers.hasOwnProperty('host'));
|
|
||||||
t.is(headers.host, `localhost:${HttpServer.port}`);
|
|
||||||
t.true(headers.hasOwnProperty('x-redirect-test'));
|
|
||||||
t.is(headers['x-redirect-test'], 'should be preserved');
|
|
||||||
t.false(headers.hasOwnProperty('content-type'));
|
|
||||||
t.false(headers.hasOwnProperty('content-length'));
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => {
|
|
||||||
t.fail();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest when redirected provides the final responseURL', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/method`);
|
|
||||||
xhr.setRequestHeader('X-Redirect-Test', 'should be preserved');
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.responseUrl, `http://localhost:${HttpServer.port}/_/method`);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => {
|
|
||||||
t.fail();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,134 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
import { PNGArrayBuffer, PNGBuffer } from './helpers/png';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest(),
|
|
||||||
jsonUrl: '',
|
|
||||||
jsonString: '',
|
|
||||||
imageUrl: ''
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
t.context.jsonUrl = `http://localhost:${HttpServer.port}/test/fixtures/hello.json`;
|
|
||||||
t.context.jsonString = '{"hello": "world", "answer": 42}\n';
|
|
||||||
t.context.imageUrl = `http://localhost:${HttpServer.port}/test/fixtures/hello.png`;
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType text reads a JSON file into a String', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('load', () => {
|
|
||||||
t.is(xhr.response, t.context.jsonString);
|
|
||||||
t.is(xhr.responseText, t.context.jsonString);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', t.context.jsonUrl);
|
|
||||||
xhr.responseType = 'text';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType json reads a JSON file into a parsed JSON object', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('readystatechange', () => {
|
|
||||||
if (xhr.readyState !== XMLHttpRequest.DONE) { return; }
|
|
||||||
|
|
||||||
t.deepEqual(xhr.response, { hello: 'world', answer: 42 });
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', t.context.jsonUrl);
|
|
||||||
xhr.responseType = 'json';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType json produces null when reading a non-JSON file', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
t.is(xhr.response, null);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/test/fixtures/hello.txt`);
|
|
||||||
xhr.responseType = 'json';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType arraybuffer reads a JSON file into an ArrayBuffer', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
t.true(xhr.response instanceof ArrayBuffer);
|
|
||||||
if (!(xhr.response instanceof ArrayBuffer)) { return; }
|
|
||||||
const view = new Uint8Array(xhr.response);
|
|
||||||
const response = Array.from(view).map(viewElement => String.fromCharCode(viewElement)).join('');
|
|
||||||
t.is(response, t.context.jsonString);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', t.context.jsonUrl);
|
|
||||||
xhr.responseType = 'arraybuffer';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType arraybuffer reads a binary file into an ArrayBuffer', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
t.true(xhr.response instanceof ArrayBuffer);
|
|
||||||
if (!(xhr.response instanceof ArrayBuffer)) { return; }
|
|
||||||
t.deepEqual(xhr.response, PNGArrayBuffer);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', t.context.imageUrl);
|
|
||||||
xhr.responseType = 'arraybuffer';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType buffer reads a JSON file into a node.js Buffer', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
t.true(xhr.response instanceof Buffer);
|
|
||||||
if (!(xhr.response instanceof Buffer)) { return; }
|
|
||||||
const response = Array.from(xhr.response).map(viewElement => String.fromCharCode(viewElement)).join('');
|
|
||||||
t.is(response, t.context.jsonString);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', t.context.jsonUrl);
|
|
||||||
xhr.responseType = 'buffer';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseType buffer reads a binary file into a node.js Buffer', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.addEventListener('loadend', () => {
|
|
||||||
t.true(xhr.response instanceof Buffer);
|
|
||||||
if (!(xhr.response instanceof Buffer)) { return; }
|
|
||||||
t.deepEqual(xhr.response, PNGBuffer);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
xhr.open('GET', t.context.imageUrl);
|
|
||||||
xhr.responseType = 'buffer';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,46 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseURL provides the URL of the response', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/method`);
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.responseUrl, `http://localhost:${HttpServer.port}/_/method`);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #responseURL ignores the hash fragment', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/_/method#foo`);
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.responseUrl, `http://localhost:${HttpServer.port}/_/method`);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,137 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
import { PNGArrayBuffer, PNGUint8Array } from './helpers/png';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
t.context.xhr.open('POST', `http://localhost:${HttpServer.port}/_/echo`);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send works with ASCII DOMStrings', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.getResponseHeader('content-type'), /^text\/plain(;\s?charset=UTF-8)?$/);
|
|
||||||
t.is(xhr.responseText, 'Hello world!');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => { t.fail(); return resolve(); };
|
|
||||||
xhr.send('Hello world!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send works with UTF-8 DOMStrings', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.getResponseHeader('content-type'), /^text\/plain(;\s?charset=UTF-8)?$/);
|
|
||||||
t.is(xhr.responseText, '世界你好!');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.send('世界你好!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send works with ArrayBufferViews', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.responseType = 'arraybuffer';
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.getResponseHeader('content-type'), null);
|
|
||||||
if (!(xhr.response instanceof ArrayBuffer)) { t.fail(); return resolve(); }
|
|
||||||
t.deepEqual(new Uint8Array(xhr.response), PNGUint8Array);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => { t.fail(); return resolve(); };
|
|
||||||
xhr.send(PNGUint8Array);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send works with ArrayBufferViews with set index and length', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.plan(2);
|
|
||||||
const arrayBufferView10 = new Uint8Array(PNGArrayBuffer, 10, 42);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.responseType = 'arraybuffer';
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.getResponseHeader('content-type'), null);
|
|
||||||
if (!(xhr.response instanceof ArrayBuffer)) { t.fail(); return resolve(); }
|
|
||||||
t.deepEqual(new Uint8Array(xhr.response), arrayBufferView10);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => { t.fail(); return resolve(); };
|
|
||||||
xhr.send(arrayBufferView10);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send works with ArrayBuffers', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.responseType = 'arraybuffer';
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.getResponseHeader('content-type'), null);
|
|
||||||
if (!(xhr.response instanceof ArrayBuffer)) { t.fail(); return resolve(); }
|
|
||||||
t.deepEqual(xhr.response, PNGArrayBuffer);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => { t.fail(); return resolve(); };
|
|
||||||
xhr.send(PNGArrayBuffer);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send works with node.js Buffers', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
const buffer = Buffer.alloc(PNGUint8Array.length);
|
|
||||||
for (let i = 0; i < PNGUint8Array.length; i++) { buffer.writeUInt8(PNGUint8Array[i], i); }
|
|
||||||
t.plan(2);
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.responseType = 'buffer';
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.is(xhr.getResponseHeader('content-type'), null);
|
|
||||||
if (!(xhr.response instanceof Buffer)) { t.fail(); return resolve(); }
|
|
||||||
t.deepEqual(new Uint8Array(xhr.response), PNGUint8Array);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => { t.fail(); return resolve(); };
|
|
||||||
xhr.send(PNGArrayBuffer);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #send sets POST headers correctly when given null data', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.responseType = 'text';
|
|
||||||
xhr.onload = () => {
|
|
||||||
t.regex(xhr.responseText, /^\{.*\}$/);
|
|
||||||
const headers = JSON.parse(xhr.responseText);
|
|
||||||
t.true(headers.hasOwnProperty('content-length'));
|
|
||||||
t.is(headers['content-length'], '0');
|
|
||||||
t.false(headers.hasOwnProperty('content-type'));
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = () => { t.fail(); return resolve(); };
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,84 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer } from './helpers/server';
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest(),
|
|
||||||
okUrl: '',
|
|
||||||
errorUrl: '',
|
|
||||||
errorJson: ''
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async () => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
t.context.okUrl = `http://localhost:${HttpServer.port}/test/fixtures/hello.txt`;
|
|
||||||
t.context.errorUrl = `http://localhost:${HttpServer.port}/_/response`;
|
|
||||||
t.context.errorJson = JSON.stringify({
|
|
||||||
code: 401,
|
|
||||||
status: 'Unauthorized',
|
|
||||||
body: JSON.stringify({error: 'Credential error'}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Content-Length': '28'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #status is 200 for a normal request', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('GET', t.context.okUrl);
|
|
||||||
let done = false;
|
|
||||||
xhr.addEventListener('readystatechange', () => {
|
|
||||||
if (done) { return; }
|
|
||||||
if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) {
|
|
||||||
t.is(xhr.status, 0);
|
|
||||||
t.is(xhr.statusText, '');
|
|
||||||
} else {
|
|
||||||
t.is(xhr.status, 200);
|
|
||||||
t.truthy(xhr.statusText);
|
|
||||||
t.not(xhr.statusText, '');
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
done = true;
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest #status returns the server-reported status', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
await new Promise(resolve => {
|
|
||||||
xhr.open('POST', t.context.errorUrl);
|
|
||||||
let done = false;
|
|
||||||
xhr.addEventListener('readystatechange', () => {
|
|
||||||
if (done) { return; }
|
|
||||||
if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) {
|
|
||||||
t.is(xhr.status, 0);
|
|
||||||
t.is(xhr.statusText, '');
|
|
||||||
} else {
|
|
||||||
t.is(xhr.status, 401);
|
|
||||||
t.truthy(xhr.statusText);
|
|
||||||
t.not(xhr.statusText, '');
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
done = true;
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.send(t.context.errorJson);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es2015",
|
|
||||||
"module": "commonjs",
|
|
||||||
"sourceMap": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"lib": [ "es5", "es6", "es2016", "es2017", "dom" ]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"*.spec.ts",
|
|
||||||
"./png.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
import * as ava from 'ava';
|
|
||||||
import { XMLHttpRequest } from '../xml-http-request';
|
|
||||||
import { HttpServer, HttpsServer } from './helpers/server';
|
|
||||||
import * as https from 'https';
|
|
||||||
|
|
||||||
const agent = new https.Agent({
|
|
||||||
rejectUnauthorized: true,
|
|
||||||
ca: HttpsServer.sslCertificate()
|
|
||||||
});
|
|
||||||
XMLHttpRequest.nodejsSet({
|
|
||||||
httpsAgent: agent
|
|
||||||
});
|
|
||||||
|
|
||||||
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
|
|
||||||
ava.test.beforeEach(t => {
|
|
||||||
Object.assign(t.context, getContext());
|
|
||||||
});
|
|
||||||
return ava.test;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = contextualize(() => ({
|
|
||||||
xhr: new XMLHttpRequest()
|
|
||||||
}));
|
|
||||||
|
|
||||||
test.before(async t => {
|
|
||||||
await HttpServer.serverStarted;
|
|
||||||
await HttpsServer.serverStarted;
|
|
||||||
|
|
||||||
XMLHttpRequest.nodejsSet({
|
|
||||||
baseUrl: HttpServer.testUrl().replace('https://', 'http://')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(t => {
|
|
||||||
t.context.xhr = new XMLHttpRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('constructor', t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.is(xhr.readyState, XMLHttpRequest.UNSENT, 'sets readyState to UNSENT');
|
|
||||||
t.is(xhr.timeout, 0, 'sets timeout to 0');
|
|
||||||
t.is(xhr.responseType, '', 'sets responseType to ""');
|
|
||||||
t.is(xhr.status, 0, 'sets status to 0');
|
|
||||||
t.is(xhr.statusText, '', 'sets statusText to ""');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#open throws SecurityError on CONNECT', t => {
|
|
||||||
t.throws(() => t.context.xhr.open('CONNECT', `http://localhost:${HttpServer.port}/test`), XMLHttpRequest.SecurityError);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#open with a GET for a local https request', t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('GET', `https://localhost:${HttpsServer.port}/test/fixtures/hello.txt`);
|
|
||||||
t.is(xhr.readyState, XMLHttpRequest.OPENED, 'sets readyState to OPENED');
|
|
||||||
t.is(xhr.status, 0, 'keeps status 0');
|
|
||||||
t.is(xhr.statusText, '', 'keeps statusText ""');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#send on a local http GET kicks off the request', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('GET', `http://localhost:${HttpServer.port}/test/fixtures/hello.txt`);
|
|
||||||
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
xhr.onload = (event) => {
|
|
||||||
t.is(xhr.status, 200, 'the status is 200');
|
|
||||||
t.is(xhr.responseText, 'Hello, world!', 'the text is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = (event) => {
|
|
||||||
reject(event);
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('#send on a local https GET kicks off the request', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('GET', `https://localhost:${HttpsServer.port}/test/fixtures/hello.txt`);
|
|
||||||
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
xhr.onload = (event) => {
|
|
||||||
t.is(xhr.status, 200, 'the status is 200');
|
|
||||||
t.is(xhr.responseText, 'Hello, world!', 'the text is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = (event) => {
|
|
||||||
reject(event);
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('on a local relative GET it kicks off the request', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
xhr.open('GET', '../fixtures/hello.txt');
|
|
||||||
|
|
||||||
t.plan(2);
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
xhr.onload = (event) => {
|
|
||||||
t.is(xhr.status, 200, 'the status is 200');
|
|
||||||
t.is(xhr.responseText, 'Hello, world!', 'the text is correct');
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
xhr.onerror = (event) => {
|
|
||||||
reject(event);
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('on a local gopher GET #open + #send throws a NetworkError', async t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.throws(() => {
|
|
||||||
xhr.open('GET', `gopher:localhost:${HttpServer.port}`);
|
|
||||||
xhr.send();
|
|
||||||
}, XMLHttpRequest.NetworkError);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('readyState constants', t => {
|
|
||||||
t.is(XMLHttpRequest.UNSENT < XMLHttpRequest.OPENED, true, 'UNSENT < OPENED');
|
|
||||||
t.is(XMLHttpRequest.OPENED < XMLHttpRequest.HEADERS_RECEIVED, true, 'OPENED < HEADERS_RECEIVED');
|
|
||||||
t.is(XMLHttpRequest.HEADERS_RECEIVED < XMLHttpRequest.LOADING, true, 'HEADERS_RECEIVED < LOADING');
|
|
||||||
t.is(XMLHttpRequest.LOADING < XMLHttpRequest.DONE, true, 'LOADING < DONE');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('XMLHttpRequest constants match the instance constants', t => {
|
|
||||||
const xhr = t.context.xhr;
|
|
||||||
t.is(XMLHttpRequest.UNSENT, xhr.UNSENT, 'UNSENT');
|
|
||||||
t.is(XMLHttpRequest.OPENED, xhr.OPENED, 'OPENED');
|
|
||||||
t.is(XMLHttpRequest.HEADERS_RECEIVED, xhr.HEADERS_RECEIVED, 'HEADERS_RECEIVED');
|
|
||||||
t.is(XMLHttpRequest.LOADING, xhr.LOADING, 'LOADING');
|
|
||||||
t.is(XMLHttpRequest.DONE, xhr.DONE, 'DONE');
|
|
||||||
});
|
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"module": "commonjs",
|
|
||||||
"outDir": "dist",
|
|
||||||
"sourceMap": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"declaration": true,
|
|
||||||
"declarationDir": "dist",
|
|
||||||
"lib": [ "es5", "es6", "es2016", "es2017", "dom" ]
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"index.ts"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
{
|
|
||||||
"rules": {
|
|
||||||
"arrow-return-shorthand": true,
|
|
||||||
"callable-types": true,
|
|
||||||
"class-name": true,
|
|
||||||
"comment-format": [
|
|
||||||
true,
|
|
||||||
"check-space"
|
|
||||||
],
|
|
||||||
"curly": true,
|
|
||||||
"eofline": true,
|
|
||||||
"forin": true,
|
|
||||||
"import-blacklist": [
|
|
||||||
true,
|
|
||||||
"rxjs"
|
|
||||||
],
|
|
||||||
"import-spacing": true,
|
|
||||||
"indent": [
|
|
||||||
true,
|
|
||||||
"tabs"
|
|
||||||
],
|
|
||||||
"interface-over-type-literal": true,
|
|
||||||
"label-position": true,
|
|
||||||
"max-line-length": [
|
|
||||||
true,
|
|
||||||
140
|
|
||||||
],
|
|
||||||
"member-access": false,
|
|
||||||
"member-ordering": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"order": [
|
|
||||||
"static-field",
|
|
||||||
"instance-field",
|
|
||||||
"static-method",
|
|
||||||
"instance-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-arg": true,
|
|
||||||
"no-bitwise": true,
|
|
||||||
"no-console": [
|
|
||||||
true,
|
|
||||||
"debug",
|
|
||||||
"info",
|
|
||||||
"time",
|
|
||||||
"timeEnd",
|
|
||||||
"trace"
|
|
||||||
],
|
|
||||||
"no-construct": true,
|
|
||||||
"no-debugger": true,
|
|
||||||
"no-duplicate-super": true,
|
|
||||||
"no-empty": false,
|
|
||||||
"no-empty-interface": true,
|
|
||||||
"no-eval": true,
|
|
||||||
"no-inferrable-types": [
|
|
||||||
true,
|
|
||||||
"ignore-params"
|
|
||||||
],
|
|
||||||
"no-misused-new": true,
|
|
||||||
"no-non-null-assertion": true,
|
|
||||||
"no-shadowed-variable": true,
|
|
||||||
"no-string-literal": false,
|
|
||||||
"no-string-throw": true,
|
|
||||||
"no-switch-case-fall-through": true,
|
|
||||||
"no-trailing-whitespace": true,
|
|
||||||
"no-unnecessary-initializer": true,
|
|
||||||
"no-unused-expression": true,
|
|
||||||
"no-use-before-declare": true,
|
|
||||||
"no-var-keyword": true,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"one-line": [
|
|
||||||
true,
|
|
||||||
"check-open-brace",
|
|
||||||
"check-catch",
|
|
||||||
"check-else",
|
|
||||||
"check-whitespace"
|
|
||||||
],
|
|
||||||
"prefer-const": true,
|
|
||||||
"quotemark": [
|
|
||||||
true,
|
|
||||||
"single"
|
|
||||||
],
|
|
||||||
"radix": true,
|
|
||||||
"semicolon": [
|
|
||||||
true,
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"triple-equals": [
|
|
||||||
true,
|
|
||||||
"allow-null-check"
|
|
||||||
],
|
|
||||||
"typedef-whitespace": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"call-signature": "nospace",
|
|
||||||
"index-signature": "nospace",
|
|
||||||
"parameter": "nospace",
|
|
||||||
"property-declaration": "nospace",
|
|
||||||
"variable-declaration": "nospace"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typeof-compare": true,
|
|
||||||
"unified-signatures": true,
|
|
||||||
"variable-name": false,
|
|
||||||
"whitespace": [
|
|
||||||
true,
|
|
||||||
"check-branch",
|
|
||||||
"check-decl",
|
|
||||||
"check-operator",
|
|
||||||
"check-separator",
|
|
||||||
"check-type"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
module.exports = function (wallaby) {
|
|
||||||
return {
|
|
||||||
files: ['**/*.ts', '*.ts', '!test/**/*'],
|
|
||||||
tests: ['test/**/*.ts'],
|
|
||||||
env: {type: 'node'},
|
|
||||||
testFramework: 'ava',
|
|
||||||
recycle: true,
|
|
||||||
name: 'XMLHttpRequest 2+',
|
|
||||||
slowTestThreshold: 300,
|
|
||||||
reportUnhandledPromises: false,
|
|
||||||
workers: {
|
|
||||||
// initial: 1,
|
|
||||||
// regular: 1,
|
|
||||||
recycle: true
|
|
||||||
},
|
|
||||||
compilers: {
|
|
||||||
'**/*.ts': wallaby.compilers.typeScript({
|
|
||||||
target: 'es2015',
|
|
||||||
module: 'commonjs',
|
|
||||||
sourceMap: true,
|
|
||||||
experimentalDecorators: true,
|
|
||||||
emitDecoratorMetadata: true,
|
|
||||||
lib: ['es5', 'es6', 'es2016', 'es2017', 'dom']
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,49 +0,0 @@
|
|||||||
import { ProgressEvent } from './progress-event';
|
|
||||||
|
|
||||||
export type ProgressEventListener = (event: ProgressEvent) => void;
|
|
||||||
export type ProgressEventListenerObject = {handleEvent(event: ProgressEvent): void};
|
|
||||||
export type ProgressEventListenerOrEventListenerObject = ProgressEventListener | ProgressEventListenerObject;
|
|
||||||
|
|
||||||
export class XMLHttpRequestEventTarget {
|
|
||||||
onloadstart: ProgressEventListener | null;
|
|
||||||
onprogress: ProgressEventListener | null;
|
|
||||||
onabort: ProgressEventListener | null;
|
|
||||||
onerror: ProgressEventListener | null;
|
|
||||||
onload: ProgressEventListener | null;
|
|
||||||
ontimeout: ProgressEventListener | null;
|
|
||||||
onloadend: ProgressEventListener | null;
|
|
||||||
|
|
||||||
private listeners: {[eventType: string]: ProgressEventListener[]} = {};
|
|
||||||
|
|
||||||
addEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject) {
|
|
||||||
eventType = eventType.toLowerCase();
|
|
||||||
this.listeners[eventType] = this.listeners[eventType] || [];
|
|
||||||
this.listeners[eventType].push((listener as ProgressEventListenerObject).handleEvent || (listener as ProgressEventListener));
|
|
||||||
}
|
|
||||||
removeEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject) {
|
|
||||||
eventType = eventType.toLowerCase();
|
|
||||||
if (!this.listeners[eventType]) { return; }
|
|
||||||
|
|
||||||
const index = this.listeners[eventType].indexOf((listener as ProgressEventListenerObject).handleEvent || (listener as ProgressEventListener));
|
|
||||||
if (index < 0) { return; }
|
|
||||||
|
|
||||||
this.listeners[eventType].splice(index, 1);
|
|
||||||
}
|
|
||||||
dispatchEvent(event: ProgressEvent) {
|
|
||||||
const eventType = event.type.toLowerCase();
|
|
||||||
event.target = this; // TODO: set event.currentTarget?
|
|
||||||
|
|
||||||
if (this.listeners[eventType]) {
|
|
||||||
for (let listener of this.listeners[eventType]) {
|
|
||||||
listener.call(this, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const listener = this[`on${eventType}`];
|
|
||||||
if (listener) {
|
|
||||||
listener.call(this, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
||||||
import { ClientRequest } from 'http';
|
|
||||||
|
|
||||||
export class XMLHttpRequestUpload extends XMLHttpRequestEventTarget {
|
|
||||||
private _contentType: string | null = null;
|
|
||||||
private _body = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this._reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
_reset() {
|
|
||||||
this._contentType = null;
|
|
||||||
this._body = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_setData(data?: string | Buffer | ArrayBuffer | ArrayBufferView) {
|
|
||||||
if (data == null) { return; }
|
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
if (data.length !== 0) {
|
|
||||||
this._contentType = 'text/plain;charset=UTF-8';
|
|
||||||
}
|
|
||||||
this._body = Buffer.from(data, 'utf-8');
|
|
||||||
} else if (Buffer.isBuffer(data)) {
|
|
||||||
this._body = data;
|
|
||||||
} else if (data instanceof ArrayBuffer) {
|
|
||||||
const body = Buffer.alloc(data.byteLength);
|
|
||||||
const view = new Uint8Array(data);
|
|
||||||
for (let i = 0; i < data.byteLength; i++) { body[i] = view[i]; }
|
|
||||||
this._body = body;
|
|
||||||
} else if (data.buffer && data.buffer instanceof ArrayBuffer) {
|
|
||||||
const body = Buffer.alloc(data.byteLength);
|
|
||||||
const offset = data.byteOffset;
|
|
||||||
const view = new Uint8Array(data.buffer);
|
|
||||||
for (let i = 0; i < data.byteLength; i++) { body[i] = view[i + offset]; }
|
|
||||||
this._body = body;
|
|
||||||
} else {
|
|
||||||
throw new Error(`Unsupported send() data ${data}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_finalizeHeaders(headers: object, loweredHeaders: object) {
|
|
||||||
if (this._contentType && !loweredHeaders['content-type']) {
|
|
||||||
headers['Content-Type'] = this._contentType;
|
|
||||||
}
|
|
||||||
if (this._body) {
|
|
||||||
headers['Content-Length'] = this._body.length.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_startUpload(request: ClientRequest) {
|
|
||||||
if (this._body) { request.write(this._body); }
|
|
||||||
request.end();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,471 +0,0 @@
|
|||||||
import * as http from 'http';
|
|
||||||
import * as https from 'https';
|
|
||||||
import * as os from 'os';
|
|
||||||
import * as url from 'url';
|
|
||||||
import { ProgressEvent } from './progress-event';
|
|
||||||
import { InvalidStateError, NetworkError, SecurityError, SyntaxError } from './errors';
|
|
||||||
import { ProgressEventListener, XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
|
||||||
import { XMLHttpRequestUpload } from './xml-http-request-upload';
|
|
||||||
import { Url } from 'url';
|
|
||||||
import { Agent as HttpAgent, ClientRequest, IncomingMessage, RequestOptions as RequestOptionsHttp } from 'http';
|
|
||||||
import { Agent as HttpsAgent } from 'https';
|
|
||||||
import * as Cookie from 'cookiejar';
|
|
||||||
|
|
||||||
export interface XMLHttpRequestOptions {
|
|
||||||
anon?: boolean;
|
|
||||||
}
|
|
||||||
export interface XHRUrl extends Url {
|
|
||||||
method?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class XMLHttpRequest extends XMLHttpRequestEventTarget {
|
|
||||||
static ProgressEvent = ProgressEvent;
|
|
||||||
static InvalidStateError = InvalidStateError;
|
|
||||||
static NetworkError = NetworkError;
|
|
||||||
static SecurityError = SecurityError;
|
|
||||||
static SyntaxError = SyntaxError;
|
|
||||||
static XMLHttpRequestUpload = XMLHttpRequestUpload;
|
|
||||||
|
|
||||||
static UNSENT = 0;
|
|
||||||
static OPENED = 1;
|
|
||||||
static HEADERS_RECEIVED = 2;
|
|
||||||
static LOADING = 3;
|
|
||||||
static DONE = 4;
|
|
||||||
|
|
||||||
static cookieJar = Cookie.CookieJar();
|
|
||||||
|
|
||||||
UNSENT = XMLHttpRequest.UNSENT;
|
|
||||||
OPENED = XMLHttpRequest.OPENED;
|
|
||||||
HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED;
|
|
||||||
LOADING = XMLHttpRequest.LOADING;
|
|
||||||
DONE = XMLHttpRequest.DONE;
|
|
||||||
|
|
||||||
onreadystatechange: ProgressEventListener | null = null;
|
|
||||||
readyState: number = XMLHttpRequest.UNSENT;
|
|
||||||
|
|
||||||
response: string | ArrayBuffer | Buffer | object | null = null;
|
|
||||||
responseText = '';
|
|
||||||
responseType = '';
|
|
||||||
status = 0; // TODO: UNSENT?
|
|
||||||
statusText = '';
|
|
||||||
timeout = 0;
|
|
||||||
upload = new XMLHttpRequestUpload();
|
|
||||||
responseUrl = '';
|
|
||||||
withCredentials = false;
|
|
||||||
|
|
||||||
nodejsHttpAgent: HttpsAgent;
|
|
||||||
nodejsHttpsAgent: HttpsAgent;
|
|
||||||
nodejsBaseUrl: string | null;
|
|
||||||
|
|
||||||
private _anonymous: boolean;
|
|
||||||
private _method: string | null = null;
|
|
||||||
private _url: XHRUrl | null = null;
|
|
||||||
private _sync = false;
|
|
||||||
private _headers: {[header: string]: string} = {};
|
|
||||||
private _loweredHeaders: {[lowercaseHeader: string]: string} = {};
|
|
||||||
private _mimeOverride: string | null = null; // TODO: is type right?
|
|
||||||
private _request: ClientRequest | null = null;
|
|
||||||
private _response: IncomingMessage | null = null;
|
|
||||||
private _responseParts: Buffer[] | null = null;
|
|
||||||
private _responseHeaders: {[lowercaseHeader: string]: string} | null = null;
|
|
||||||
private _aborting = null; // TODO: type?
|
|
||||||
private _error = null; // TODO: type?
|
|
||||||
private _loadedBytes = 0;
|
|
||||||
private _totalBytes = 0;
|
|
||||||
private _lengthComputable = false;
|
|
||||||
|
|
||||||
private _restrictedMethods = {CONNECT: true, TRACE: true, TRACK: true};
|
|
||||||
private _restrictedHeaders = {
|
|
||||||
'accept-charset': true,
|
|
||||||
'accept-encoding': true,
|
|
||||||
'access-control-request-headers': true,
|
|
||||||
'access-control-request-method': true,
|
|
||||||
connection: true,
|
|
||||||
'content-length': true,
|
|
||||||
cookie: true,
|
|
||||||
cookie2: true,
|
|
||||||
date: true,
|
|
||||||
dnt: true,
|
|
||||||
expect: true,
|
|
||||||
host: true,
|
|
||||||
'keep-alive': true,
|
|
||||||
origin: true,
|
|
||||||
referer: true,
|
|
||||||
te: true,
|
|
||||||
trailer: true,
|
|
||||||
'transfer-encoding': true,
|
|
||||||
upgrade: true,
|
|
||||||
'user-agent': true,
|
|
||||||
via: true
|
|
||||||
};
|
|
||||||
private _privateHeaders = {'set-cookie': true, 'set-cookie2': true};
|
|
||||||
|
|
||||||
//Redacted private information (${os.type()} ${os.arch()}) node.js/${process.versions.node} v8/${process.versions.v8} from the original version @ github
|
|
||||||
//Pretend to be tor-browser https://blog.torproject.org/browser-fingerprinting-introduction-and-challenges-ahead/
|
|
||||||
private _userAgent = `Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0`;
|
|
||||||
|
|
||||||
constructor(options: XMLHttpRequestOptions = {}) {
|
|
||||||
super();
|
|
||||||
this._anonymous = options.anon || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
open(method: string, url: string, async = true, user?: string, password?: string) {
|
|
||||||
method = method.toUpperCase();
|
|
||||||
if (this._restrictedMethods[method]) { throw new XMLHttpRequest.SecurityError(`HTTP method ${method} is not allowed in XHR`)};
|
|
||||||
|
|
||||||
const xhrUrl = this._parseUrl(url, user, password);
|
|
||||||
|
|
||||||
if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED || this.readyState === XMLHttpRequest.LOADING) {
|
|
||||||
// TODO(pwnall): terminate abort(), terminate send()
|
|
||||||
}
|
|
||||||
|
|
||||||
this._method = method;
|
|
||||||
this._url = xhrUrl;
|
|
||||||
this._sync = !async;
|
|
||||||
this._headers = {};
|
|
||||||
this._loweredHeaders = {};
|
|
||||||
this._mimeOverride = null;
|
|
||||||
this._setReadyState(XMLHttpRequest.OPENED);
|
|
||||||
this._request = null;
|
|
||||||
this._response = null;
|
|
||||||
this.status = 0;
|
|
||||||
this.statusText = '';
|
|
||||||
this._responseParts = [];
|
|
||||||
this._responseHeaders = null;
|
|
||||||
this._loadedBytes = 0;
|
|
||||||
this._totalBytes = 0;
|
|
||||||
this._lengthComputable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setRequestHeader(name: string, value: any) {
|
|
||||||
if (this.readyState !== XMLHttpRequest.OPENED) { throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED'); }
|
|
||||||
|
|
||||||
const loweredName = name.toLowerCase();
|
|
||||||
if (this._restrictedHeaders[loweredName] || /^sec-/.test(loweredName) || /^proxy-/.test(loweredName)) {
|
|
||||||
console.warn(`Refused to set unsafe header "${name}"`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = value.toString();
|
|
||||||
if (this._loweredHeaders[loweredName] != null) {
|
|
||||||
name = this._loweredHeaders[loweredName];
|
|
||||||
this._headers[name] = `${this._headers[name]}, ${value}`;
|
|
||||||
} else {
|
|
||||||
this._loweredHeaders[loweredName] = name;
|
|
||||||
this._headers[name] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
send(data?: string | Buffer | ArrayBuffer | ArrayBufferView) {
|
|
||||||
if (this.readyState !== XMLHttpRequest.OPENED) { throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED'); }
|
|
||||||
if (this._request) { throw new XMLHttpRequest.InvalidStateError('send() already called'); }
|
|
||||||
|
|
||||||
switch (this._url.protocol) {
|
|
||||||
case 'file:':
|
|
||||||
return this._sendFile(data);
|
|
||||||
case 'http:':
|
|
||||||
case 'https:':
|
|
||||||
return this._sendHttp(data);
|
|
||||||
default:
|
|
||||||
throw new XMLHttpRequest.NetworkError(`Unsupported protocol ${this._url.protocol}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abort() {
|
|
||||||
if (this._request == null) { return; }
|
|
||||||
|
|
||||||
this._request.abort();
|
|
||||||
this._setError();
|
|
||||||
|
|
||||||
this._dispatchProgress('abort');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
}
|
|
||||||
|
|
||||||
getResponseHeader(name: string) {
|
|
||||||
if (this._responseHeaders == null || name == null) { return null; }
|
|
||||||
const loweredName = name.toLowerCase();
|
|
||||||
return this._responseHeaders.hasOwnProperty(loweredName)
|
|
||||||
? this._responseHeaders[name.toLowerCase()]
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllResponseHeaders() {
|
|
||||||
if (this._responseHeaders == null) { return ''; }
|
|
||||||
return Object.keys(this._responseHeaders).map(key => `${key}: ${this._responseHeaders[key]}`).join('\r\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
overrideMimeType(mimeType: string) {
|
|
||||||
if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) { throw new XMLHttpRequest.InvalidStateError('overrideMimeType() not allowed in LOADING or DONE'); }
|
|
||||||
this._mimeOverride = mimeType.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodejsSet(options: {httpAgent?: HttpAgent, httpsAgent?: HttpsAgent, baseUrl?: string }) {
|
|
||||||
this.nodejsHttpAgent = options.httpAgent || this.nodejsHttpAgent;
|
|
||||||
this.nodejsHttpsAgent = options.httpsAgent || this.nodejsHttpsAgent;
|
|
||||||
if (options.hasOwnProperty('baseUrl')) {
|
|
||||||
if (options.baseUrl != null) {
|
|
||||||
const parsedUrl = url.parse(options.baseUrl, false, true);
|
|
||||||
if (!parsedUrl.protocol) {
|
|
||||||
throw new XMLHttpRequest.SyntaxError("baseUrl must be an absolute URL")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.nodejsBaseUrl = options.baseUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static nodejsSet(options: {httpAgent?: HttpAgent, httpsAgent?: HttpsAgent, baseUrl?: string }) {
|
|
||||||
XMLHttpRequest.prototype.nodejsSet(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setReadyState(readyState: number) {
|
|
||||||
this.readyState = readyState;
|
|
||||||
this.dispatchEvent(new ProgressEvent('readystatechange'));
|
|
||||||
}
|
|
||||||
|
|
||||||
private _sendFile(data: any) {
|
|
||||||
// TODO
|
|
||||||
throw new Error('Protocol file: not implemented');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _sendHttp(data?: string | Buffer | ArrayBuffer | ArrayBufferView) {
|
|
||||||
if (this._sync) { throw new Error('Synchronous XHR processing not implemented'); }
|
|
||||||
if (data && (this._method === 'GET' || this._method === 'HEAD')) {
|
|
||||||
console.warn(`Discarding entity body for ${this._method} requests`);
|
|
||||||
data = null;
|
|
||||||
} else {
|
|
||||||
data = data || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.upload._setData(data);
|
|
||||||
this._finalizeHeaders();
|
|
||||||
this._sendHxxpRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _sendHxxpRequest() {
|
|
||||||
if (this.withCredentials) {
|
|
||||||
const cookie = XMLHttpRequest.cookieJar
|
|
||||||
.getCookies(
|
|
||||||
Cookie.CookieAccessInfo(this._url.hostname, this._url.pathname, this._url.protocol === 'https:')
|
|
||||||
).toValueString();
|
|
||||||
|
|
||||||
this._headers.cookie = this._headers.cookie2 = cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [hxxp, agent] = this._url.protocol === 'http:' ? [http, this.nodejsHttpAgent] : [https, this.nodejsHttpsAgent];
|
|
||||||
const requestMethod: (options: RequestOptionsHttp) => ClientRequest = hxxp.request.bind(hxxp);
|
|
||||||
const request = requestMethod({
|
|
||||||
hostname: this._url.hostname,
|
|
||||||
port: +this._url.port,
|
|
||||||
path: this._url.path,
|
|
||||||
auth: this._url.auth,
|
|
||||||
method: this._method,
|
|
||||||
headers: this._headers,
|
|
||||||
agent
|
|
||||||
});
|
|
||||||
this._request = request;
|
|
||||||
|
|
||||||
if (this.timeout) { request.setTimeout(this.timeout, () => this._onHttpTimeout(request)); }
|
|
||||||
request.on('response', response => this._onHttpResponse(request, response));
|
|
||||||
request.on('error', error => this._onHttpRequestError(request, error));
|
|
||||||
this.upload._startUpload(request);
|
|
||||||
|
|
||||||
if (this._request === request) { this._dispatchProgress('loadstart'); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private _finalizeHeaders() {
|
|
||||||
this._headers = {
|
|
||||||
...this._headers,
|
|
||||||
Connection: 'keep-alive',
|
|
||||||
Host: this._url.host,
|
|
||||||
'User-Agent': this._userAgent,
|
|
||||||
...this._anonymous ? {Referer: 'about:blank'} : {}
|
|
||||||
};
|
|
||||||
this.upload._finalizeHeaders(this._headers, this._loweredHeaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHttpResponse(request: ClientRequest, response: IncomingMessage) {
|
|
||||||
if (this._request !== request) { return; }
|
|
||||||
|
|
||||||
if (this.withCredentials && (response.headers['set-cookie'] || response.headers['set-cookie2'])) {
|
|
||||||
XMLHttpRequest.cookieJar
|
|
||||||
.setCookies(response.headers['set-cookie'] || response.headers['set-cookie2']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([301, 302, 303, 307, 308].indexOf(response.statusCode) >= 0) {
|
|
||||||
this._url = this._parseUrl(response.headers.location);
|
|
||||||
this._method = 'GET';
|
|
||||||
if (this._loweredHeaders['content-type']) {
|
|
||||||
delete this._headers[this._loweredHeaders['content-type']];
|
|
||||||
delete this._loweredHeaders['content-type'];
|
|
||||||
}
|
|
||||||
if (this._headers['Content-Type'] != null) {
|
|
||||||
delete this._headers['Content-Type'];
|
|
||||||
}
|
|
||||||
delete this._headers['Content-Length'];
|
|
||||||
|
|
||||||
this.upload._reset();
|
|
||||||
this._finalizeHeaders();
|
|
||||||
this._sendHxxpRequest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._response = response;
|
|
||||||
this._response.on('data', data => this._onHttpResponseData(response, data));
|
|
||||||
this._response.on('end', () => this._onHttpResponseEnd(response));
|
|
||||||
this._response.on('close', () => this._onHttpResponseClose(response));
|
|
||||||
|
|
||||||
this.responseUrl = this._url.href.split('#')[0];
|
|
||||||
this.status = response.statusCode;
|
|
||||||
this.statusText = http.STATUS_CODES[this.status];
|
|
||||||
this._parseResponseHeaders(response);
|
|
||||||
|
|
||||||
const lengthString = this._responseHeaders['content-length'] || '';
|
|
||||||
this._totalBytes = +lengthString;
|
|
||||||
this._lengthComputable = !!lengthString;
|
|
||||||
|
|
||||||
this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHttpResponseData(response: IncomingMessage, data: string | Buffer) {
|
|
||||||
if (this._response !== response) { return; }
|
|
||||||
|
|
||||||
this._responseParts.push(Buffer.from(data as any));
|
|
||||||
this._loadedBytes += data.length;
|
|
||||||
|
|
||||||
if (this.readyState !== XMLHttpRequest.LOADING) {
|
|
||||||
this._setReadyState(XMLHttpRequest.LOADING);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._dispatchProgress('progress');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHttpResponseEnd(response: IncomingMessage) {
|
|
||||||
if (this._response !== response) { return; }
|
|
||||||
|
|
||||||
this._parseResponse();
|
|
||||||
this._request = null;
|
|
||||||
this._response = null;
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
|
|
||||||
this._dispatchProgress('load');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHttpResponseClose(response: IncomingMessage) {
|
|
||||||
if (this._response !== response) { return; }
|
|
||||||
|
|
||||||
const request = this._request;
|
|
||||||
this._setError();
|
|
||||||
request.abort();
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
|
|
||||||
this._dispatchProgress('error');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHttpTimeout(request: ClientRequest) {
|
|
||||||
if (this._request !== request) { return; }
|
|
||||||
|
|
||||||
this._setError();
|
|
||||||
request.abort();
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
|
|
||||||
this._dispatchProgress('timeout');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHttpRequestError(request: ClientRequest, error: Error) {
|
|
||||||
if (this._request !== request) { return; }
|
|
||||||
|
|
||||||
this._setError();
|
|
||||||
request.abort();
|
|
||||||
this._setReadyState(XMLHttpRequest.DONE);
|
|
||||||
|
|
||||||
this._dispatchProgress('error');
|
|
||||||
this._dispatchProgress('loadend');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dispatchProgress(eventType: string) {
|
|
||||||
const event = new XMLHttpRequest.ProgressEvent(eventType);
|
|
||||||
event.lengthComputable = this._lengthComputable;
|
|
||||||
event.loaded = this._loadedBytes;
|
|
||||||
event.total = this._totalBytes;
|
|
||||||
this.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setError() {
|
|
||||||
this._request = null;
|
|
||||||
this._response = null;
|
|
||||||
this._responseHeaders = null;
|
|
||||||
this._responseParts = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _parseUrl(urlString: string, user?: string, password?: string) {
|
|
||||||
const absoluteUrl = this.nodejsBaseUrl == null ? urlString : url.resolve(this.nodejsBaseUrl, urlString);
|
|
||||||
const xhrUrl: XHRUrl = url.parse(absoluteUrl, false, true);
|
|
||||||
|
|
||||||
xhrUrl.hash = null;
|
|
||||||
|
|
||||||
const [xhrUser, xhrPassword] = (xhrUrl.auth || '').split(':');
|
|
||||||
if (xhrUser || xhrPassword || user || password) {
|
|
||||||
xhrUrl.auth = `${user || xhrUser || ''}:${password || xhrPassword || ''}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xhrUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _parseResponseHeaders(response: IncomingMessage) {
|
|
||||||
this._responseHeaders = {};
|
|
||||||
for (let name in response.headers) {
|
|
||||||
const loweredName = name.toLowerCase();
|
|
||||||
if (this._privateHeaders[loweredName]) { continue; }
|
|
||||||
this._responseHeaders[loweredName] = response.headers[name];
|
|
||||||
}
|
|
||||||
if (this._mimeOverride != null) {
|
|
||||||
this._responseHeaders['content-type'] = this._mimeOverride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _parseResponse() {
|
|
||||||
const buffer = Buffer.concat(this._responseParts);
|
|
||||||
this._responseParts = null;
|
|
||||||
|
|
||||||
switch (this.responseType) {
|
|
||||||
case 'json':
|
|
||||||
this.responseText = null;
|
|
||||||
try {
|
|
||||||
this.response = JSON.parse(buffer.toString('utf-8'));
|
|
||||||
} catch {
|
|
||||||
this.response = null;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case 'buffer':
|
|
||||||
this.responseText = null;
|
|
||||||
this.response = buffer;
|
|
||||||
return;
|
|
||||||
case 'arraybuffer':
|
|
||||||
this.responseText = null;
|
|
||||||
const arrayBuffer = new ArrayBuffer(buffer.length);
|
|
||||||
const view = new Uint8Array(arrayBuffer);
|
|
||||||
for (let i = 0; i < buffer.length; i++) { view[i] = buffer[i]; }
|
|
||||||
this.response = arrayBuffer;
|
|
||||||
return;
|
|
||||||
case 'text':
|
|
||||||
default:
|
|
||||||
try {
|
|
||||||
this.responseText = buffer.toString(this._parseResponseEncoding());
|
|
||||||
} catch {
|
|
||||||
this.responseText = buffer.toString('binary');
|
|
||||||
}
|
|
||||||
this.response = this.responseText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _parseResponseEncoding() {
|
|
||||||
return /;\s*charset=(.*)$/.exec(this._responseHeaders['content-type'] || '')[1] || 'utf-8';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLHttpRequest.prototype.nodejsHttpAgent = http.globalAgent;
|
|
||||||
XMLHttpRequest.prototype.nodejsHttpsAgent = https.globalAgent;
|
|
||||||
XMLHttpRequest.prototype.nodejsBaseUrl = null;
|
|
File diff suppressed because it is too large
Load Diff
2171
local_modules/web3-providers-http/package-lock.json
generated
2171
local_modules/web3-providers-http/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "web3-providers-http",
|
|
||||||
"version": "1.6.1",
|
|
||||||
"description": "Module to handle web3 RPC connections over HTTP.",
|
|
||||||
"repository": "https://github.com/ethereum/web3.js/tree/1.x/packages/web3-providers-http",
|
|
||||||
"license": "LGPL-3.0",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"compile": "tsc -b tsconfig.json",
|
|
||||||
"dtslint": "dtslint --localTs ../../node_modules/typescript/lib types"
|
|
||||||
},
|
|
||||||
"types": "types/index.d.ts",
|
|
||||||
"main": "lib/index.js",
|
|
||||||
"dependencies": {
|
|
||||||
"web3-core-helpers": "1.6.1",
|
|
||||||
"xhr2-cookies": "file:local_modules/xhr2-cookies"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"dtslint": "^3.4.1",
|
|
||||||
"typescript": "^3.9.5"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of web3.js.
|
|
||||||
|
|
||||||
web3.js is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
web3.js is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/** @file httpprovider.js
|
|
||||||
* @authors:
|
|
||||||
* Marek Kotewicz <marek@parity.io>
|
|
||||||
* Marian Oancea
|
|
||||||
* Fabian Vogelsteller <fabian@ethereum.org>
|
|
||||||
* @date 2015
|
|
||||||
*/
|
|
||||||
|
|
||||||
var errors = require('web3-core-helpers').errors;
|
|
||||||
var XHR2 = require('xhr2-cookies').XMLHttpRequest; // jshint ignore: line
|
|
||||||
var http = require('http');
|
|
||||||
var https = require('https');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HttpProvider should be used to send rpc calls over http
|
|
||||||
*/
|
|
||||||
var HttpProvider = function HttpProvider(host, options) {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
this.withCredentials = options.withCredentials || false;
|
|
||||||
this.timeout = options.timeout || 0;
|
|
||||||
this.headers = options.headers;
|
|
||||||
this.agent = options.agent;
|
|
||||||
this.connected = false;
|
|
||||||
|
|
||||||
// keepAlive is true unless explicitly set to false
|
|
||||||
const keepAlive = options.keepAlive !== false;
|
|
||||||
this.host = host || 'http://localhost:8545';
|
|
||||||
if (!this.agent) {
|
|
||||||
if (this.host.substring(0,5) === "https") {
|
|
||||||
this.httpsAgent = new https.Agent({ keepAlive });
|
|
||||||
} else {
|
|
||||||
this.httpAgent = new http.Agent({ keepAlive });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpProvider.prototype._prepareRequest = function(){
|
|
||||||
var request;
|
|
||||||
|
|
||||||
// the current runtime is a browser
|
|
||||||
if (typeof XMLHttpRequest !== 'undefined') {
|
|
||||||
request = new XMLHttpRequest();
|
|
||||||
} else {
|
|
||||||
request = new XHR2();
|
|
||||||
var agents = {httpsAgent: this.httpsAgent, httpAgent: this.httpAgent, baseUrl: this.baseUrl};
|
|
||||||
|
|
||||||
if (this.agent) {
|
|
||||||
agents.httpsAgent = this.agent.https;
|
|
||||||
agents.httpAgent = this.agent.http;
|
|
||||||
agents.baseUrl = this.agent.baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.nodejsSet(agents);
|
|
||||||
}
|
|
||||||
|
|
||||||
request.open('POST', this.host, true);
|
|
||||||
request.setRequestHeader('Content-Type','application/json');
|
|
||||||
request.timeout = this.timeout;
|
|
||||||
request.withCredentials = this.withCredentials;
|
|
||||||
|
|
||||||
if(this.headers) {
|
|
||||||
this.headers.forEach(function(header) {
|
|
||||||
request.setRequestHeader(header.name, header.value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be used to make async request
|
|
||||||
*
|
|
||||||
* @method send
|
|
||||||
* @param {Object} payload
|
|
||||||
* @param {Function} callback triggered on end with (err, result)
|
|
||||||
*/
|
|
||||||
HttpProvider.prototype.send = function (payload, callback) {
|
|
||||||
var _this = this;
|
|
||||||
var request = this._prepareRequest();
|
|
||||||
|
|
||||||
request.onreadystatechange = function() {
|
|
||||||
if (request.readyState === 4 && request.timeout !== 1) {
|
|
||||||
var result = request.responseText;
|
|
||||||
var error = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = JSON.parse(result);
|
|
||||||
} catch(e) {
|
|
||||||
error = errors.InvalidResponse(request.responseText);
|
|
||||||
}
|
|
||||||
|
|
||||||
_this.connected = true;
|
|
||||||
callback(error, result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
request.ontimeout = function() {
|
|
||||||
_this.connected = false;
|
|
||||||
callback(errors.ConnectionTimeout(this.timeout));
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
request.send(JSON.stringify(payload));
|
|
||||||
} catch(error) {
|
|
||||||
this.connected = false;
|
|
||||||
callback(errors.InvalidConnection(this.host));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpProvider.prototype.disconnect = function () {
|
|
||||||
//NO OP
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the desired boolean.
|
|
||||||
*
|
|
||||||
* @method supportsSubscriptions
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
HttpProvider.prototype.supportsSubscriptions = function () {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = HttpProvider;
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./lib"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"./src"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of web3.js.
|
|
||||||
|
|
||||||
web3.js is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
web3.js is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file index.d.ts
|
|
||||||
* @author Josh Stevens <joshstevens19@hotmail.co.uk>
|
|
||||||
* @date 2018
|
|
||||||
*/
|
|
||||||
import * as http from 'http';
|
|
||||||
import * as https from 'https';
|
|
||||||
|
|
||||||
import { HttpProviderBase, JsonRpcResponse } from 'web3-core-helpers';
|
|
||||||
|
|
||||||
export interface HttpHeader {
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HttpProviderAgent {
|
|
||||||
baseUrl?: string;
|
|
||||||
http?: http.Agent;
|
|
||||||
https?: https.Agent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HttpProviderOptions {
|
|
||||||
withCredentials?: boolean;
|
|
||||||
timeout?: number;
|
|
||||||
headers?: HttpHeader[];
|
|
||||||
agent?: HttpProviderAgent;
|
|
||||||
keepAlive?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HttpProvider extends HttpProviderBase {
|
|
||||||
host: string;
|
|
||||||
|
|
||||||
withCredentials: boolean;
|
|
||||||
timeout: number;
|
|
||||||
headers?: HttpHeader[];
|
|
||||||
agent?: HttpProviderAgent;
|
|
||||||
connected: boolean;
|
|
||||||
|
|
||||||
constructor(host?: string, options?: HttpProviderOptions);
|
|
||||||
|
|
||||||
send(
|
|
||||||
payload: object,
|
|
||||||
callback?: (
|
|
||||||
error: Error | null,
|
|
||||||
result: JsonRpcResponse | undefined
|
|
||||||
) => void
|
|
||||||
): void;
|
|
||||||
disconnect(): boolean;
|
|
||||||
supportsSubscriptions(): boolean;
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of web3.js.
|
|
||||||
|
|
||||||
web3.js is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
web3.js is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file web3-provider-http-tests.ts
|
|
||||||
* @author Josh Stevens <joshstevens19@hotmail.co.uk> , Samuel Furter <samuel@ethereum.org>
|
|
||||||
* @date 2018
|
|
||||||
*/
|
|
||||||
|
|
||||||
import * as http from 'http';
|
|
||||||
import * as https from 'https';
|
|
||||||
import { HttpProvider } from 'web3-providers';
|
|
||||||
import { JsonRpcResponse } from 'web3-core-helpers';
|
|
||||||
|
|
||||||
const httpProvider = new HttpProvider('http://localhost:8545', {
|
|
||||||
timeout: 20000,
|
|
||||||
headers: [
|
|
||||||
{
|
|
||||||
name: 'Access-Control-Allow-Origin',
|
|
||||||
value: '*'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
withCredentials: false,
|
|
||||||
agent: {
|
|
||||||
baseUrl: 'base',
|
|
||||||
http: new http.Agent({}),
|
|
||||||
https: new https.Agent({})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// $ExpectType void
|
|
||||||
httpProvider.send({}, (error: Error | null) => {});
|
|
||||||
|
|
||||||
// $ExpectType void
|
|
||||||
httpProvider.send({}, (error: Error | null, result: JsonRpcResponse | undefined) => {});
|
|
||||||
|
|
||||||
// $ExpectType boolean
|
|
||||||
httpProvider.disconnect();
|
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"lib": ["es6"],
|
|
||||||
"target": "es6",
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"noImplicitThis": true,
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"strictFunctionTypes": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"allowSyntheticDefaultImports": false,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"web3-providers": ["."]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "dtslint/dtslint.json",
|
|
||||||
"rules": {
|
|
||||||
"semicolon": false,
|
|
||||||
"no-import-default-of-export-equals": false,
|
|
||||||
"file-name-casing": [true, "kebab-case"],
|
|
||||||
"whitespace": false,
|
|
||||||
"no-unnecessary-class": false
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,6 +10,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ethersproject/transactions": "^5.7.0",
|
||||||
"@tornado/circomlib": "0.0.20-p2",
|
"@tornado/circomlib": "0.0.20-p2",
|
||||||
"@tornado/fixed-merkle-tree": "0.6.1-p1",
|
"@tornado/fixed-merkle-tree": "0.6.1-p1",
|
||||||
"@tornado/gas-price-oracle": "0.5.2-p1",
|
"@tornado/gas-price-oracle": "0.5.2-p1",
|
||||||
|
Loading…
Reference in New Issue
Block a user