const {
// eslint-disable-next-line camelcase
req_read, req_read_json, reg_getHeaders, reg_getMethod, reg_getUrl, reg_getURI, reg_getDecodedURI,
// eslint-disable-next-line camelcase
reg_getParameters, reg_getDecodedParameters, req_writeToFile, req_appendToFile
// eslint-disable-next-line n/no-deprecated-api
} = process.binding('http_server')
const queryString = require('querystring')
// eslint-disable-next-line n/no-deprecated-api
let reqGetReqId = process.binding('http_server').req_getReqId
if (!reqGetReqId) {
reqGetReqId = function () { return 0 }// fallback for UB<5.18.2
}
/**
* @classdesc
* An `THTTPRequest` object is created by UB server and passed as the first
* argument to the `endpoint's` methods or as a second argument to the `rest` entity method's event.
*
* It may be used to access HTTP request status, headers and data.
* @class THTTPRequest
* @implements {UBReader}
*/
class THTTPRequest {
/**
* @inheritdoc
* @param {string} [encoding]
*/
read (encoding) {
return req_read(encoding)
}
/**
* Return http request body content as JSON; Faster when JSON.parse(req.read()).
*
* Expect body to be in UTF8 encoding
*
* @returns {*}
*/
json () {
return req_read_json()
}
/**
* Write request body content (as binary) to a file. Return true on success
*
* @param {string} fullFilePath
* @param {string} [encoding='bin'] Can be 'bin'(default) or 'base64` - in this case
* request body will be converted from base64 into binary before write to file
* @returns {boolean}
*/
writeToFile (fullFilePath, encoding = 'bin') {
return req_writeToFile(fullFilePath, encoding)
}
/**
* Append request body content (as binary) to a file. If file does not exist - creates it. Return true on success
*
* @param {string} fullFilePath
* @param {string} [encoding='bin'] Can be 'bin'(default) or 'base64` - in this case
* request body will be converted from base64 into binary before write to file
* @returns {boolean}
*/
appendToFile (fullFilePath, encoding = 'bin') {
return req_appendToFile(fullFilePath, encoding)
}
/**
* HTTP request headers.
*
* To get a single header value it is preferred to use `req.getHeader(name)`
* To get all parsed headers as object - `req.getHeaders()`
*
* @type {string}
* @readonly
*/
get headers () {
if (this._headers === undefined) this._headers = reg_getHeaders()
return this._headers
}
/**
* Return a header value by name. Name is case-insensitive
*
* @example
// incoming headers string 'Host: unitybase.info\r\nAccept-Encoding: gzip\r\n\r\nAccept-Encoding: deflate, br'
req.getHeader('accept-Encoding') // 'gzip, deflate, br
* @param {string} name Case-insensitive header name
* @returns {string|undefined}
* @since 5.19.0
*/
getHeader (name) {
if (!this._parsedHeaders) {
this._parsedHeaders = parseHeaders(this.headers)
}
return this._parsedHeaders[name.toLowerCase()]
}
/**
* Returns an array containing the unique names of the headers. All header names are lowercase
*
* @example
// incoming headers string 'Host: unitybase.info\r\nAccept-Encoding: gzip\r\n\r\nAccept-Encoding: deflate, br'
req.getHeaderNames() // ['host', 'accept-encoding']
* @returns {Array<string>}
* @since 5.19.0
*/
getHeaderNames () {
if (!this._parsedHeaders) {
this._parsedHeaders = parseHeaders(this.headers)
}
return Object.keys(this._parsedHeaders)
}
/**
* Return parsed headers object. Keys are lower-cased header names, values are header values
*
* @example
// incoming headers string 'Host: unitybase.info\r\nAccept-Encoding: gzip\r\n\r\nAccept-Encoding: deflate, br'
req.getHeaders() // {host: "unitybase.info", accept-encoding: "gzip, deflate, br"}
* @since 5.19.0
*/
getHeaders () {
if (!this._parsedHeaders) {
this._parsedHeaders = parseHeaders(this.headers)
}
return this._parsedHeaders
}
/**
* HTTP request method GET|POST|PUT......
*
* @type {string}
* @readonly
*/
get method () {
if (this._method === undefined) this._method = reg_getMethod()
return this._method
}
/**
* Full URL
*
* @example
// GET http://host:port/ub/rest/doc_document/report?id=1¶m2=asdas
req.url === 'ub/rest/doc_document/report?id=1¶m2=asdas'
* @type {string}
* @readonly
*/
get url () {
if (this._url === undefined) this._url = reg_getUrl()
return this._url
}
/**
* URL WITHOUT appName and endpoint name
*
* @example
// GET http://host:port/ub/rest/doc_document/report?id=1¶m2=asdas
req.uri === 'doc_document/report'
* @type {string}
* @readonly
*/
get uri () {
if (this._uri === undefined) this._uri = reg_getURI()
return this._uri
}
/**
* The same as uri, but URLDecoded
*
* @example
//GET http://host:port/ub/rest/TripPinServiceRW/My%20People"
req.decodedUri === 'TripPinServiceRW/My People'
* @type {string}
* @readonly
*/
get decodedUri () {
if (this._decodedUri === undefined) this._decodedUri = reg_getDecodedURI()
return this._decodedUri
}
/**
* URL parameters as string. Better to use `req.parsedParameters` instead, what returns an object
*
* @example
// GET http://host:port/ub/rest/doc_document/report?id=1¶m2=asdas
req.parameters === 'id=1¶m2=asdas'
* @type {string}
* @readonly
*/
get parameters () {
if (this._parameters === undefined) this._parameters = reg_getParameters()
return this._parameters
}
/**
* URLDecoded parameters. Better to use `req.parsedParameters` instead, what returns an object
*
* @example
// GET http://host:port/bla-bla?$filter=Name%20eq%20%27John%27
req.parameters === '$filter=Name%20eq%20%27John%27'
req.decodedParameters === "$filter=Name eq 'John'"
* @type {string}
* @readonly
*/
get decodedParameters () {
if (this._decodedParameters === undefined) this._decodedParameters = reg_getDecodedParameters()
return this._decodedParameters
}
/**
* Return a parsed request parameters (decoded using querystring.parse()).
* Second call to parsedParameters uses cached result, so it faster than first
*
* @example
// for parameters 'foo=bar&baz=qux&baz=quux&corge' return
req.parsedParameters // { foo: 'bar', baz: ['qux', 'quux'], corge: '' }
* @returns {Object<string, string|Array<string>>}
* @since 5.19.0
*/
get parsedParameters () {
if (this._parsedParameters === undefined) this._parsedParameters = queryString.parse(reg_getParameters())
return this._parsedParameters
}
/**
* Unique HTTP request ID - the same value as used to fill a `uba_auditTrail.request_id`.
* In case audit trail is disabled in domain (uba_auditTrail entity not available) or Ub server version < 5.18.2 returns 0
*
* @readonly
* @returns {number}
* @since 5.18.2
*/
get requestId () {
return reqGetReqId()
}
}
/**
* Parse a headers string into object. Keys is lower cased header name.
*
* Values for the same header names a concatenated using comma
*
* @private
* @param {string} headers
* @returns {Object<string, string>}
*/
function parseHeaders (headers) {
const parsed = {}
if (!headers) return parsed
headers.split('\n').forEach(function (line) {
const i = line.indexOf(':')
const key = line.substr(0, i).trim().toLowerCase()
const val = line.substr(i + 1).trim()
if (key) {
if (parsed[key]) {
parsed[key] += ', ' + val
} else {
parsed[key] = val
}
}
})
return parsed
}
module.exports = THTTPRequest