// eslint-disable-next-line camelcase,n/no-deprecated-api
const { resp_writeHead, resp_write, resp_writeEnd, resp_writeBinaryBase64, resp_validateETag, resp_getStatus, resp_setStatus, resp_getBodyForDebug } = process.binding('http_server')
/**
* @classdesc
* This object is created internally by UB server and passed as the second
* argument to the `endpoint's` methods or as a third argument to the entity level method's called using `rest` endpoint.
*
* It represents an in-progress HTTP response.
* Response body is buffered during calls to {@link THTTPResponse#write write}
* until {@link THTTPResponse#writeEnd writeEnd} is called.
* Actual headers and response will be sent after endpoint handler finished.
*
* Do not forget to set the {@link THTTPResponse#statusCode statusCode} to 200 on success or use a helper's
* {@link THTTPResponse#badRequest badRequest} / {@link THTTPResponse#notFound notFound} on errors.
*
* TODO To send file content as a response without loading file into memory the following code can be used:
*
// Replace this comments by JSDocs style comment
// param {THTTPRequest} req
// param {THTTPResponse} resp
function getPublicDocument(req, resp){
resp.statusCode = 200;
resp.writeHead('Content-Type: !STATICFILE\r\nContent-Type: text/plain'); // !STATICFILE is a special content type - will be removed from headers by server during sending
resp.writeEnd('c:\\myFilesWithPasswords.txt');
}
* @class THTTPResponse
* @implements {UBWriter}
*/
class THTTPResponse {
/**
* Response HTTP status code
*
* @returns {number}
*/
get statusCode () {
return resp_getStatus()
}
/**
* @param {number} status
*/
set statusCode (status) {
resp_setStatus(status)
}
/**
* Add response header(s). Can be called several times for DIFFERENT header.
* Can write several headers at once - in this case usa `\r\n` as separator
*
*@example
* resp.writeHead('Content-Type: text/css; charset=UTF-8\r\nOther-header: value')
* @param {string} header One header or `\r\n` separated headers
*/
writeHead (header) {
resp_writeHead(header)
}
/**
* @inheritdoc
*/
write (data, encoding) {
resp_write(data, encoding)
}
/**
* Write base64 encoded data as a binary representation (will decode from base64 to binary before write to response)
*
* @param {string} base64Data
*/
writeBinaryBase64 (base64Data) {
resp_writeBinaryBase64(base64Data)
}
/**
* Write to internal buffer and set buffer content as HTTP response.
* See {UBWriter.wrote} for parameter details
*
* @param {ArrayBuffer | object | string} data
* @param {string} [encoding]
*/
writeEnd (data, encoding) {
resp_writeEnd(data, encoding)
}
/**
* For DEBUG PURPOSE ONLY
* Retrieve a response body created by writeEnd call
*
* @returns {string}
*/
getBodyForDebug () {
return resp_getBodyForDebug()
}
/**
* ETag based HTTP response caching.
* Must be called after writeEnd called and and statusCode is defined.
*
* In case statusCode === 200 and response body length > 64 will
* - if request contains a IF-NONE-MATCH header, and it value equal to response crc32
* will mutate a statusCode to 304 (not modified) and clear the response body
* - in other case will add a ETag header with value = hex representation of crc32(responseBody).
*/
validateETag () {
return resp_validateETag()
}
/**
* Write an HTTP 400 Bad Request response. Return false
*
* @param {string} [reason] If specified will be written to log as error
* @returns {boolean}
*/
badRequest (reason) {
this.statusCode = 400
this.writeHead('Content-Type: text/plain; charset=UTF-8')
this.writeEnd('Bad Request')
if (reason) console.error('Bad request', reason)
return false
}
/**
* Write an HTTP 404 Not Found response. Return false
*
* @param {string} [reason] If specified will be written to log as error
* @returns {boolean}
*/
notFound (reason) {
this.statusCode = 404
this.writeHead('Content-Type: text/plain; charset=UTF-8')
this.writeEnd('Not Found')
if (reason) console.error('Not found', reason)
return false
}
/**
* Write an HTTP 501 'Not Implemented response. Return false
*
* @param {string} [reason] If specified will be written to log as error
* @returns {boolean}
*/
notImplemented (reason) {
this.statusCode = 501
this.writeHead('Content-Type: text/plain; charset=UTF-8')
this.writeEnd('Not Implemented')
if (reason) console.error('Not Implemented', reason)
return false
}
}
module.exports = THTTPResponse