/
HTTPResponse.js
193 lines (176 loc) · 4.72 KB
/
HTTPResponse.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// (c) 2018, The Awesome Engineering Company, https://awesomeneg.com
"use strict";
const Readable = require("stream").Readable;
const AwesomeUtils = require("@awesomeeng/awesome-utils");
const AbstractResponse = require("../AbstractResponse");
/**
* A wrapper for the nodejs http ServerResponse object that is received
* when an incoming request comes into the server.
*
* @extends AbstractRequest
*/
class HTTPResponse extends AbstractResponse {
/**
* Constructor which takes the nodejs http ServerResponse and wraps
* it in a custom AbstractRequest object.
*
* @param {ServerResponse} request
*/
constructor(response) {
super(response);
}
/**
* Returns true when the response is finished (end() has been called)
* and cannot receive any more data/changes.
*
* @return {boolean}
*/
get finished() {
return this.original.finished;
}
/**
* Returns the status code set with writeHead for this response.
*
* @return {number}
*/
get statusCode() {
return this.original.statusCode;
}
/**
* Returns the headers set with writeHead for this response.
* @return {Object}
*/
get headers() {
return this.original.getHeaders();
}
/**
* Returns the mime-type portion from the Content-Type header.
*
* @return {String}
*/
get contentType() {
return AwesomeUtils.Request.parseContentType(this.headers && this.headers["Content-Type"] || "");
}
/**
* Returns the charset (encoding) portion from the Content-Type
* header for this response.
*
* @return {String}
*/
get contentEncoding() {
return AwesomeUtils.Request.parseContentEncoding(this.headers && this.headers["Content-Type"] || "");
}
/**
* Set a header for outgoing requests. Any header set via setHeader()
* is merged with any headers set by writeHead() before the final response
* is sent.
*
* @param {string} name
* @param {string} value
*/
setHeader(/*name,value*/) {
return this.original.setHeader.apply(this.original,arguments);
}
/**
* Sets the status code and headers for the response. This may only be
* called once per request and cannot be called after a write() or
* and end() has been called.
*
* Unlike write() and end() this does not return a Promise and does
* not need to be preceeded by an await.
*
* THe headers parameter should have the header keys as lower case.
*
* @param statusCode {number}
* @param statusMessage {(string|null)} optional.
* @param headers {Object} optional.
*/
writeHead(/*statusCode,statusMessage,headers*/) {
return this.original.writeHead.apply(this.original,arguments);
}
/**
* Writes a chunk of data to the response with the given encoding.
*
* Returns a Promise that will resolve when the write is complete.
* It is always good practice to await a write().
*
* @param data {(Buffer|string)}
* @param encoding {string} optional. Defaults to utf-8.
*
* @return {Promise}
*/
write(data,encoding) {
return new Promise((resolve,reject)=>{
try {
this.original.write(data,encoding,(err)=>{
if (err) reject(err);
else resolve();
});
}
catch (ex) {
return reject(ex);
}
});
}
/**
* Writes the passed in data to the response with the given encoding
* and then marks the response finished.
*
* Returns a Promise that will resolve when the end is complete.
* It is always good practice to await an end().
*
* @param data {(Buffer|string)}
* @param encoding {string} optional. Defaults to utf-8.
*
* @return {Promise}
*/
end(data,encoding) {
return new Promise((resolve,reject)=>{
try {
this.original.end(data,encoding,(err)=>{
if (err) reject(err);
else resolve();
});
}
catch (ex) {
return reject(ex);
}
});
}
/**
* Pipes the given Readable stream into the response object. writeHead()
* should be called prior to this.
*
* When the pipeFrom() is complete, end() is called and the response
* is marked finished.
*
* It is worth noting that pipeFrom() is different from nodejs Stream
* pipe() method in that pipe() takes as an argument the writable stream.
* pipeFrom() flips that and takes as an argument the readable stream.
*
* Returns a Promise that will resolve when the end of the stream has
* been sent and end() has been called. It is always good practice to
* await pipeFrom().
*
* @return {Promise}
*/
pipeFrom(readable) {
if (!readable) throw new Error("Missing readable.");
if (!(readable instanceof Readable)) throw new Error("Invalid readable.");
return new Promise((resolve,reject)=>{
try {
readable.on("end",async ()=>{
await this.end();
resolve();
});
readable.pipe(this.original,{
end:false
});
}
catch (ex) {
return reject(ex);
}
});
}
}
module.exports = HTTPResponse;