| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 | const path = require('path')const http = require('http')const https = require('https')const followRedirects = require('follow-redirects')const qs = require('querystring')const zlib = require('zlib')const {URL} = require('url')const CentraResponse = require('./CentraResponse.js')const supportedCompressions = ['gzip', 'deflate', 'br']const useRequest = (protocol, maxRedirects) => {	let httpr	let httpsr	if (maxRedirects <= 0) {		httpr = http.request		httpsr = https.request	}	else {		httpr = followRedirects.http.request		httpsr = followRedirects.https.request	}	if (protocol === 'http:') {		return httpr	}	else if (protocol === 'https:') {		return httpsr	}	else throw new Error('Bad URL protocol: ' + protocol)}module.exports = class CentraRequest {	constructor (url, method = 'GET') {		this.url = typeof url === 'string' ? new URL(url) : url		this.method = method		this.data = null		this.sendDataAs = null		this.reqHeaders = {}		this.streamEnabled = false		this.compressionEnabled = false		this.timeoutTime = null		this.coreOptions = {}		this.maxRedirects = 0		this.resOptions = {			'maxBuffer': 50 * 1000000 // 50 MB		}		return this	}	followRedirects(n) {		this.maxRedirects = n		return this	}	query (a1, a2) {		if (typeof a1 === 'object') {			Object.keys(a1).forEach((queryKey) => {				this.url.searchParams.append(queryKey, a1[queryKey])			})		}		else this.url.searchParams.append(a1, a2)		return this	}	path (relativePath) {		this.url.pathname = path.join(this.url.pathname, relativePath)		return this	}	body (data, sendAs) {		this.sendDataAs = typeof data === 'object' && !sendAs && !Buffer.isBuffer(data) ? 'json' : (sendAs ? sendAs.toLowerCase() : 'buffer')		this.data = this.sendDataAs === 'form' ? qs.stringify(data) : (this.sendDataAs === 'json' ? JSON.stringify(data) : data)		return this	}	header (a1, a2) {		if (typeof a1 === 'object') {			Object.keys(a1).forEach((headerName) => {				this.reqHeaders[headerName.toLowerCase()] = a1[headerName]			})		}		else this.reqHeaders[a1.toLowerCase()] = a2		return this	}	timeout (timeout) {		this.timeoutTime = timeout		return this	}	option (name, value) {		this.coreOptions[name] = value		return this	}	stream () {		this.streamEnabled = true		return this	}	compress () {		this.compressionEnabled = true		if (!this.reqHeaders['accept-encoding']) this.reqHeaders['accept-encoding'] = supportedCompressions.join(', ')		return this	}	send () {		return new Promise((resolve, reject) => {			if (this.data) {				if (!this.reqHeaders.hasOwnProperty('content-type')) {					if (this.sendDataAs === 'json') {						this.reqHeaders['content-type'] = 'application/json'					}					else if (this.sendDataAs === 'form') {						this.reqHeaders['content-type'] = 'application/x-www-form-urlencoded'					}				}				if (!this.reqHeaders.hasOwnProperty('content-length')) {					this.reqHeaders['content-length'] = Buffer.byteLength(this.data)				}			}			const options = Object.assign({				'protocol': this.url.protocol,				'host': this.url.hostname.replace('[', '').replace(']', ''),				'port': this.url.port,				'path': this.url.pathname + (this.url.search === null ? '' : this.url.search),				'method': this.method,				'headers': this.reqHeaders,				'maxRedirects': this.maxRedirects			}, this.coreOptions)			let req			const resHandler = (res) => {				let stream = res				if (this.compressionEnabled) {					if (res.headers['content-encoding'] === 'gzip') {						stream = res.pipe(zlib.createGunzip())					}					else if (res.headers['content-encoding'] === 'deflate') {						stream = res.pipe(zlib.createInflate())					}					else if (res.headers['content-encoding'] === 'br') {						stream = res.pipe(zlib.createBrotliDecompress())					}				}				let centraRes				if (this.streamEnabled) {					resolve(stream)				}				else {					centraRes = new CentraResponse(res, this.resOptions)					stream.on('error', (err) => {						reject(err)					})					stream.on('aborted', () => {						reject(new Error('Server aborted request'))					})					stream.on('data', (chunk) => {						centraRes._addChunk(chunk)						if (this.resOptions.maxBuffer !== null && centraRes.body.length > this.resOptions.maxBuffer) {							stream.destroy()							reject('Received a response which was longer than acceptable when buffering. (' + this.body.length + ' bytes)')						}					})					stream.on('end', () => {						resolve(centraRes)					})				}			}			const request = useRequest(this.url.protocol, this.maxRedirects)			req = request(options, resHandler)			if (this.timeoutTime) {				req.setTimeout(this.timeoutTime, () => {					req.abort()					if (!this.streamEnabled) {						reject(new Error('Timeout reached'))					}				})			}			req.on('error', (err) => {				reject(err)			})			if (this.data) req.write(this.data)			req.end()		})	}}
 |