web_plsql 0.5.1 → 0.8.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/README.md +128 -111
- package/examples/server_apex.js +26 -0
- package/examples/server_sample.js +30 -0
- package/examples/sql/{doc_table.sql → doctable.sql} +1 -1
- package/examples/sql/install.sql +6 -9
- package/examples/sql/sample_package.sql +27 -0
- package/examples/sql/sample_package_body.sql +245 -0
- package/examples/static/sample.css +11 -10
- package/package.json +92 -83
- package/src/cgi.js +127 -0
- package/src/error.js +24 -0
- package/src/errorPage.js +296 -0
- package/src/file.js +95 -0
- package/src/handlerLogger.js +21 -0
- package/src/handlerMetrics.js +46 -0
- package/src/handlerPlSql.js +65 -0
- package/src/handlerUpload.js +32 -0
- package/src/index.js +17 -0
- package/src/oracle.js +80 -0
- package/src/parsePage.js +193 -0
- package/src/procedure.js +260 -0
- package/src/procedureError.js +40 -0
- package/src/procedureNamed.js +233 -0
- package/src/procedureSanitize.js +215 -0
- package/src/procedureVariable.js +57 -0
- package/src/request.js +103 -0
- package/src/{requestError.ts → requestError.js} +8 -4
- package/src/sendResponse.js +104 -0
- package/src/server.js +185 -0
- package/src/shutdown.js +53 -0
- package/src/stream.js +28 -0
- package/src/trace.js +74 -0
- package/src/tty.js +48 -0
- package/src/types.js +146 -0
- package/src/upload.js +92 -0
- package/src/version.js +38 -0
- package/types/cgi.d.ts +4 -0
- package/types/error.d.ts +1 -0
- package/types/errorPage.d.ts +10 -0
- package/types/file.d.ts +6 -0
- package/types/handlerLogger.d.ts +2 -0
- package/types/handlerMetrics.d.ts +4 -0
- package/types/handlerPlSql.d.ts +8 -0
- package/types/handlerUpload.d.ts +7 -0
- package/types/index.d.ts +10 -0
- package/types/oracle.d.ts +5 -0
- package/types/parsePage.d.ts +3 -0
- package/types/procedure.d.ts +10 -0
- package/types/procedureError.d.ts +23 -0
- package/types/procedureNamed.d.ts +14 -0
- package/types/procedureSanitize.d.ts +14 -0
- package/types/procedureVariable.d.ts +9 -0
- package/types/request.d.ts +7 -0
- package/types/requestError.d.ts +8 -0
- package/types/sendResponse.d.ts +4 -0
- package/types/server.d.ts +11 -0
- package/types/shutdown.d.ts +2 -0
- package/types/stream.d.ts +1 -0
- package/types/trace.d.ts +5 -0
- package/types/tty.d.ts +4 -0
- package/types/types.d.ts +251 -0
- package/types/upload.d.ts +5 -0
- package/types/version.d.ts +8 -0
- package/.editorconfig +0 -8
- package/.eslintignore +0 -3
- package/.eslintrc.js +0 -347
- package/CHANGELOG.md +0 -133
- package/examples/apex.js +0 -70
- package/examples/credentials.js +0 -22
- package/examples/oracledb_example.js +0 -30
- package/examples/sample.js +0 -101
- package/examples/sql/sample.pkb +0 -223
- package/examples/sql/sample.pks +0 -24
- package/jest.config.js +0 -207
- package/src/cgi.ts +0 -95
- package/src/config.ts +0 -97
- package/src/errorPage.ts +0 -286
- package/src/fileUpload.ts +0 -126
- package/src/index.ts +0 -65
- package/src/page.ts +0 -275
- package/src/procedure.ts +0 -360
- package/src/procedureError.ts +0 -27
- package/src/request.ts +0 -139
- package/src/stream.ts +0 -26
- package/src/trace.ts +0 -194
- package/test/.eslintrc.json +0 -5
- package/test/__tests__/cgi.ts +0 -96
- package/test/__tests__/config.ts +0 -41
- package/test/__tests__/errorPage.ts +0 -101
- package/test/__tests__/oracledb_mock.ts +0 -98
- package/test/__tests__/server.ts +0 -495
- package/test/__tests__/stream.ts +0 -21
- package/test/mock/oracledb.ts +0 -85
- package/test/static/static.html +0 -1
- package/tsconfig.json +0 -24
- package/tsconfig.src.json +0 -23
package/package.json
CHANGED
|
@@ -1,85 +1,94 @@
|
|
|
1
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
|
-
|
|
2
|
+
"name": "web_plsql",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"author": "Dieter Oberkofler <dieter.oberkofler@gmail.com>",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "The Express Middleware for Oracle PL/SQL",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"node",
|
|
9
|
+
"nodejs",
|
|
10
|
+
"express",
|
|
11
|
+
"middleware",
|
|
12
|
+
"plsql",
|
|
13
|
+
"pl/sql",
|
|
14
|
+
"oracle",
|
|
15
|
+
"ohs",
|
|
16
|
+
"ords",
|
|
17
|
+
"apex"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/doberkofler/web_plsql",
|
|
20
|
+
"engines": {
|
|
21
|
+
"npm": ">=10.0.0",
|
|
22
|
+
"node": ">=22.0.0"
|
|
23
|
+
},
|
|
24
|
+
"maintainers": [
|
|
25
|
+
{
|
|
26
|
+
"name": "Dieter Oberkofler",
|
|
27
|
+
"email": "dieter.oberkofler@gmail.com"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/doberkofler/web_plsql/issues"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git://github.com/doberkofler/web_plsql.git"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"src/",
|
|
39
|
+
"examples/",
|
|
40
|
+
"types"
|
|
41
|
+
],
|
|
42
|
+
"main": "./src/index.js",
|
|
43
|
+
"types": "./types/index.d.ts",
|
|
44
|
+
"type": "module",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"lint": "prettier --check . && eslint . && tsc --noEmit",
|
|
47
|
+
"test": "node --test --test-concurrency=1 \"./tests/**/*.test.js\"",
|
|
48
|
+
"types": "rm -rf types && tsc --noEmit false --declaration true --declarationDir types --emitDeclarationOnly true --allowJs true --target es2020 --module es2020 --moduleResolution node src/*.js",
|
|
49
|
+
"clean": "shx rm -f *.tgz && shx rm -f *.log",
|
|
50
|
+
"ci": "npm run clean && npm run lint && npm run test",
|
|
51
|
+
"create-package": "shx rm -f *.tgz && npm pack",
|
|
52
|
+
"image-build": "docker build --no-cache --progress=plain --tag=web_plsql .",
|
|
53
|
+
"image-save": "docker save web_plsql | gzip > web_plsql.tar.gz"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"basic-auth": "2.0.1",
|
|
57
|
+
"body-parser": "2.2.0",
|
|
58
|
+
"compression": "1.8.0",
|
|
59
|
+
"connect-multiparty": "2.2.0",
|
|
60
|
+
"cookie-parser": "1.4.7",
|
|
61
|
+
"debug": "4.4.0",
|
|
62
|
+
"escape-html": "1.0.3",
|
|
63
|
+
"express": "5.1.0",
|
|
64
|
+
"fs-extra": "11.3.0",
|
|
65
|
+
"http-parser-js": "0.5.10",
|
|
66
|
+
"morgan": "1.10.0",
|
|
67
|
+
"multer": "1.4.5-lts.2",
|
|
68
|
+
"oracledb": "6.8.0",
|
|
69
|
+
"rotating-file-stream": "3.2.6",
|
|
70
|
+
"zod": "3.24.2"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@types/basic-auth": "1.1.8",
|
|
74
|
+
"@types/body-parser": "1.19.5",
|
|
75
|
+
"@types/compression": "1.7.5",
|
|
76
|
+
"@types/cookie-parser": "1.4.8",
|
|
77
|
+
"@types/debug": "4.1.12",
|
|
78
|
+
"@types/escape-html": "1.0.4",
|
|
79
|
+
"@types/fs-extra": "11.0.4",
|
|
80
|
+
"@types/morgan": "1.9.9",
|
|
81
|
+
"@types/multer": "1.4.12",
|
|
82
|
+
"@types/node": "22.14.1",
|
|
83
|
+
"@types/oracledb": "6.6.0",
|
|
84
|
+
"@types/supertest": "6.0.3",
|
|
85
|
+
"eslint": "9.24.0",
|
|
86
|
+
"eslint-plugin-jsdoc": "50.6.9",
|
|
87
|
+
"prettier": "3.5.3",
|
|
88
|
+
"rimraf": "6.0.1",
|
|
89
|
+
"shx": "0.4.0",
|
|
90
|
+
"supertest": "7.1.0",
|
|
91
|
+
"typescript": "5.8.3",
|
|
92
|
+
"typescript-eslint": "8.30.1"
|
|
93
|
+
}
|
|
85
94
|
}
|
package/src/cgi.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Prepare the CGI information
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import {URL} from 'node:url';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('express').Request} Request
|
|
10
|
+
* @typedef {import('./types.js').environmentType} environmentType
|
|
11
|
+
* @typedef {import('./types.js').configPlSqlType} configPlSqlType
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** @type {environmentType} */
|
|
15
|
+
const DEFAULT_CGI = {
|
|
16
|
+
PLSQL_GATEWAY: 'WebDb',
|
|
17
|
+
GATEWAY_IVERSION: '2',
|
|
18
|
+
SERVER_SOFTWARE: 'web_plsql',
|
|
19
|
+
GATEWAY_INTERFACE: 'CGI/1.1',
|
|
20
|
+
SERVER_PORT: '',
|
|
21
|
+
SERVER_NAME: os.hostname(),
|
|
22
|
+
REQUEST_METHOD: '',
|
|
23
|
+
PATH_INFO: '',
|
|
24
|
+
SCRIPT_NAME: '',
|
|
25
|
+
REMOTE_ADDR: '',
|
|
26
|
+
SERVER_PROTOCOL: '',
|
|
27
|
+
REQUEST_PROTOCOL: '',
|
|
28
|
+
REMOTE_USER: '',
|
|
29
|
+
HTTP_COOKIE: '',
|
|
30
|
+
HTTP_USER_AGENT: '',
|
|
31
|
+
HTTP_HOST: '',
|
|
32
|
+
HTTP_ACCEPT: '',
|
|
33
|
+
HTTP_ACCEPT_ENCODING: '',
|
|
34
|
+
HTTP_ACCEPT_LANGUAGE: '',
|
|
35
|
+
HTTP_REFERER: '',
|
|
36
|
+
HTTP_X_FORWARDED_FOR: '',
|
|
37
|
+
WEB_AUTHENT_PREFIX: '',
|
|
38
|
+
DAD_NAME: '',
|
|
39
|
+
DOC_ACCESS_PATH: 'doc',
|
|
40
|
+
DOCUMENT_TABLE: '',
|
|
41
|
+
PATH_ALIAS: '',
|
|
42
|
+
REQUEST_CHARSET: 'UTF8',
|
|
43
|
+
REQUEST_IANA_CHARSET: 'UTF-8',
|
|
44
|
+
SCRIPT_PREFIX: '',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create the HTTP_COOKIE string
|
|
49
|
+
*
|
|
50
|
+
* @param {Request} req - The req object represents the HTTP request.
|
|
51
|
+
* @returns {string} - The string representation of the cookies.
|
|
52
|
+
*/
|
|
53
|
+
const getCookieString = (req) => {
|
|
54
|
+
let cookieString = '';
|
|
55
|
+
|
|
56
|
+
for (const propName in req.cookies) {
|
|
57
|
+
cookieString += `${propName}=${req.cookies[propName]};`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return cookieString;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get the script name and DAD name from a URL
|
|
65
|
+
*
|
|
66
|
+
* @param {Request} req - The req object represents the HTTP request.
|
|
67
|
+
* @returns {{script: string; prefix: string; dad: string}} - The DAD structure.
|
|
68
|
+
*/
|
|
69
|
+
const getPath = (req) => {
|
|
70
|
+
// create a valid url
|
|
71
|
+
const validUrl = `${req.protocol}://${os.hostname()}${req.originalUrl}`;
|
|
72
|
+
|
|
73
|
+
// get the pathname from the url (new URL('https://example.org/abc/xyz?123').pathname => /abc/xyz)
|
|
74
|
+
const pathname = new URL(validUrl).pathname;
|
|
75
|
+
|
|
76
|
+
const tmp = trimPath(pathname.substring(0, pathname.lastIndexOf('/') + 1));
|
|
77
|
+
const script = `/${tmp}`;
|
|
78
|
+
const prefix = `/${tmp.substring(0, tmp.lastIndexOf('/'))}`;
|
|
79
|
+
const dad = tmp.substring(tmp.indexOf('/') + 1);
|
|
80
|
+
|
|
81
|
+
return {script, prefix, dad};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get a path that is not enclodes in slashes
|
|
86
|
+
*
|
|
87
|
+
* @param {string} value - The value to trim.
|
|
88
|
+
* @returns {string} - The trimmed value.
|
|
89
|
+
*/
|
|
90
|
+
const trimPath = (value) => value.replace(/^\/+|\/+$/g, '');
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Create a CGI object
|
|
94
|
+
*
|
|
95
|
+
* @param {Request} req - The req object represents the HTTP request.
|
|
96
|
+
* @param {string} doctable - The document table.
|
|
97
|
+
* @param {environmentType} cgi - The additional cgi.
|
|
98
|
+
* @returns {environmentType} CGI object
|
|
99
|
+
*/
|
|
100
|
+
export const getCGI = (req, doctable, cgi) => {
|
|
101
|
+
const PROTOCOL = req.protocol ? req.protocol.toUpperCase() : '';
|
|
102
|
+
const PATH = getPath(req);
|
|
103
|
+
|
|
104
|
+
/** @type {environmentType} */
|
|
105
|
+
const CGI = {
|
|
106
|
+
SERVER_PORT: typeof req.socket.localPort === 'number' ? req.socket.localPort.toString() : '',
|
|
107
|
+
REQUEST_METHOD: req.method,
|
|
108
|
+
PATH_INFO: req.params.name,
|
|
109
|
+
SCRIPT_NAME: PATH.script,
|
|
110
|
+
REMOTE_ADDR: (req.ip ?? '').replace('::ffff:', ''),
|
|
111
|
+
SERVER_PROTOCOL: `${PROTOCOL}/${req.httpVersion}`,
|
|
112
|
+
REQUEST_PROTOCOL: PROTOCOL,
|
|
113
|
+
HTTP_COOKIE: getCookieString(req),
|
|
114
|
+
HTTP_USER_AGENT: req.get('user-agent') ?? '',
|
|
115
|
+
HTTP_HOST: req.get('host') ?? '',
|
|
116
|
+
HTTP_ACCEPT: req.get('accept') ?? '',
|
|
117
|
+
HTTP_ACCEPT_ENCODING: req.get('accept-encoding') ?? '',
|
|
118
|
+
HTTP_ACCEPT_LANGUAGE: req.get('accept-language') ?? '',
|
|
119
|
+
HTTP_REFERER: req.get('referer') ?? '',
|
|
120
|
+
HTTP_X_FORWARDED_FOR: req.get('x-forwarded-for') ?? '',
|
|
121
|
+
DAD_NAME: PATH.dad,
|
|
122
|
+
DOCUMENT_TABLE: doctable,
|
|
123
|
+
SCRIPT_PREFIX: PATH.prefix,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return Object.assign({}, DEFAULT_CGI, CGI, cgi);
|
|
127
|
+
};
|
package/src/error.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {inspect} from './trace.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert Error to a string.
|
|
5
|
+
*
|
|
6
|
+
* @param {unknown} error - The error.
|
|
7
|
+
* @returns {string} The string representation.
|
|
8
|
+
*/
|
|
9
|
+
export const errorToString = (error) => {
|
|
10
|
+
if (typeof error === 'string') {
|
|
11
|
+
return error;
|
|
12
|
+
} else if (error instanceof Error) {
|
|
13
|
+
const parts = [error.name];
|
|
14
|
+
if (typeof error.message === 'string' && error.message.length > 0) {
|
|
15
|
+
parts.push(error.message);
|
|
16
|
+
}
|
|
17
|
+
if (typeof error.stack === 'string' && error.stack.length > 0) {
|
|
18
|
+
parts.push(error.stack);
|
|
19
|
+
}
|
|
20
|
+
return parts.join('\n');
|
|
21
|
+
} else {
|
|
22
|
+
return inspect(error);
|
|
23
|
+
}
|
|
24
|
+
};
|
package/src/errorPage.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Error handling
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import util from 'node:util';
|
|
6
|
+
import escape from 'escape-html';
|
|
7
|
+
import {ProcedureError} from './procedureError.js';
|
|
8
|
+
import {RequestError} from './requestError.js';
|
|
9
|
+
import {inspectRequest, logToFile} from './trace.js';
|
|
10
|
+
import {errorToString} from './error.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {import('express').Request} Request
|
|
14
|
+
* @typedef {import('express').Response} Response
|
|
15
|
+
* @typedef {import('./types.js').BindParameterConfig} BindParameterConfig
|
|
16
|
+
* @typedef {import('./types.js').environmentType} environmentType
|
|
17
|
+
* @typedef {import('./types.js').configPlSqlHandlerType} configPlSqlHandlerType
|
|
18
|
+
* @typedef {{html: string; text: string}} outputType
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Convert value to string
|
|
23
|
+
* @param {unknown} value - The value to convert.
|
|
24
|
+
* @returns {string} - The string representation of the value.
|
|
25
|
+
*/
|
|
26
|
+
const inspect = (value) => util.inspect(value, {showHidden: false, depth: null, colors: false});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Convert LF and/or CR to <br>
|
|
30
|
+
* @param {string} text - The text to convert.
|
|
31
|
+
* @returns {string} - The converted text.
|
|
32
|
+
*/
|
|
33
|
+
const convertToHtml = (text) => {
|
|
34
|
+
let html = escape(text);
|
|
35
|
+
|
|
36
|
+
html = html.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
|
37
|
+
html = html.replace(/\t/g, ' ');
|
|
38
|
+
|
|
39
|
+
return html;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get html
|
|
44
|
+
* @param {string} text - The text to convert.
|
|
45
|
+
* @returns {string} - The converted text.
|
|
46
|
+
*/
|
|
47
|
+
const getHtml = (text) => `<p>${convertToHtml(text)}</p>`;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get text header
|
|
51
|
+
* @param {string} text - The text to convert.
|
|
52
|
+
* @returns {string} - The converted text.
|
|
53
|
+
*/
|
|
54
|
+
const getHeaderText = (text) => `\n${text}\n${'='.repeat(text.length)}\n`;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get html header
|
|
58
|
+
* @param {string} text - The text to convert.
|
|
59
|
+
* @returns {string} - The converted text.
|
|
60
|
+
*/
|
|
61
|
+
const getHeaderHtml = (text) => `<h1>${text}</h1>`;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get text
|
|
65
|
+
* @param {string} text - The text to convert.
|
|
66
|
+
* @returns {string} - The converted text.
|
|
67
|
+
*/
|
|
68
|
+
const getText = (text) => `${text}\n`;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get evnironment
|
|
72
|
+
* @param {outputType} output - The output.
|
|
73
|
+
* @param {environmentType} environment - The environment.
|
|
74
|
+
*/
|
|
75
|
+
const getEnvironment = (output, environment) => {
|
|
76
|
+
let html = '<table>';
|
|
77
|
+
let text = '';
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
for (const key in environment) {
|
|
81
|
+
html += `<tr><td>${key}:</td><td>${environment[key]}</td></tr>`;
|
|
82
|
+
text += `${key}=${environment[key]}\n`;
|
|
83
|
+
}
|
|
84
|
+
} catch (err) {
|
|
85
|
+
/* istanbul ignore next */
|
|
86
|
+
output.html += errorToString(err);
|
|
87
|
+
|
|
88
|
+
/* istanbul ignore next */
|
|
89
|
+
output.text += errorToString(err);
|
|
90
|
+
|
|
91
|
+
/* istanbul ignore next */
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
html += '</table>';
|
|
96
|
+
|
|
97
|
+
output.html += html;
|
|
98
|
+
output.text += text;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Show an error page
|
|
103
|
+
* @param {Request} req - The req object represents the HTTP request.
|
|
104
|
+
* @param {unknown} error - The error.
|
|
105
|
+
* @returns {outputType} - The output.
|
|
106
|
+
*/
|
|
107
|
+
const getError = (req, error) => {
|
|
108
|
+
let timestamp = new Date();
|
|
109
|
+
let message = '';
|
|
110
|
+
/** @type {environmentType | null} */
|
|
111
|
+
let environment = null;
|
|
112
|
+
/** @type {string | null} */
|
|
113
|
+
let sql = null;
|
|
114
|
+
/** @type {BindParameterConfig} */
|
|
115
|
+
let bind = {};
|
|
116
|
+
|
|
117
|
+
// what type of Error did we receive
|
|
118
|
+
if (error instanceof ProcedureError) {
|
|
119
|
+
timestamp = error.timestamp;
|
|
120
|
+
/* istanbul ignore next */
|
|
121
|
+
message = error.stack ?? '';
|
|
122
|
+
environment = error.environment;
|
|
123
|
+
sql = error.sql;
|
|
124
|
+
bind = error.bind;
|
|
125
|
+
} else if (error instanceof RequestError) {
|
|
126
|
+
timestamp = error.timestamp;
|
|
127
|
+
/* istanbul ignore next */
|
|
128
|
+
message = error.stack ?? '';
|
|
129
|
+
} else if (error instanceof Error) {
|
|
130
|
+
/* istanbul ignore next */
|
|
131
|
+
message = errorToString(error);
|
|
132
|
+
} else {
|
|
133
|
+
if (typeof error === 'string') {
|
|
134
|
+
/* istanbul ignore next */
|
|
135
|
+
message = `${error}\n`;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
/* istanbul ignore next */
|
|
139
|
+
new Error();
|
|
140
|
+
} catch (err) {
|
|
141
|
+
/* istanbul ignore next */
|
|
142
|
+
message += errorToString(err);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** @type {outputType} */
|
|
147
|
+
const output = {
|
|
148
|
+
html: '',
|
|
149
|
+
text: '',
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// timestamp
|
|
153
|
+
let header = 'TIMESTAMP';
|
|
154
|
+
output.html += getHeaderHtml(header);
|
|
155
|
+
output.html += getHtml(timestamp.toUTCString());
|
|
156
|
+
|
|
157
|
+
// error
|
|
158
|
+
header = 'ERROR';
|
|
159
|
+
output.html += getHeaderHtml(header);
|
|
160
|
+
output.html += getHtml(message);
|
|
161
|
+
output.text += getHeaderText(header);
|
|
162
|
+
output.text += getText(message);
|
|
163
|
+
|
|
164
|
+
// request
|
|
165
|
+
header = 'REQUEST';
|
|
166
|
+
output.text += getHeaderText(header);
|
|
167
|
+
output.text += getText(inspectRequest(req));
|
|
168
|
+
|
|
169
|
+
// parameters
|
|
170
|
+
if (typeof sql === 'string' && bind) {
|
|
171
|
+
header = 'PROCEDURE';
|
|
172
|
+
output.html += getHeaderHtml(header);
|
|
173
|
+
output.text += getHeaderText(header);
|
|
174
|
+
getProcedure(output, sql, bind);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// environment
|
|
178
|
+
if (environment) {
|
|
179
|
+
header = 'ENVIRONMENT';
|
|
180
|
+
output.html += getHeaderHtml(header);
|
|
181
|
+
output.text += getHeaderText(header);
|
|
182
|
+
getEnvironment(output, environment);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return output;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get procedure
|
|
190
|
+
* @param {outputType} output - The output.
|
|
191
|
+
* @param {string} sql - The SQL to execute.
|
|
192
|
+
* @param {BindParameterConfig} bind - The bind parameters.
|
|
193
|
+
*/
|
|
194
|
+
const getProcedure = (output, sql, bind) => {
|
|
195
|
+
let html = '<table>';
|
|
196
|
+
let text = '';
|
|
197
|
+
|
|
198
|
+
text += `PROCEDURE: ${sql}\n`;
|
|
199
|
+
html += `<tr><td>PROCEDURE:</td><td>${sql}</td></tr>`;
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
/* istanbul ignore else */
|
|
203
|
+
for (const key in bind) {
|
|
204
|
+
const value = inspect(bind[key].val);
|
|
205
|
+
|
|
206
|
+
html += `<tr><td>${key}:</td><td>${value}</td></tr>`;
|
|
207
|
+
text += `${key}: ${value}\n`;
|
|
208
|
+
}
|
|
209
|
+
} catch (err) {
|
|
210
|
+
/* istanbul ignore next */
|
|
211
|
+
output.html += err instanceof Error ? err.toString() : 'ERROR';
|
|
212
|
+
|
|
213
|
+
/* istanbul ignore next */
|
|
214
|
+
output.text += err instanceof Error ? err.toString() : 'ERROR';
|
|
215
|
+
/* istanbul ignore next */
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
html += '</table>';
|
|
220
|
+
|
|
221
|
+
output.html += html;
|
|
222
|
+
output.text += text;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* getHtmlPage
|
|
227
|
+
* @param {string} body - The body.
|
|
228
|
+
* @returns {string} - The html page.
|
|
229
|
+
*/
|
|
230
|
+
const getHtmlPage = (body) => `<!DOCTYPE html>
|
|
231
|
+
<html lang="en">
|
|
232
|
+
<head>
|
|
233
|
+
<meta charset="utf-8">
|
|
234
|
+
<title>web_plsql error page</title>
|
|
235
|
+
<style type="text/css">
|
|
236
|
+
html {
|
|
237
|
+
font-family: monospace, sans-serif;
|
|
238
|
+
font-size: 12px;
|
|
239
|
+
}
|
|
240
|
+
h1 {
|
|
241
|
+
font-size: 16px;
|
|
242
|
+
padding: 2px;
|
|
243
|
+
background-color: #cc0000;
|
|
244
|
+
}
|
|
245
|
+
</style>
|
|
246
|
+
</head>
|
|
247
|
+
<body>
|
|
248
|
+
${body}
|
|
249
|
+
</body>
|
|
250
|
+
</html>
|
|
251
|
+
`;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Show an error page
|
|
255
|
+
*
|
|
256
|
+
* @param {Request} req - The req object represents the HTTP request.
|
|
257
|
+
* @param {Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
258
|
+
* @param {configPlSqlHandlerType} options - The configuration options.
|
|
259
|
+
* @param {unknown} error - The error.
|
|
260
|
+
*/
|
|
261
|
+
export const errorPage = (req, res, options, error) => {
|
|
262
|
+
let output = {
|
|
263
|
+
html: '',
|
|
264
|
+
text: '',
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// get the error description
|
|
268
|
+
try {
|
|
269
|
+
output = getError(req, error);
|
|
270
|
+
} catch (err) {
|
|
271
|
+
/* istanbul ignore next */
|
|
272
|
+
const header = 'ERROR';
|
|
273
|
+
|
|
274
|
+
/* istanbul ignore next */
|
|
275
|
+
const message = errorToString(err);
|
|
276
|
+
|
|
277
|
+
/* istanbul ignore next */
|
|
278
|
+
output.html += getHeaderHtml(header) + getHtml(message);
|
|
279
|
+
|
|
280
|
+
/* istanbul ignore next */
|
|
281
|
+
output.text += getHeaderHtml(header) + getHtml(message);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// trace to file
|
|
285
|
+
logToFile(output.text);
|
|
286
|
+
|
|
287
|
+
// console
|
|
288
|
+
console.error(output.text);
|
|
289
|
+
|
|
290
|
+
// show page
|
|
291
|
+
if (options.errorStyle === 'basic') {
|
|
292
|
+
res.status(404).send('Page not found');
|
|
293
|
+
} else {
|
|
294
|
+
res.status(404).send(getHtmlPage(output.html));
|
|
295
|
+
}
|
|
296
|
+
};
|