summaryrefslogtreecommitdiffstats
path: root/node_modules/stream-http/lib/request.js
diff options
context:
space:
mode:
authorGravatar Piotr Russ <mail@pruss.it> 2020-11-16 00:10:28 +0100
committerGravatar Piotr Russ <mail@pruss.it> 2020-11-16 00:10:28 +0100
commite06ec920f7a5d784e674c4c4b4e6d1da3dc7391d (patch)
tree55713f725f77b44ebfec86e4eec3ce33e71458ca /node_modules/stream-http/lib/request.js
downloadwebsite_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.gz
website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.bz2
website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.zip
api, login, auth
Diffstat (limited to 'node_modules/stream-http/lib/request.js')
-rw-r--r--node_modules/stream-http/lib/request.js327
1 files changed, 327 insertions, 0 deletions
diff --git a/node_modules/stream-http/lib/request.js b/node_modules/stream-http/lib/request.js
new file mode 100644
index 0000000..4f097df
--- /dev/null
+++ b/node_modules/stream-http/lib/request.js
@@ -0,0 +1,327 @@
+var capability = require('./capability')
+var inherits = require('inherits')
+var response = require('./response')
+var stream = require('readable-stream')
+var toArrayBuffer = require('to-arraybuffer')
+
+var IncomingMessage = response.IncomingMessage
+var rStates = response.readyStates
+
+function decideMode (preferBinary, useFetch) {
+ if (capability.fetch && useFetch) {
+ return 'fetch'
+ } else if (capability.mozchunkedarraybuffer) {
+ return 'moz-chunked-arraybuffer'
+ } else if (capability.msstream) {
+ return 'ms-stream'
+ } else if (capability.arraybuffer && preferBinary) {
+ return 'arraybuffer'
+ } else if (capability.vbArray && preferBinary) {
+ return 'text:vbarray'
+ } else {
+ return 'text'
+ }
+}
+
+var ClientRequest = module.exports = function (opts) {
+ var self = this
+ stream.Writable.call(self)
+
+ self._opts = opts
+ self._body = []
+ self._headers = {}
+ if (opts.auth)
+ self.setHeader('Authorization', 'Basic ' + new Buffer(opts.auth).toString('base64'))
+ Object.keys(opts.headers).forEach(function (name) {
+ self.setHeader(name, opts.headers[name])
+ })
+
+ var preferBinary
+ var useFetch = true
+ if (opts.mode === 'disable-fetch' || ('requestTimeout' in opts && !capability.abortController)) {
+ // If the use of XHR should be preferred. Not typically needed.
+ useFetch = false
+ preferBinary = true
+ } else if (opts.mode === 'prefer-streaming') {
+ // If streaming is a high priority but binary compatibility and
+ // the accuracy of the 'content-type' header aren't
+ preferBinary = false
+ } else if (opts.mode === 'allow-wrong-content-type') {
+ // If streaming is more important than preserving the 'content-type' header
+ preferBinary = !capability.overrideMimeType
+ } else if (!opts.mode || opts.mode === 'default' || opts.mode === 'prefer-fast') {
+ // Use binary if text streaming may corrupt data or the content-type header, or for speed
+ preferBinary = true
+ } else {
+ throw new Error('Invalid value for opts.mode')
+ }
+ self._mode = decideMode(preferBinary, useFetch)
+ self._fetchTimer = null
+
+ self.on('finish', function () {
+ self._onFinish()
+ })
+}
+
+inherits(ClientRequest, stream.Writable)
+
+ClientRequest.prototype.setHeader = function (name, value) {
+ var self = this
+ var lowerName = name.toLowerCase()
+ // This check is not necessary, but it prevents warnings from browsers about setting unsafe
+ // headers. To be honest I'm not entirely sure hiding these warnings is a good thing, but
+ // http-browserify did it, so I will too.
+ if (unsafeHeaders.indexOf(lowerName) !== -1)
+ return
+
+ self._headers[lowerName] = {
+ name: name,
+ value: value
+ }
+}
+
+ClientRequest.prototype.getHeader = function (name) {
+ var header = this._headers[name.toLowerCase()]
+ if (header)
+ return header.value
+ return null
+}
+
+ClientRequest.prototype.removeHeader = function (name) {
+ var self = this
+ delete self._headers[name.toLowerCase()]
+}
+
+ClientRequest.prototype._onFinish = function () {
+ var self = this
+
+ if (self._destroyed)
+ return
+ var opts = self._opts
+
+ var headersObj = self._headers
+ var body = null
+ if (opts.method !== 'GET' && opts.method !== 'HEAD') {
+ if (capability.arraybuffer) {
+ body = toArrayBuffer(Buffer.concat(self._body))
+ } else if (capability.blobConstructor) {
+ body = new global.Blob(self._body.map(function (buffer) {
+ return toArrayBuffer(buffer)
+ }), {
+ type: (headersObj['content-type'] || {}).value || ''
+ })
+ } else {
+ // get utf8 string
+ body = Buffer.concat(self._body).toString()
+ }
+ }
+
+ // create flattened list of headers
+ var headersList = []
+ Object.keys(headersObj).forEach(function (keyName) {
+ var name = headersObj[keyName].name
+ var value = headersObj[keyName].value
+ if (Array.isArray(value)) {
+ value.forEach(function (v) {
+ headersList.push([name, v])
+ })
+ } else {
+ headersList.push([name, value])
+ }
+ })
+
+ if (self._mode === 'fetch') {
+ var signal = null
+ var fetchTimer = null
+ if (capability.abortController) {
+ var controller = new AbortController()
+ signal = controller.signal
+ self._fetchAbortController = controller
+
+ if ('requestTimeout' in opts && opts.requestTimeout !== 0) {
+ self._fetchTimer = global.setTimeout(function () {
+ self.emit('requestTimeout')
+ if (self._fetchAbortController)
+ self._fetchAbortController.abort()
+ }, opts.requestTimeout)
+ }
+ }
+
+ global.fetch(self._opts.url, {
+ method: self._opts.method,
+ headers: headersList,
+ body: body || undefined,
+ mode: 'cors',
+ credentials: opts.withCredentials ? 'include' : 'same-origin',
+ signal: signal
+ }).then(function (response) {
+ self._fetchResponse = response
+ self._connect()
+ }, function (reason) {
+ global.clearTimeout(self._fetchTimer)
+ if (!self._destroyed)
+ self.emit('error', reason)
+ })
+ } else {
+ var xhr = self._xhr = new global.XMLHttpRequest()
+ try {
+ xhr.open(self._opts.method, self._opts.url, true)
+ } catch (err) {
+ process.nextTick(function () {
+ self.emit('error', err)
+ })
+ return
+ }
+
+ // Can't set responseType on really old browsers
+ if ('responseType' in xhr)
+ xhr.responseType = self._mode.split(':')[0]
+
+ if ('withCredentials' in xhr)
+ xhr.withCredentials = !!opts.withCredentials
+
+ if (self._mode === 'text' && 'overrideMimeType' in xhr)
+ xhr.overrideMimeType('text/plain; charset=x-user-defined')
+
+ if ('requestTimeout' in opts) {
+ xhr.timeout = opts.requestTimeout
+ xhr.ontimeout = function () {
+ self.emit('requestTimeout')
+ }
+ }
+
+ headersList.forEach(function (header) {
+ xhr.setRequestHeader(header[0], header[1])
+ })
+
+ self._response = null
+ xhr.onreadystatechange = function () {
+ switch (xhr.readyState) {
+ case rStates.LOADING:
+ case rStates.DONE:
+ self._onXHRProgress()
+ break
+ }
+ }
+ // Necessary for streaming in Firefox, since xhr.response is ONLY defined
+ // in onprogress, not in onreadystatechange with xhr.readyState = 3
+ if (self._mode === 'moz-chunked-arraybuffer') {
+ xhr.onprogress = function () {
+ self._onXHRProgress()
+ }
+ }
+
+ xhr.onerror = function () {
+ if (self._destroyed)
+ return
+ self.emit('error', new Error('XHR error'))
+ }
+
+ try {
+ xhr.send(body)
+ } catch (err) {
+ process.nextTick(function () {
+ self.emit('error', err)
+ })
+ return
+ }
+ }
+}
+
+/**
+ * Checks if xhr.status is readable and non-zero, indicating no error.
+ * Even though the spec says it should be available in readyState 3,
+ * accessing it throws an exception in IE8
+ */
+function statusValid (xhr) {
+ try {
+ var status = xhr.status
+ return (status !== null && status !== 0)
+ } catch (e) {
+ return false
+ }
+}
+
+ClientRequest.prototype._onXHRProgress = function () {
+ var self = this
+
+ if (!statusValid(self._xhr) || self._destroyed)
+ return
+
+ if (!self._response)
+ self._connect()
+
+ self._response._onXHRProgress()
+}
+
+ClientRequest.prototype._connect = function () {
+ var self = this
+
+ if (self._destroyed)
+ return
+
+ self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode, self._fetchTimer)
+ self._response.on('error', function(err) {
+ self.emit('error', err)
+ })
+
+ self.emit('response', self._response)
+}
+
+ClientRequest.prototype._write = function (chunk, encoding, cb) {
+ var self = this
+
+ self._body.push(chunk)
+ cb()
+}
+
+ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function () {
+ var self = this
+ self._destroyed = true
+ global.clearTimeout(self._fetchTimer)
+ if (self._response)
+ self._response._destroyed = true
+ if (self._xhr)
+ self._xhr.abort()
+ else if (self._fetchAbortController)
+ self._fetchAbortController.abort()
+}
+
+ClientRequest.prototype.end = function (data, encoding, cb) {
+ var self = this
+ if (typeof data === 'function') {
+ cb = data
+ data = undefined
+ }
+
+ stream.Writable.prototype.end.call(self, data, encoding, cb)
+}
+
+ClientRequest.prototype.flushHeaders = function () {}
+ClientRequest.prototype.setTimeout = function () {}
+ClientRequest.prototype.setNoDelay = function () {}
+ClientRequest.prototype.setSocketKeepAlive = function () {}
+
+// Taken from http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method
+var unsafeHeaders = [
+ 'accept-charset',
+ 'accept-encoding',
+ 'access-control-request-headers',
+ 'access-control-request-method',
+ 'connection',
+ 'content-length',
+ 'cookie',
+ 'cookie2',
+ 'date',
+ 'dnt',
+ 'expect',
+ 'host',
+ 'keep-alive',
+ 'origin',
+ 'referer',
+ 'te',
+ 'trailer',
+ 'transfer-encoding',
+ 'upgrade',
+ 'via'
+]