@browserless.io/browserless 2.8.0 → 2.9.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/README.md +41 -3
  3. package/assets/debugger.png +0 -0
  4. package/bin/scaffold/src/hello-world.http.ts +3 -2
  5. package/build/browserless.d.ts +5 -4
  6. package/build/browserless.js +15 -11
  7. package/build/browsers/chrome.cdp.d.ts +2 -2
  8. package/build/browsers/chrome.cdp.js +2 -2
  9. package/build/browsers/chrome.playwright.d.ts +2 -2
  10. package/build/browsers/chrome.playwright.js +2 -2
  11. package/build/browsers/chromium.cdp.d.ts +4 -4
  12. package/build/browsers/chromium.cdp.js +49 -32
  13. package/build/browsers/chromium.playwright.d.ts +4 -4
  14. package/build/browsers/chromium.playwright.js +14 -13
  15. package/build/browsers/firefox.playwright.d.ts +4 -4
  16. package/build/browsers/firefox.playwright.js +14 -13
  17. package/build/browsers/index.d.ts +24 -8
  18. package/build/browsers/index.js +20 -15
  19. package/build/browsers/webkit.playwright.d.ts +4 -4
  20. package/build/browsers/webkit.playwright.js +14 -13
  21. package/build/config.d.ts +3 -0
  22. package/build/config.js +3 -0
  23. package/build/file-system.d.ts +2 -3
  24. package/build/file-system.js +2 -2
  25. package/build/index.js +7 -7
  26. package/build/limiter.d.ts +2 -3
  27. package/build/limiter.js +11 -11
  28. package/build/logger.d.ts +16 -9
  29. package/build/logger.js +32 -16
  30. package/build/monitoring.d.ts +2 -3
  31. package/build/monitoring.js +4 -4
  32. package/build/router.d.ts +1 -3
  33. package/build/router.js +21 -22
  34. package/build/routes/chrome/http/content.post.body.json +8 -8
  35. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  36. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  37. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  38. package/build/routes/chromium/http/content.post.body.json +8 -8
  39. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  40. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  41. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  42. package/build/routes/management/http/static.get.js +3 -3
  43. package/build/routes/management/tests/management.spec.js +9 -0
  44. package/build/server.d.ts +1 -3
  45. package/build/server.js +33 -30
  46. package/build/shared/content.http.d.ts +1 -1
  47. package/build/shared/content.http.js +4 -1
  48. package/build/shared/download.http.js +9 -9
  49. package/build/shared/function.http.js +2 -2
  50. package/build/shared/json-protocol.http.d.ts +3 -3
  51. package/build/shared/json-protocol.http.js +2 -2
  52. package/build/shared/json-version.http.d.ts +3 -3
  53. package/build/shared/json-version.http.js +2 -2
  54. package/build/shared/pdf.http.d.ts +1 -1
  55. package/build/shared/pdf.http.js +6 -4
  56. package/build/shared/performance.http.js +1 -0
  57. package/build/shared/scrape.http.d.ts +1 -1
  58. package/build/shared/scrape.http.js +4 -1
  59. package/build/shared/screenshot.http.d.ts +1 -1
  60. package/build/shared/screenshot.http.js +4 -1
  61. package/build/shared/utils/function/handler.js +7 -7
  62. package/build/shared/utils/performance/child.js +4 -4
  63. package/build/shared/utils/performance/main.d.ts +1 -1
  64. package/build/shared/utils/performance/main.js +5 -7
  65. package/build/shared/utils/performance/types.d.ts +2 -1
  66. package/build/utils.d.ts +1 -1
  67. package/build/utils.js +6 -2
  68. package/package.json +18 -15
  69. package/scripts/install-debugger.js +55 -15
  70. package/src/browserless.ts +21 -12
  71. package/src/browsers/chrome.cdp.ts +2 -5
  72. package/src/browsers/chrome.playwright.ts +2 -5
  73. package/src/browsers/chromium.cdp.ts +84 -35
  74. package/src/browsers/chromium.playwright.ts +26 -13
  75. package/src/browsers/firefox.playwright.ts +28 -13
  76. package/src/browsers/index.ts +24 -16
  77. package/src/browsers/webkit.playwright.ts +28 -13
  78. package/src/config.ts +4 -0
  79. package/src/file-system.ts +2 -7
  80. package/src/index.ts +7 -7
  81. package/src/limiter.ts +13 -11
  82. package/src/logger.ts +39 -18
  83. package/src/monitoring.ts +6 -8
  84. package/src/router.ts +20 -20
  85. package/src/routes/management/http/static.get.ts +3 -5
  86. package/src/routes/management/tests/management.spec.ts +15 -0
  87. package/src/server.ts +43 -30
  88. package/src/shared/content.http.ts +5 -1
  89. package/src/shared/download.http.ts +9 -9
  90. package/src/shared/function.http.ts +2 -2
  91. package/src/shared/json-protocol.http.ts +8 -3
  92. package/src/shared/json-version.http.ts +8 -4
  93. package/src/shared/pdf.http.ts +6 -4
  94. package/src/shared/performance.http.ts +1 -0
  95. package/src/shared/scrape.http.ts +5 -1
  96. package/src/shared/screenshot.http.ts +4 -1
  97. package/src/shared/utils/function/handler.ts +7 -7
  98. package/src/shared/utils/performance/child.ts +4 -4
  99. package/src/shared/utils/performance/main.ts +5 -6
  100. package/src/shared/utils/performance/types.ts +2 -1
  101. package/src/utils.ts +7 -2
  102. package/static/docs/swagger.json +10 -10
  103. package/static/docs/swagger.min.json +9 -9
  104. package/static/function/client.js +1646 -2917
  105. package/static/function/index.html +1646 -2917
