icore 0.1.38 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/argv.d.ts +14 -0
- package/dist/argv.d.ts.map +1 -0
- package/dist/argv.js +62 -0
- package/dist/argv.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +36 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +81 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +132 -0
- package/dist/commands.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/options.d.ts +119 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +132 -0
- package/dist/options.js.map +1 -0
- package/package.json +23 -25
- package/readme.md +591 -0
- package/README.md +0 -267
- package/index.js +0 -18
- package/src/application.js +0 -219
- package/src/async-function.js +0 -3
- package/src/inquiry.js +0 -141
- package/src/route.js +0 -109
package/README.md
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
# Iсore
|
|
2
|
-
|
|
3
|
-
[](https://github.com/woodger/icore/blob/master/LICENSE)
|
|
4
|
-
[](https://travis-ci.com/woodger/icore)
|
|
5
|
-
[](https://coveralls.io/github/woodger/icore?branch=master)
|
|
6
|
-
[](https://snyk.io/test/github/woodger/icore?targetFile=package.json)
|
|
7
|
-
|
|
8
|
-
`Icore` is a framework a high-level to build strict web application. Allows the developer to focus on the final handler.
|
|
9
|
-
|
|
10
|
-
## Features
|
|
11
|
-
|
|
12
|
-
This module for [Node.js®](https://nodejs.org) implemented by following the [ECMAScript® 2018 Language Specification Standard](https://www.ecma-international.org/ecma-262/9.0/index.html)
|
|
13
|
-
|
|
14
|
-
* strict interface
|
|
15
|
-
* not immutable context
|
|
16
|
-
* routing implements a binary tree
|
|
17
|
-
* all asynchronous functions on promises
|
|
18
|
-
* error handling
|
|
19
|
-
|
|
20
|
-
## Install
|
|
21
|
-
|
|
22
|
-
To use `iсore` in your project, run:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm i icore
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Table of Contents
|
|
29
|
-
|
|
30
|
-
[class Application](#class-application)
|
|
31
|
-
|
|
32
|
-
* [constructor: new Application(options)](#constructor-new-Applicationoptions)
|
|
33
|
-
* [app.listenHttp(router)](#applistenhttprouter)
|
|
34
|
-
* [app.close()](#appclose)
|
|
35
|
-
* [app.server](#appserver)
|
|
36
|
-
* [app.context](#appcontext)
|
|
37
|
-
|
|
38
|
-
[class Route](#class-route)
|
|
39
|
-
|
|
40
|
-
* [Event: 'error'](#event-error)
|
|
41
|
-
* [constructor: new Route(options)](#constructor-new-routeoptions)
|
|
42
|
-
* [route.route(options)](#routerouteoptions)
|
|
43
|
-
* [route.find(paths[, index])](#routefindpaths-index)
|
|
44
|
-
* [route.method](#routemethod)
|
|
45
|
-
* [route.handler](#routehandler)
|
|
46
|
-
* [route.finish](#routefinish)
|
|
47
|
-
* [route.childs](#routechilds)
|
|
48
|
-
|
|
49
|
-
[class Inquiry](#class-inquiry)
|
|
50
|
-
|
|
51
|
-
* [constructor: new Inquiry(req, cookie)](#constructor-new-inquiryreq-cookie)
|
|
52
|
-
* [inq.read(options)](#inqreadoptions)
|
|
53
|
-
* [inq.pipe(stream[, options])](#inqpipestream-options)
|
|
54
|
-
* [inq.queries](#inqqueries)
|
|
55
|
-
* [inq.method](#inqmethod)
|
|
56
|
-
* [inq.headers](#inqheaders)
|
|
57
|
-
* [inq.context](#inqcontext)
|
|
58
|
-
|
|
59
|
-
### class Application
|
|
60
|
-
|
|
61
|
-
#### constructor: new Application(options)
|
|
62
|
-
|
|
63
|
-
* `options` <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>
|
|
64
|
-
|
|
65
|
-
* `host` <[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)> To start the development server using a different default `hostname` or `IP address`. This will start a TCP server listening for connections on the provided host. **Default:** `'localhost'`.
|
|
66
|
-
|
|
67
|
-
* `port` <[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> TCP port of remote server. Is required parameter.
|
|
68
|
-
|
|
69
|
-
* `timeout` <[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> The number of milliseconds of inactivity before a socket is presumed to have timed out. A value of `0` will disable the timeout behavior on incoming connections. **Default:** `12e4` (2 minutes).
|
|
70
|
-
|
|
71
|
-
* `maxHeadersCount` <[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> Limits maximum incoming headers count. If set to `0`, no limit will be applied. **Default:** `2e3`.
|
|
72
|
-
|
|
73
|
-
For example:
|
|
74
|
-
|
|
75
|
-
```js
|
|
76
|
-
const icore = require('icore');
|
|
77
|
-
|
|
78
|
-
const app = new icore.Application({
|
|
79
|
-
port: 3000
|
|
80
|
-
});
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
#### app.listenHttp(router)
|
|
84
|
-
|
|
85
|
-
* `router` <[Router](#class-route)> Is instance class Route this module.
|
|
86
|
-
* returns: <[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)> Following successful listen, the Promise is resolved with an value with a `undefined`.
|
|
87
|
-
|
|
88
|
-
Starts the HTTP server listening for connections. These arguments are documented on [nodejs.org](https://nodejs.org/api/http.html#http_server_listen).
|
|
89
|
-
|
|
90
|
-
**index.js**
|
|
91
|
-
|
|
92
|
-
```js
|
|
93
|
-
const icore = require('icore');
|
|
94
|
-
const router = require('./router');
|
|
95
|
-
|
|
96
|
-
const app = new icore.Application({
|
|
97
|
-
port: 3000
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
app.listenHttp(router);
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Start script in terminal:
|
|
104
|
-
|
|
105
|
-
```console
|
|
106
|
-
$ node index.js
|
|
107
|
-
Server started on http://localhost:3000
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### app.close()
|
|
111
|
-
|
|
112
|
-
* returns: <[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)> Following successful listen, the Promise is resolved with an value with a `undefined`.
|
|
113
|
-
|
|
114
|
-
Stops the server from accepting new connections.
|
|
115
|
-
|
|
116
|
-
#### app.server
|
|
117
|
-
|
|
118
|
-
In this variable, an instance of the server will be assigned after a successful listen installation.
|
|
119
|
-
|
|
120
|
-
#### app.context
|
|
121
|
-
|
|
122
|
-
This empty <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>. You may add additional properties to [inq.context](#inqcontext) by editing `app.context`.
|
|
123
|
-
|
|
124
|
-
```js
|
|
125
|
-
app.context.db = db();
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
#### class Route
|
|
129
|
-
|
|
130
|
-
The router is made up of instances class `Route`.
|
|
131
|
-
|
|
132
|
-

|
|
133
|
-
|
|
134
|
-
Routing will be done:
|
|
135
|
-
|
|
136
|
-
| Method | URL |
|
|
137
|
-
|--------|----------------------------------|
|
|
138
|
-
| GET | http://example.com |
|
|
139
|
-
| GET | http://example.com/catalog |
|
|
140
|
-
| GET | http://example.com/logs_0 |
|
|
141
|
-
| GET | http://example.com/logs_1 |
|
|
142
|
-
| POST | http://example.com/catalog/books |
|
|
143
|
-
|
|
144
|
-
Extends the Node.js [events](https://nodejs.org/api/events.html) module.
|
|
145
|
-
|
|
146
|
-
##### Event: 'error'
|
|
147
|
-
|
|
148
|
-
The `'error'` event is emitted if throw an exception. The listener callback is passed a single `Error` argument when called.
|
|
149
|
-
The server is not closed when the `'error'` event is emitted.
|
|
150
|
-
|
|
151
|
-
##### constructor: new Route(options)
|
|
152
|
-
|
|
153
|
-
When defining a route in `icore` you need one basic element - the `handler`.
|
|
154
|
-
|
|
155
|
-
* `options` <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>
|
|
156
|
-
* `handler` <[AsyncFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)> takes an instance of a [class Inquiry](#class-inquiry) as context. The handler option must return a object, a promise, or throw an error.
|
|
157
|
-
* `path` <[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)> The path option must be a string, though it can contain regular expression. **Default:** `''`.
|
|
158
|
-
* `method` <[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)> The property of the method can be any valid HTTP method in lower case letters. **Default:** `'get'`.
|
|
159
|
-
* `finish` <[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)> If set to `true`, the find returns the current route. **Default:** `false`.
|
|
160
|
-
|
|
161
|
-
Simple example use Route class:
|
|
162
|
-
|
|
163
|
-
```js
|
|
164
|
-
const homepage = new Route({
|
|
165
|
-
async handler(inq) {
|
|
166
|
-
return {
|
|
167
|
-
status: 200,
|
|
168
|
-
header: {
|
|
169
|
-
'Content-Type': 'text/html; charset=utf-8'
|
|
170
|
-
},
|
|
171
|
-
body: 'Hello World!'
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
#### route.route(options)
|
|
178
|
-
|
|
179
|
-
Uses the same interface as the class constructor.
|
|
180
|
-
|
|
181
|
-
```js
|
|
182
|
-
const catalog = homepage.route({
|
|
183
|
-
method: 'catalog',
|
|
184
|
-
async handler(inq) {
|
|
185
|
-
return {};
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
#### route.find(paths[, index])
|
|
191
|
-
|
|
192
|
-
This method is intended for [class Application](#class-application) use.
|
|
193
|
-
|
|
194
|
-
* `paths` <[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)> The result of the transform of the URL.
|
|
195
|
-
* `index` <[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> Is cursor for next call find. **Default:** `0`.
|
|
196
|
-
* returns: <this> Returns `null` if the route is not found.
|
|
197
|
-
|
|
198
|
-
#### route.method
|
|
199
|
-
|
|
200
|
-
* <[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)> The property of the method can be any valid HTTP method in lower case letters. **Default:** `'get'`.
|
|
201
|
-
|
|
202
|
-
#### route.handler
|
|
203
|
-
|
|
204
|
-
* <[AsyncFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)> takes an instance of a [class Inquiry](#class-inquiry) as context. The handler option must return a object, a promise, or throw an error.
|
|
205
|
-
|
|
206
|
-
#### route.finish
|
|
207
|
-
|
|
208
|
-
* <[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)> If set to `true`, the find returns the current route. **Default:** `false`.
|
|
209
|
-
|
|
210
|
-
#### route.childs
|
|
211
|
-
|
|
212
|
-
* <[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)> Nested route list.
|
|
213
|
-
|
|
214
|
-
#### class Inquiry
|
|
215
|
-
|
|
216
|
-
A [class Application](#class-application) context encapsulates node's request and response objects into a single object which provides many helpful methods for writing web applications and APIs.
|
|
217
|
-
|
|
218
|
-
#### constructor: new Inquiry(req, cookie)
|
|
219
|
-
|
|
220
|
-
The constructor will be auto called whenever a new `request` is established.
|
|
221
|
-
|
|
222
|
-
* `req` <[http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)> Node's request object.
|
|
223
|
-
* `cookie` <[coookie.entries](https://www.npmjs.com/package/cookie-httponly#cookieentries)> The values of the incoming cookie.
|
|
224
|
-
|
|
225
|
-
#### inq.read(options)
|
|
226
|
-
|
|
227
|
-
* `options` <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>
|
|
228
|
-
* `maxSize` <[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> Limits the amount of memory all fields together (except files) can allocate in bytes. If this value is exceeded, an 'error' event is emitted. **Default:** `Infinity`.
|
|
229
|
-
* returns: <[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)> Following successful listen, the Promise is resolved with an value with a `string` type.
|
|
230
|
-
|
|
231
|
-
To start reading the body of the incoming message.
|
|
232
|
-
|
|
233
|
-
```js
|
|
234
|
-
async handler(inq) {
|
|
235
|
-
const data = await inq.read();
|
|
236
|
-
}
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
#### inq.pipe(stream[, options])
|
|
240
|
-
|
|
241
|
-
* `stream` <[stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable)>
|
|
242
|
-
* `options` <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>
|
|
243
|
-
* `maxSize` <[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> Limits the amount of memory all fields together (except files) can allocate in bytes. If this value is exceeded, an 'error' event is emitted. **Default:** `Infinity`.
|
|
244
|
-
|
|
245
|
-
To start reading the body of an incoming message as a stream
|
|
246
|
-
|
|
247
|
-
```js
|
|
248
|
-
async handler(inq) {
|
|
249
|
-
inq.pipe(writeStream);
|
|
250
|
-
}
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
#### inq.queries
|
|
254
|
-
|
|
255
|
-
* <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> Get raw query string void of `?`.
|
|
256
|
-
|
|
257
|
-
#### inq.method
|
|
258
|
-
|
|
259
|
-
* <[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)> The property of the method can be any valid HTTP method in lower case letters. **Default:** `'get'`.
|
|
260
|
-
|
|
261
|
-
#### inq.headers
|
|
262
|
-
|
|
263
|
-
* <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> Response header object.
|
|
264
|
-
|
|
265
|
-
#### inq.context
|
|
266
|
-
|
|
267
|
-
* <[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> Inherit [app.context](#appcontext)
|
package/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Icore is a framework a high-level to build strict web application
|
|
3
|
-
*
|
|
4
|
-
* This module for Node.js® implemented by following the ECMAScript® 2018
|
|
5
|
-
* Language Specification Standard
|
|
6
|
-
*
|
|
7
|
-
* https://www.ecma-international.org/ecma-262/9.0/index.html
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const Application = require('./src/application');
|
|
11
|
-
const Inquiry = require('./src/inquiry');
|
|
12
|
-
const Route = require('./src/route');
|
|
13
|
-
|
|
14
|
-
module.exports = {
|
|
15
|
-
Application,
|
|
16
|
-
Inquiry,
|
|
17
|
-
Route
|
|
18
|
-
};
|
package/src/application.js
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const stream = require('stream');
|
|
3
|
-
const mime = require('mime-types');
|
|
4
|
-
const CookieHttpOnly = require('cookie-httponly');
|
|
5
|
-
const TypeEnforcement = require('type-enforcement');
|
|
6
|
-
const AsyncFunction = require('./async-function');
|
|
7
|
-
const Inquiry = require('./inquiry');
|
|
8
|
-
const Route = require('./route');
|
|
9
|
-
|
|
10
|
-
const te = new TypeEnforcement({
|
|
11
|
-
'#constructor()': {
|
|
12
|
-
port: Number,
|
|
13
|
-
host: String,
|
|
14
|
-
timeout: Number,
|
|
15
|
-
maxHeadersCount: Number
|
|
16
|
-
},
|
|
17
|
-
'#listenHttp()': {
|
|
18
|
-
router: Route
|
|
19
|
-
},
|
|
20
|
-
'#handler()': {
|
|
21
|
-
status: Number,
|
|
22
|
-
cookie: Array,
|
|
23
|
-
headers: Object
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
class Application {
|
|
28
|
-
constructor({
|
|
29
|
-
port, host = 'localhost', timeout = 12e4, maxHeadersCount = 2e3
|
|
30
|
-
}) {
|
|
31
|
-
const err = te.validate('#constructor()', {
|
|
32
|
-
port,
|
|
33
|
-
host,
|
|
34
|
-
timeout,
|
|
35
|
-
maxHeadersCount
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
if (err) {
|
|
39
|
-
throw err;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (Number.isInteger(port) === false) {
|
|
43
|
-
throw new Error('TCP port value must be an integer');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (port < 1 || port > 65535) {
|
|
47
|
-
throw new Error('TCP port must be in use allowed range');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this.port = port;
|
|
51
|
-
this.host = host;
|
|
52
|
-
this.timeout = timeout;
|
|
53
|
-
this.maxHeadersCount = maxHeadersCount;
|
|
54
|
-
this.server = null;
|
|
55
|
-
this.context = {};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
listenHttp(router) {
|
|
59
|
-
const err = te.validate('#listenHttp()', {
|
|
60
|
-
router
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (err) {
|
|
64
|
-
throw err;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const incomingHandler = async (inq, coookieHttpOnly) => {
|
|
68
|
-
Object.assign(inq.context, this.context);
|
|
69
|
-
|
|
70
|
-
const paths = inq.url.pathname === '/' ?
|
|
71
|
-
[''] : inq.url.pathname.split('/');
|
|
72
|
-
|
|
73
|
-
const route = router.find(paths);
|
|
74
|
-
|
|
75
|
-
if (route === null) {
|
|
76
|
-
return {
|
|
77
|
-
status: 404
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (route.method !== inq.method && inq.method !== 'head') {
|
|
82
|
-
return {
|
|
83
|
-
status: 405
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const {
|
|
88
|
-
status = 200,
|
|
89
|
-
cookie = [],
|
|
90
|
-
headers = {},
|
|
91
|
-
body = ''
|
|
92
|
-
} = await route.handler(inq);
|
|
93
|
-
|
|
94
|
-
const err = te.validate('#handler()', {
|
|
95
|
-
status,
|
|
96
|
-
cookie,
|
|
97
|
-
headers
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
if (err) {
|
|
101
|
-
throw err;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (Number.isInteger(status) === false || status < 100 || status > 599) {
|
|
105
|
-
throw new Error('Invalid HTTP status code');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const isStream = body instanceof stream.Readable;
|
|
109
|
-
|
|
110
|
-
if (isStream === false && typeof body !== 'string') {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`Invalid value 'body'. Expected 'string' or stream.Readable object`
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (isStream === true) {
|
|
117
|
-
headers['Content-Type'] = mime.lookup(body.path) || 'application/octet-stream';
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (cookie.length > 0) {
|
|
121
|
-
for (let {name, value, domain, path, expires} of cookie) {
|
|
122
|
-
coookieHttpOnly.set(name, value, {
|
|
123
|
-
domain,
|
|
124
|
-
path,
|
|
125
|
-
expires
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
for (let i in headers) {
|
|
131
|
-
if (headers.hasOwnProperty(i)) {
|
|
132
|
-
headers[i] = Buffer.from(headers[i]).toString('binary');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
status,
|
|
138
|
-
headers,
|
|
139
|
-
body
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
return new Promise((resolve, reject) => {
|
|
144
|
-
this.server = http.createServer();
|
|
145
|
-
|
|
146
|
-
this.server.on('request', (req, res) => {
|
|
147
|
-
const coookie = new CookieHttpOnly(req, res);
|
|
148
|
-
const inq = new Inquiry(req, coookie.entries);
|
|
149
|
-
|
|
150
|
-
incomingHandler(inq, coookie).catch((err) => {
|
|
151
|
-
router.emit('error', err);
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
status: 500
|
|
155
|
-
};
|
|
156
|
-
})
|
|
157
|
-
.then(({status, headers = {}, body = ''}) => {
|
|
158
|
-
const bodyless = inq.method === 'head';
|
|
159
|
-
|
|
160
|
-
if (body instanceof stream.Readable) {
|
|
161
|
-
res.writeHead(status, headers);
|
|
162
|
-
|
|
163
|
-
if (bodyless === true) {
|
|
164
|
-
if (body.finished === false) {
|
|
165
|
-
body.destroy();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
res.end();
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
body.pipe(res);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
res.writeHead(status, headers);
|
|
176
|
-
|
|
177
|
-
if (bodyless === false) {
|
|
178
|
-
res.write(body);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
res.end();
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
this.server.once('listening', () => {
|
|
187
|
-
console.log(`Server started on http://${this.host}:${this.port}`);
|
|
188
|
-
resolve();
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
this.server.once('error', (err) => {
|
|
192
|
-
reject(err);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
this.server.maxHeadersCount = this.maxHeadersCount;
|
|
196
|
-
this.server.timeout = this.timeout;
|
|
197
|
-
|
|
198
|
-
this.server.listen({
|
|
199
|
-
host: this.host,
|
|
200
|
-
port: this.port
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
close() {
|
|
206
|
-
return new Promise((resolve, reject) => {
|
|
207
|
-
this.server.close((err) => {
|
|
208
|
-
if (err) {
|
|
209
|
-
reject(err);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
console.log(`Server stoped on http://${this.host}:${this.port}`);
|
|
213
|
-
resolve();
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
module.exports = Application;
|
package/src/async-function.js
DELETED
package/src/inquiry.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
const url = require('url');
|
|
2
|
-
const stream = require('stream');
|
|
3
|
-
const querystring = require('querystring');
|
|
4
|
-
const EventEmitter = require('events');
|
|
5
|
-
const TypeEnforcement = require('type-enforcement');
|
|
6
|
-
|
|
7
|
-
const te = new TypeEnforcement({
|
|
8
|
-
'#pipe()': {
|
|
9
|
-
maxSize: Number
|
|
10
|
-
},
|
|
11
|
-
'#read()': {
|
|
12
|
-
maxSize: Number
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
class Inquiry extends EventEmitter {
|
|
17
|
-
constructor(req, cookie) {
|
|
18
|
-
super();
|
|
19
|
-
|
|
20
|
-
this.request = req;
|
|
21
|
-
|
|
22
|
-
req.on('aborted', (err) => {
|
|
23
|
-
this.emit('aborted', err);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
this.cookie = cookie;
|
|
27
|
-
this.type = 0;
|
|
28
|
-
|
|
29
|
-
let [domain, port = 80] = req.headers.host.split(':');
|
|
30
|
-
port = Number(port);
|
|
31
|
-
|
|
32
|
-
const protocol = port === 443 ?
|
|
33
|
-
'https:' : 'http:';
|
|
34
|
-
|
|
35
|
-
this.url = url.parse(`${protocol}//${domain}:${port}${req.url}`);
|
|
36
|
-
this.paths = [];
|
|
37
|
-
|
|
38
|
-
if (this.url.pathname !== '/') {
|
|
39
|
-
let paths = this.url.pathname.substr(1).split('/');
|
|
40
|
-
|
|
41
|
-
for (let i of paths) {
|
|
42
|
-
this.paths.push(decodeURI(i));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
this.queries = querystring.parse(this.url.query);
|
|
47
|
-
this.method = req.method.toLowerCase();
|
|
48
|
-
this.headers = req.headers;
|
|
49
|
-
this.context = {};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async read({maxSize = Infinity} = {}) {
|
|
53
|
-
const err = te.validate('#read()', {
|
|
54
|
-
maxSize
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
if (err) {
|
|
58
|
-
throw err;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return new Promise((resolve, reject) => {
|
|
62
|
-
let data = '';
|
|
63
|
-
|
|
64
|
-
this.request.on('data', (chunk) => {
|
|
65
|
-
if (data.length + chunk.length > maxSize) {
|
|
66
|
-
const err = new Error(`Exceeding maximum body size`);
|
|
67
|
-
|
|
68
|
-
this.request.destroy(err);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
data += chunk;
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
this.request.on('end', () => {
|
|
76
|
-
resolve(data);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
this.request.on('aborted', () => {
|
|
80
|
-
const err = new Error(`Socket aborted`);
|
|
81
|
-
reject(err);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
this.request.on('error', reject);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
pipe(dest, {maxSize = Infinity} = {}) {
|
|
89
|
-
const err = te.validate('#pipe()', {
|
|
90
|
-
maxSize
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
if (err) {
|
|
94
|
-
throw err;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (dest instanceof stream.Writable === false) {
|
|
98
|
-
throw new Error('Expected stream.Writable object');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const pipe = () => {
|
|
102
|
-
this.request.on('data', (chunk) => {
|
|
103
|
-
if (dest.bytesWritten + chunk.byteLength > maxSize) {
|
|
104
|
-
const err = new Error('Exceeding maximum body size');
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* this.request.on('aborted') -> this.request.on('close')
|
|
108
|
-
*
|
|
109
|
-
*/
|
|
110
|
-
|
|
111
|
-
dest.destroy(err);
|
|
112
|
-
}
|
|
113
|
-
else if (dest.write(chunk) === false) {
|
|
114
|
-
this.request.pause();
|
|
115
|
-
|
|
116
|
-
dest.once('drain', () => {
|
|
117
|
-
this.request.resume();
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
dest.on('ready', pipe);
|
|
124
|
-
|
|
125
|
-
dest.on('error', (err) => {
|
|
126
|
-
this.request.destroy();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
this.request.on('end', () => {
|
|
130
|
-
dest.end(); // -> dest.on('close')
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
this.request.on('aborted', () => {
|
|
134
|
-
dest.end();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
return dest;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
module.exports = Inquiry;
|