package/src/limiter.ts CHANGED
@@ -2,11 +2,11 @@ import {
2
2
  AfterResponse,
3
3
  Config,
4
4
  Hooks,
5
+ Logger,
5
6
  Metrics,
6
7
  Monitoring,
7
8
  TooManyRequests,
8
9
  WebHooks,
9
- createLogger,
10
10
  } from '@browserless.io/browserless';
11
11
  import q from 'queue';
12
12
 
@@ -26,7 +26,7 @@ interface Job {
26
26
 
27
27
  export class Limiter extends q {
28
28
  protected queued: number;
29
- protected debug = createLogger('limiter');
29
+ protected logger = new Logger('limiter');
30
30
 
31
31
  constructor(
32
32
  protected config: Config,
@@ -42,22 +42,22 @@ export class Limiter extends q {
42
42
  });
43
43
  this.queued = config.getQueued();
44
44
 
45
- this.debug(
45
+ this.logger.info(
46
46
  `Concurrency: ${this.concurrency} queue: ${this.queued} timeout: ${this.timeout}ms`,
47
47
  );
48
48
 
49
49
  config.on('concurrent', (concurrency: number) => {
50
- this.debug(`Concurrency updated to ${concurrency}`);
50
+ this.logger.info(`Concurrency updated to ${concurrency}`);
51
51
  this.concurrency = concurrency;
52
52
  });
53
53
 
54
54
  config.on('queued', (queued: number) => {
55
- this.debug(`Queue updated to ${queued}`);
55
+ this.logger.info(`Queue updated to ${queued}`);
56
56
  this.queued = queued;
57
57
  });
58
58
 
59
59
  config.on('timeout', (timeout: number) => {
60
- this.debug(`Timeout updated to ${timeout}ms`);
60
+ this.logger.info(`Timeout updated to ${timeout}ms`);
61
61
  this.timeout = timeout <= 0 ? 0 : timeout;
62
62
  });
63
63
 
@@ -83,7 +83,7 @@ export class Limiter extends q {
83
83
 
84
84
  protected handleSuccess({ detail: { job } }: { detail: { job: Job } }) {
85
85
  const timeUsed = Date.now() - job.start;
86
- this.debug(
86
+ this.logger.info(
87
87
  `Job has succeeded after ${timeUsed.toLocaleString()}ms of activity.`,
88
88
  );
89
89
  this.metrics.addSuccessful(Date.now() - job.start);
@@ -101,12 +101,12 @@ export class Limiter extends q {
101
101
  detail: { job: Job; next: Job };
102
102
  }) {
103
103
  const timeUsed = Date.now() - job.start;
104
- this.debug(
104
+ this.logger.warn(
105
105
  `Job has hit timeout after ${timeUsed.toLocaleString()}ms of activity.`,
106
106
  );
107
107
  this.metrics.addTimedout(Date.now() - job.start);
108
108
  this.webhooks.callTimeoutAlertURL();
109
- this.debug(`Calling timeout handler`);
109
+ this.logger.info(`Calling timeout handler`);
110
110
  job?.onTimeoutFn(job);
111
111
  this.jobEnd({
112
112
  req: job.args[0],
@@ -122,7 +122,9 @@ export class Limiter extends q {
122
122
  }: {
123
123
  detail: { error: unknown; job: Job };
124
124
  }) {
125
- this.debug(`Recording failed stat, cleaning up: "${error?.toString()}"`);
125
+ this.logger.info(
126
+ `Recording failed stat, cleaning up: "${error?.toString()}"`,
127
+ );
126
128
  this.metrics.addError(Date.now() - job.start);
127
129
  this.webhooks.callErrorAlertURL(error?.toString() ?? 'Unknown Error');
128
130
  this.jobEnd({
@@ -133,7 +135,7 @@ export class Limiter extends q {
133
135
  }
134
136
 
135
137
  protected logQueue(message: string) {
136
- this.debug(
138
+ this.logger.info(
137
139
  `(Running: ${this.executing}, Pending: ${this.waiting}) ${message} `,
138
140
  );
139
141
  }
package/src/logger.ts CHANGED
@@ -1,31 +1,52 @@
1
1
  import { Request, createLogger } from '@browserless.io/browserless';
2
2
 
3
3
  export class Logger {
4
- protected _log: ReturnType<typeof createLogger>;
5
- protected _verbose: ReturnType<typeof createLogger>;
6
- protected _error: ReturnType<typeof createLogger>;
4
+ protected _trace: (...args: unknown[]) => void;
5
+ protected _debug: (...args: unknown[]) => void;
6
+ protected _info: (...args: unknown[]) => void;
7
+ protected _warn: (...args: unknown[]) => void;
8
+ protected _error: (...args: unknown[]) => void;
9
+ protected _fatal: (...args: unknown[]) => void;
7
10
 
8
11
  constructor(
9
12
  protected prefix: string,
10
- protected request: Request,
13
+ protected request?: Request,
11
14
  ) {
12
- this._log = createLogger(prefix);
13
- this._verbose = this._log.extend('verbose');
14
- this._error = this._log.extend('error');
15
- }
15
+ const logger = createLogger(prefix);
16
16
 
17
- public verbose(...messages: string[]) {
18
- const ip = this.request.socket.remoteAddress ?? 'Unknown';
19
- this._verbose(ip, ...messages);
17
+ this._trace = logger.extend('trace');
18
+ this._debug = logger.extend('debug');
19
+ this._info = logger.extend('info');
20
+ this._warn = logger.extend('warn');
21
+ this._error = logger.extend('error');
22
+ this._fatal = logger.extend('fatal');
20
23
  }
21
24
 
22
- public log(...messages: string[]) {
23
- const ip = this.request.socket.remoteAddress ?? 'Unknown';
24
- this._log(ip, ...messages);
25
+ protected get reqInfo() {
26
+ return this.request ? this.request.socket.remoteAddress ?? 'Unknown' : '';
25
27
  }
26
28
 
27
- public error(...messages: string[]) {
28
- const ip = this.request.socket.remoteAddress ?? 'Unknown';
29
- this._error(ip, ...messages);
30
- }
29
+ public trace = (...messages: unknown[]) => {
30
+ this._trace(this.reqInfo, ...messages);
31
+ };
32
+
33
+ public debug = (...messages: unknown[]) => {
34
+ this._debug(this.reqInfo, ...messages);
35
+ };
36
+
37
+ public info = (...messages: unknown[]) => {
38
+ this._info(this.reqInfo, ...messages);
39
+ };
40
+
41
+ public warn = (...messages: unknown[]) => {
42
+ this._warn(this.reqInfo, ...messages);
43
+ };
44
+
45
+ public error = (...messages: unknown[]) => {
46
+ this._error(this.reqInfo, ...messages);
47
+ };
48
+
49
+ public fatal = (...messages: unknown[]) => {
50
+ this._fatal(this.reqInfo, ...messages);
51
+ };
31
52
  }
package/src/monitoring.ts CHANGED
@@ -1,13 +1,9 @@
1
- import {
2
- Config,
3
- IResourceLoad,
4
- createLogger,
5
- } from '@browserless.io/browserless';
1
+ import { Config, IResourceLoad, Logger } from '@browserless.io/browserless';
6
2
  import { EventEmitter } from 'events';
7
3
  import si from 'systeminformation';
8
4
 
9
5
  export class Monitoring extends EventEmitter {
10
- protected log = createLogger('hardware');
6
+ protected log = new Logger('hardware');
11
7
  constructor(protected config: Config) {
12
8
  super();
13
9
  }
@@ -17,7 +13,7 @@ export class Monitoring extends EventEmitter {
17
13
  si.currentLoad(),
18
14
  si.mem(),
19
15
  ]).catch((err) => {
20
- this.log(`Error checking machine stats`, err);
16
+ this.log.error(`Error checking machine stats`, err);
21
17
  return [null, null];
22
18
  });
23
19
 
@@ -40,7 +36,9 @@ export class Monitoring extends EventEmitter {
40
36
  const cpuInt = cpu && Math.ceil(cpu * 100);
41
37
  const memoryInt = memory && Math.ceil(memory * 100);
42
38
 
43
- this.log(`Checking overload status: CPU ${cpuInt}% Memory ${memoryInt}%`);
39
+ this.log.info(
40
+ `Checking overload status: CPU ${cpuInt}% Memory ${memoryInt}%`,
41
+ );
44
42
 
45
43
  const cpuOverloaded = !!(cpuInt && cpuInt >= this.config.getCPULimit());
46
44
  const memoryOverloaded = !!(
package/src/router.ts CHANGED
@@ -13,7 +13,6 @@ import {
13
13
  Response,
14
14
  WebSocketRoute,
15
15
  contentTypes,
16
- createLogger,
17
16
  isConnected,
18
17
  writeResponse,
19
18
  } from '@browserless.io/browserless';
@@ -22,8 +21,7 @@ import micromatch from 'micromatch';
22
21
  import stream from 'stream';
23
22
 
24
23
  export class Router extends EventEmitter {
25
- protected log = createLogger('router');
26
- protected verbose = createLogger('router:verbose');
24
+ protected log = new Logger('router');
27
25
  protected httpRoutes: Array<HTTPRoute | BrowserHTTPRoute> = [];
28
26
  protected webSocketRoutes: Array<WebSocketRoute | BrowserWebsocketRoute> = [];
29
27
 
@@ -43,22 +41,22 @@ export class Router extends EventEmitter {
43
41
  }
44
42
 
45
43
  protected onQueueFullHTTP = (_req: Request, res: Response) => {
46
- this.log(`Queue is full, sending 429 response`);
44
+ this.log.warn(`Queue is full, sending 429 response`);
47
45
  return writeResponse(res, 429, 'Too many requests');
48
46
  };
49
47
 
50
48
  protected onQueueFullWebSocket = (_req: Request, socket: stream.Duplex) => {
51
- this.log(`Queue is full, sending 429 response`);
49
+ this.log.warn(`Queue is full, sending 429 response`);
52
50
  return writeResponse(socket, 429, 'Too many requests');
53
51
  };
54
52
 
55
53
  protected onHTTPTimeout = (_req: Request, res: Response) => {
56
- this.log(`HTTP job has timedout, sending 429 response`);
54
+ this.log.error(`HTTP job has timedout, sending 429 response`);
57
55
  return writeResponse(res, 408, 'Request has timed out');
58
56
  };
59
57
 
60
58
  protected onWebsocketTimeout = (_req: Request, socket: stream.Duplex) => {
61
- this.log(`Websocket job has timedout, sending 429 response`);
59
+ this.log.error(`Websocket job has timedout, sending 429 response`);
62
60
  return writeResponse(socket, 408, 'Request has timed out');
63
61
  };
64
62
 
@@ -69,7 +67,7 @@ export class Router extends EventEmitter {
69
67
  ) =>
70
68
  async (req: Request, res: Response) => {
71
69
  if (!isConnected(res)) {
72
- this.log(`HTTP Request has closed prior to running`);
70
+ this.log.warn(`HTTP Request has closed prior to running`);
73
71
  return Promise.resolve();
74
72
  }
75
73
  const logger = new this.logger(route.name, req);
@@ -77,10 +75,11 @@ export class Router extends EventEmitter {
77
75
  const browser = await this.browserManager.getBrowserForRequest(
78
76
  req,
79
77
  route,
78
+ logger,
80
79
  );
81
80
 
82
81
  if (!isConnected(res)) {
83
- this.log(`HTTP Request has closed prior to running`);
82
+ this.log.warn(`HTTP Request has closed prior to running`);
84
83
  this.browserManager.complete(browser);
85
84
  return Promise.resolve();
86
85
  }
@@ -90,7 +89,7 @@ export class Router extends EventEmitter {
90
89
  }
91
90
 
92
91
  try {
93
- this.verbose(`Running found HTTP handler.`);
92
+ this.log.trace(`Running found HTTP handler.`);
94
93
  return await Promise.race([
95
94
  handler(req, res, logger, browser),
96
95
  new Promise((resolve, reject) => {
@@ -98,13 +97,13 @@ export class Router extends EventEmitter {
98
97
  if (!res.writableEnded) {
99
98
  reject(new Error(`Request closed prior to writing results`));
100
99
  }
101
- this.verbose(`Response has been written, resolving`);
100
+ this.log.trace(`Response has been written, resolving`);
102
101
  resolve(null);
103
102
  });
104
103
  }),
105
104
  ]);
106
105
  } finally {
107
- this.verbose(`HTTP Request handler has finished.`);
106
+ this.log.trace(`HTTP Request handler has finished.`);
108
107
  this.browserManager.complete(browser);
109
108
  }
110
109
  }
@@ -119,7 +118,7 @@ export class Router extends EventEmitter {
119
118
  ) =>
120
119
  async (req: Request, socket: stream.Duplex, head: Buffer) => {
121
120
  if (!isConnected(socket)) {
122
- this.log(`WebSocket Request has closed prior to running`);
121
+ this.log.warn(`WebSocket Request has closed prior to running`);
123
122
  return Promise.resolve();
124
123
  }
125
124
  const logger = new this.logger(route.name, req);
@@ -127,10 +126,11 @@ export class Router extends EventEmitter {
127
126
  const browser = await this.browserManager.getBrowserForRequest(
128
127
  req,
129
128
  route,
129
+ logger,
130
130
  );
131
131
 
132
132
  if (!isConnected(socket)) {
133
- this.log(`WebSocket Request has closed prior to running`);
133
+ this.log.warn(`WebSocket Request has closed prior to running`);
134
134
  this.browserManager.complete(browser);
135
135
  return Promise.resolve();
136
136
  }
@@ -140,10 +140,10 @@ export class Router extends EventEmitter {
140
140
  }
141
141
 
142
142
  try {
143
- this.verbose(`Running found WebSocket handler.`);
143
+ this.log.trace(`Running found WebSocket handler.`);
144
144
  await handler(req, socket, head, logger, browser);
145
145
  } finally {
146
- this.verbose(`WebSocket Request handler has finished.`);
146
+ this.log.trace(`WebSocket Request handler has finished.`);
147
147
  this.browserManager.complete(browser);
148
148
  }
149
149
  return;
@@ -154,7 +154,7 @@ export class Router extends EventEmitter {
154
154
  public registerHTTPRoute(
155
155
  route: HTTPRoute | BrowserHTTPRoute,
156
156
  ): HTTPRoute | BrowserHTTPRoute {
157
- this.verbose(
157
+ this.log.trace(
158
158
  `Registering HTTP ${route.method.toUpperCase()} ${route.path}`,
159
159
  );
160
160
 
@@ -176,7 +176,7 @@ export class Router extends EventEmitter {
176
176
  );
177
177
 
178
178
  if (duplicatePaths.length) {
179
- this.log(`Found duplicate routes: ${duplicatePaths.join(', ')}`);
179
+ this.log.warn(`Found duplicate routes: ${duplicatePaths.join(', ')}`);
180
180
  }
181
181
  this.httpRoutes.push(route);
182
182
 
@@ -186,7 +186,7 @@ export class Router extends EventEmitter {
186
186
  public registerWebSocketRoute(
187
187
  route: WebSocketRoute | BrowserWebsocketRoute,
188
188
  ): WebSocketRoute | BrowserWebsocketRoute {
189
- this.verbose(`Registering WebSocket "${route.path}"`);
189
+ this.log.trace(`Registering WebSocket "${route.path}"`);
190
190
 
191
191
  const bound = route.handler.bind(route);
192
192
  const wrapped = this.wrapWebSocketHandler(route, bound);
@@ -206,7 +206,7 @@ export class Router extends EventEmitter {
206
206
  );
207
207
 
208
208
  if (duplicatePaths.length) {
209
- this.log(`Found duplicate routes: ${duplicatePaths.join(', ')}`);
209
+ this.log.warn(`Found duplicate routes: ${duplicatePaths.join(', ')}`);
210
210
  }
211
211
  this.webSocketRoutes.push(route);
212
212
  return route;
@@ -31,7 +31,7 @@ const streamFile = (
31
31
  ) =>
32
32
  new Promise((resolve, reject) => {
33
33
  if (contentType) {
34
- logger.log(`Setting content-type ${contentType}`);
34
+ logger.debug(`Setting content-type ${contentType}`);
35
35
  res.setHeader('Content-Type', contentType);
36
36
  }
37
37
 
@@ -96,15 +96,13 @@ export default class StaticGetRoute extends HTTPRoute {
96
96
  }
97
97
 
98
98
  if (foundFilePaths.length > 1) {
99
- logger.log(
99
+ logger.warn(
100
100
  `Multiple files found for request to "${pathname}". Only the first file is served, so please name your files uniquely.`,
101
101
  );
102
102
  }
103
103
 
104
104
  const [foundFilePath] = foundFilePaths;
105
- logger.verbose(
106
- `Found new file "${foundFilePath}", caching path and serving`,
107
- );
105
+ logger.info(`Found new file "${foundFilePath}", caching path and serving`);
108
106
 
109
107
  const contentType = mimeTypes.get(path.extname(foundFilePath));
110
108
 
@@ -81,4 +81,19 @@ describe('Management APIs', function () {
81
81
  },
82
82
  );
83
83
  });
84
+
85
+ it('allows HEAD requests to /active', async () => {
86
+ await start();
87
+
88
+ await fetch('http://localhost:3000/active?token=6R0W53R135510', {
89
+ method: 'HEAD',
90
+ }).then(
91
+ async (res) => {
92
+ expect(res.headers.get('content-type')).to.equal(
93
+ 'text/plain; charset=UTF-8',
94
+ );
95
+ expect(res.status).to.equal(204);
96
+ },
97
+ );
98
+ });
84
99
  });
package/src/server.ts CHANGED
@@ -18,7 +18,6 @@ import {
18
18
  WebSocketRoute,
19
19
  contentTypes,
20
20
  convertPathToURL,
21
- createLogger,
22
21
  queryParamsToObject,
23
22
  readBody,
24
23
  shimLegacyRequests,
@@ -41,8 +40,7 @@ export class HTTPServer extends EventEmitter {
41
40
  protected server: http.Server = http.createServer();
42
41
  protected port: number;
43
42
  protected host?: string;
44
- protected log = createLogger('server');
45
- protected verbose = createLogger('server:verbose');
43
+ protected logger = new BlessLogger('server');
46
44
 
47
45
  constructor(
48
46
  protected config: Config,
@@ -56,7 +54,7 @@ export class HTTPServer extends EventEmitter {
56
54
  this.host = config.getHost();
57
55
  this.port = config.getPort();
58
56
 
59
- this.log(
57
+ this.logger.info(
60
58
  `Server instantiated with host "${this.host}" on port "${
61
59
  this.port
62
60
  }" using token "${this.config.getToken()}"`,
@@ -64,7 +62,9 @@ export class HTTPServer extends EventEmitter {
64
62
  }
65
63
 
66
64
  protected onHTTPUnauthorized = (_req: Request, res: Response) => {
67
- this.log(`HTTP request is not properly authorized, responding with 401`);
65
+ this.logger.error(
66
+ `HTTP request is not properly authorized, responding with 401`,
67
+ );
68
68
  this.metrics.addUnauthorized();
69
69
  return writeResponse(res, 401, 'Bad or missing authentication.');
70
70
  };
@@ -73,7 +73,7 @@ export class HTTPServer extends EventEmitter {
73
73
  _req: Request,
74
74
  socket: stream.Duplex,
75
75
  ) => {
76
- this.log(
76
+ this.logger.error(
77
77
  `Websocket request is not properly authorized, responding with 401`,
78
78
  );
79
79
  this.metrics.addUnauthorized();
@@ -81,7 +81,7 @@ export class HTTPServer extends EventEmitter {
81
81
  };
82
82
 
83
83
  public async start(): Promise<void> {
84
- this.log(`HTTP Server is starting`);
84
+ this.logger.info(`HTTP Server is starting`);
85
85
 
86
86
  this.server.on('request', this.handleRequest);
87
87
  this.server.on('upgrade', this.handleWebSocket);
@@ -98,7 +98,7 @@ export class HTTPServer extends EventEmitter {
98
98
  },
99
99
  undefined,
100
100
  () => {
101
- this.log(listenMessage);
101
+ this.logger.info(listenMessage);
102
102
  r(undefined);
103
103
  },
104
104
  );
@@ -109,7 +109,7 @@ export class HTTPServer extends EventEmitter {
109
109
  request: http.IncomingMessage,
110
110
  res: http.ServerResponse,
111
111
  ) => {
112
- this.verbose(
112
+ this.logger.trace(
113
113
  `Handling inbound HTTP request on "${request.method}: ${request.url}"`,
114
114
  );
115
115
 
@@ -131,6 +131,11 @@ export class HTTPServer extends EventEmitter {
131
131
  }
132
132
  }
133
133
 
134
+ if (req.method?.toLowerCase() === 'head') {
135
+ this.logger.debug(`Inbound HEAD request, setting to GET`);
136
+ req.method = 'GET';
137
+ }
138
+
134
139
  if (
135
140
  this.config.getAllowGetCalls() &&
136
141
  req.method === 'GET' &&
@@ -145,17 +150,17 @@ export class HTTPServer extends EventEmitter {
145
150
  const route = await this.router.getRouteForHTTPRequest(req);
146
151
 
147
152
  if (!route) {
148
- this.log(
153
+ this.logger.error(
149
154
  `No matching HTTP route handler for "${req.method}: ${req.parsed.href}"`,
150
155
  );
151
156
  writeResponse(res, 404, 'Not Found');
152
157
  return Promise.resolve();
153
158
  }
154
159
 
155
- this.verbose(`Found matching HTTP route handler "${route.path}"`);
160
+ this.logger.trace(`Found matching HTTP route handler "${route.path}"`);
156
161
 
157
162
  if (route?.auth) {
158
- this.verbose(`Authorizing HTTP request to "${request.url}"`);
163
+ this.logger.trace(`Authorizing HTTP request to "${request.url}"`);
159
164
  const isPermitted = await this.token.isAuthorized(req, route);
160
165
 
161
166
  if (!isPermitted) {
@@ -179,7 +184,7 @@ export class HTTPServer extends EventEmitter {
179
184
  }
180
185
 
181
186
  if (route.querySchema) {
182
- this.verbose(`Validating route query-params with QUERY schema`);
187
+ this.logger.trace(`Validating route query-params with QUERY schema`);
183
188
  try {
184
189
  const schema = Enjoi.schema(route.querySchema);
185
190
  const valid = schema.validate(req.queryParams, {
@@ -199,7 +204,7 @@ export class HTTPServer extends EventEmitter {
199
204
  )
200
205
  .join('\n');
201
206
 
202
- this.log(
207
+ this.logger.error(
203
208
  `HTTP query-params contain errors sending 400:${errorDetails}`,
204
209
  );
205
210
 
@@ -212,7 +217,7 @@ export class HTTPServer extends EventEmitter {
212
217
  return Promise.resolve();
213
218
  }
214
219
  } catch (e) {
215
- this.log(`Error parsing body schema`, e);
220
+ this.logger.error(`Error parsing body schema`, e);
216
221
  writeResponse(
217
222
  res,
218
223
  500,
@@ -224,7 +229,7 @@ export class HTTPServer extends EventEmitter {
224
229
  }
225
230
 
226
231
  if (route.bodySchema) {
227
- this.verbose(`Validating route payload with BODY schema`);
232
+ this.logger.trace(`Validating route payload with BODY schema`);
228
233
  try {
229
234
  const schema = Enjoi.schema(route.bodySchema);
230
235
  const valid = schema.validate(body, { abortEarly: false });
@@ -242,7 +247,9 @@ export class HTTPServer extends EventEmitter {
242
247
  )
243
248
  .join('\n');
244
249
 
245
- this.log(`HTTP body contain errors sending 400:${errorDetails}`);
250
+ this.logger.error(
251
+ `HTTP body contain errors sending 400:${errorDetails}`,
252
+ );
246
253
 
247
254
  writeResponse(
248
255
  res,
@@ -253,7 +260,7 @@ export class HTTPServer extends EventEmitter {
253
260
  return Promise.resolve();
254
261
  }
255
262
  } catch (e) {
256
- this.log(`Error parsing body schema`, e);
263
+ this.logger.error(`Error parsing body schema`, e);
257
264
  writeResponse(
258
265
  res,
259
266
  500,
@@ -267,7 +274,7 @@ export class HTTPServer extends EventEmitter {
267
274
  return (route as HTTPRoute)
268
275
  .handler(req, res, new this.Logger(route.name, req))
269
276
  .then(() => {
270
- this.verbose('HTTP connection complete');
277
+ this.logger.trace('HTTP connection complete');
271
278
  })
272
279
  .catch((e) => {
273
280
  if (e instanceof BadRequest) {
@@ -299,7 +306,7 @@ export class HTTPServer extends EventEmitter {
299
306
  socket: stream.Duplex,
300
307
  head: Buffer,
301
308
  ) => {
302
- this.verbose(`Handling inbound WebSocket request on "${request.url}"`);
309
+ this.logger.trace(`Handling inbound WebSocket request on "${request.url}"`);
303
310
 
304
311
  const req = request as Request;
305
312
  const proceed = await this.hooks.before({ head, req, socket });
@@ -313,10 +320,14 @@ export class HTTPServer extends EventEmitter {
313
320
  const route = await this.router.getRouteForWebSocketRequest(req);
314
321
 
315
322
  if (route) {
316
- this.verbose(`Found matching WebSocket route handler "${route.path}"`);
323
+ this.logger.trace(
324
+ `Found matching WebSocket route handler "${route.path}"`,
325
+ );
317
326
 
318
327
  if (route?.auth) {
319
- this.verbose(`Authorizing WebSocket request to "${req.parsed.href}"`);
328
+ this.logger.trace(
329
+ `Authorizing WebSocket request to "${req.parsed.href}"`,
330
+ );
320
331
  const isPermitted = await this.token.isAuthorized(req, route);
321
332
 
322
333
  if (!isPermitted) {
@@ -325,7 +336,7 @@ export class HTTPServer extends EventEmitter {
325
336
  }
326
337
 
327
338
  if (route.querySchema) {
328
- this.verbose(`Validating route query-params with QUERY schema`);
339
+ this.logger.trace(`Validating route query-params with QUERY schema`);
329
340
  try {
330
341
  const schema = Enjoi.schema(route.querySchema);
331
342
  const valid = schema.validate(req.queryParams, {
@@ -345,7 +356,7 @@ export class HTTPServer extends EventEmitter {
345
356
  )
346
357
  .join('\n');
347
358
 
348
- this.log(
359
+ this.logger.error(
349
360
  `WebSocket query-params contain errors sending 400:${errorDetails}`,
350
361
  );
351
362
 
@@ -358,7 +369,7 @@ export class HTTPServer extends EventEmitter {
358
369
  return Promise.resolve();
359
370
  }
360
371
  } catch (e) {
361
- this.log(`Error parsing query-params schema`, e);
372
+ this.logger.error(`Error parsing query-params schema`, e);
362
373
  writeResponse(
363
374
  socket,
364
375
  500,
@@ -372,7 +383,7 @@ export class HTTPServer extends EventEmitter {
372
383
  return (route as WebSocketRoute)
373
384
  .handler(req, socket, head, new this.Logger(route.name, req))
374
385
  .then(() => {
375
- this.verbose('Websocket connection complete');
386
+ this.logger.trace('Websocket connection complete');
376
387
  })
377
388
  .catch((e) => {
378
389
  if (e instanceof BadRequest) {
@@ -391,7 +402,7 @@ export class HTTPServer extends EventEmitter {
391
402
  return writeResponse(socket, 429, e.message);
392
403
  }
393
404
 
394
- this.log(
405
+ this.logger.error(
395
406
  `Error handling request at "${route.path}": ${e}\n${e.stack}`,
396
407
  );
397
408
 
@@ -399,18 +410,20 @@ export class HTTPServer extends EventEmitter {
399
410
  });
400
411
  }
401
412
 
402
- this.log(`No matching WebSocket route handler for "${req.parsed.href}"`);
413
+ this.logger.error(
414
+ `No matching WebSocket route handler for "${req.parsed.href}"`,
415
+ );
403
416
  return writeResponse(socket, 404, 'Not Found');
404
417
  };
405
418
 
406
419
  public async shutdown(): Promise<void> {
407
- this.log(`HTTP Server is shutting down`);
420
+ this.logger.info(`HTTP Server is shutting down`);
408
421
  await new Promise((r) => this.server.close(r));
409
422
  this.server && this.server.removeAllListeners();
410
423
 
411
424
  // @ts-ignore garbage collect this reference
412
425
  this.server = null;
413
- this.log(`HTTP Server shutdown complete`);
426
+ this.logger.info(`HTTP Server shutdown complete`);
414
427
  }
415
428
 
416
429
  /**