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.
Files changed (96) hide show
  1. package/README.md +128 -111
  2. package/examples/server_apex.js +26 -0
  3. package/examples/server_sample.js +30 -0
  4. package/examples/sql/{doc_table.sql → doctable.sql} +1 -1
  5. package/examples/sql/install.sql +6 -9
  6. package/examples/sql/sample_package.sql +27 -0
  7. package/examples/sql/sample_package_body.sql +245 -0
  8. package/examples/static/sample.css +11 -10
  9. package/package.json +92 -83
  10. package/src/cgi.js +127 -0
  11. package/src/error.js +24 -0
  12. package/src/errorPage.js +296 -0
  13. package/src/file.js +95 -0
  14. package/src/handlerLogger.js +21 -0
  15. package/src/handlerMetrics.js +46 -0
  16. package/src/handlerPlSql.js +65 -0
  17. package/src/handlerUpload.js +32 -0
  18. package/src/index.js +17 -0
  19. package/src/oracle.js +80 -0
  20. package/src/parsePage.js +193 -0
  21. package/src/procedure.js +260 -0
  22. package/src/procedureError.js +40 -0
  23. package/src/procedureNamed.js +233 -0
  24. package/src/procedureSanitize.js +215 -0
  25. package/src/procedureVariable.js +57 -0
  26. package/src/request.js +103 -0
  27. package/src/{requestError.ts → requestError.js} +8 -4
  28. package/src/sendResponse.js +104 -0
  29. package/src/server.js +185 -0
  30. package/src/shutdown.js +53 -0
  31. package/src/stream.js +28 -0
  32. package/src/trace.js +74 -0
  33. package/src/tty.js +48 -0
  34. package/src/types.js +146 -0
  35. package/src/upload.js +92 -0
  36. package/src/version.js +38 -0
  37. package/types/cgi.d.ts +4 -0
  38. package/types/error.d.ts +1 -0
  39. package/types/errorPage.d.ts +10 -0
  40. package/types/file.d.ts +6 -0
  41. package/types/handlerLogger.d.ts +2 -0
  42. package/types/handlerMetrics.d.ts +4 -0
  43. package/types/handlerPlSql.d.ts +8 -0
  44. package/types/handlerUpload.d.ts +7 -0
  45. package/types/index.d.ts +10 -0
  46. package/types/oracle.d.ts +5 -0
  47. package/types/parsePage.d.ts +3 -0
  48. package/types/procedure.d.ts +10 -0
  49. package/types/procedureError.d.ts +23 -0
  50. package/types/procedureNamed.d.ts +14 -0
  51. package/types/procedureSanitize.d.ts +14 -0
  52. package/types/procedureVariable.d.ts +9 -0
  53. package/types/request.d.ts +7 -0
  54. package/types/requestError.d.ts +8 -0
  55. package/types/sendResponse.d.ts +4 -0
  56. package/types/server.d.ts +11 -0
  57. package/types/shutdown.d.ts +2 -0
  58. package/types/stream.d.ts +1 -0
  59. package/types/trace.d.ts +5 -0
  60. package/types/tty.d.ts +4 -0
  61. package/types/types.d.ts +251 -0
  62. package/types/upload.d.ts +5 -0
  63. package/types/version.d.ts +8 -0
  64. package/.editorconfig +0 -8
  65. package/.eslintignore +0 -3
  66. package/.eslintrc.js +0 -347
  67. package/CHANGELOG.md +0 -133
  68. package/examples/apex.js +0 -70
  69. package/examples/credentials.js +0 -22
  70. package/examples/oracledb_example.js +0 -30
  71. package/examples/sample.js +0 -101
  72. package/examples/sql/sample.pkb +0 -223
  73. package/examples/sql/sample.pks +0 -24
  74. package/jest.config.js +0 -207
  75. package/src/cgi.ts +0 -95
  76. package/src/config.ts +0 -97
  77. package/src/errorPage.ts +0 -286
  78. package/src/fileUpload.ts +0 -126
  79. package/src/index.ts +0 -65
  80. package/src/page.ts +0 -275
  81. package/src/procedure.ts +0 -360
  82. package/src/procedureError.ts +0 -27
  83. package/src/request.ts +0 -139
  84. package/src/stream.ts +0 -26
  85. package/src/trace.ts +0 -194
  86. package/test/.eslintrc.json +0 -5
  87. package/test/__tests__/cgi.ts +0 -96
  88. package/test/__tests__/config.ts +0 -41
  89. package/test/__tests__/errorPage.ts +0 -101
  90. package/test/__tests__/oracledb_mock.ts +0 -98
  91. package/test/__tests__/server.ts +0 -495
  92. package/test/__tests__/stream.ts +0 -21
  93. package/test/mock/oracledb.ts +0 -85
  94. package/test/static/static.html +0 -1
  95. package/tsconfig.json +0 -24
  96. package/tsconfig.src.json +0 -23
package/src/fileUpload.ts DELETED
@@ -1,126 +0,0 @@
1
- /*
2
- * Process file uploads
3
- */
4
-
5
- import path from 'path';
6
- import fs from 'fs';
7
- import express from 'express';
8
- import oracledb from 'oracledb';
9
-
10
- export type fileUploadType = {
11
- fieldValue: string;
12
- filename: string;
13
- physicalFilename: string;
14
- encoding: string;
15
- mimetype: string;
16
- size: number;
17
- };
18
- export type filesUploadType = Array<fileUploadType>;
19
-
20
- let sequencialID = 0;
21
-
22
- /**
23
- * Get the files
24
- *
25
- * @param {express.Request} req - The req object represents the HTTP request.
26
- * @returns {Promise<filesUploadType>} - Promise that resolves with an array of files to be uploaded.
27
- */
28
- export function getFiles(req: express.Request): filesUploadType {
29
- interface TCustomRequest extends express.Request {
30
- files: Array<any>;
31
- }
32
- const customRequest = req as TCustomRequest;
33
- const files: filesUploadType = [];
34
-
35
- // are there any files
36
- /* istanbul ignore next */
37
- if (typeof customRequest.files !== 'object') {
38
- return files;
39
- }
40
-
41
- // process the files
42
- for (const key in customRequest.files) {
43
- const file = customRequest.files[key];
44
-
45
- /* istanbul ignore else */
46
- if (typeof file.originalFilename === 'string' && file.originalFilename.length > 0) {
47
- // get a temporary filename
48
- const filename = getRandomizedFilename(file.originalFilename);
49
-
50
- // Add the field
51
- file.filename = filename;
52
-
53
- // Add the file to upload
54
- files.push({
55
- fieldValue: file.fieldName,
56
- filename: file.originalFilename,
57
- physicalFilename: path.normalize(path.resolve(file.path)),
58
- encoding: '',
59
- mimetype: file.type,
60
- size: file.size
61
- });
62
- }
63
- }
64
-
65
- return files;
66
- }
67
-
68
- /**
69
- * Upload the given array of files and return a promise that resolves when all uploads have been finished.
70
- *
71
- * @param {Array<string>} files - array of file path's.
72
- * @param {string} docTableName - name of the oracle table holding the uploaded files.
73
- * @param {oracledb.Connection} databaseConnection - Database connection.
74
- * @returns {Promise<void>} - Promise that resolves when the request has been fullfilled.
75
- */
76
- export async function uploadFiles(files: filesUploadType, docTableName: string, databaseConnection: oracledb.Connection): Promise<void> {
77
- await Promise.all(files.map(file => uploadFile(file, docTableName, databaseConnection)));
78
- }
79
-
80
- /*
81
- * Upload the given file and return a promise.
82
- */
83
- export function uploadFile(file: fileUploadType, docTableName: string, databaseConnection: oracledb.Connection): Promise<void> {
84
- return new Promise((resolve, reject) => {
85
- /* istanbul ignore next */
86
- if (typeof docTableName !== 'string' || docTableName.length === 0) {
87
- reject(new Error('The option "docTableName" has not been defined or the name is empty'));
88
- }
89
-
90
- let blobContent;
91
- try {
92
- blobContent = fs.readFileSync(file.physicalFilename);
93
- } catch (err) {
94
- /* istanbul ignore next */
95
- reject(new Error(`Unable to read file "${file.physicalFilename}"\n${err instanceof Error ? err.toString() : ''}`));
96
- /* istanbul ignore next */
97
- return;
98
- }
99
-
100
- const sql = `INSERT INTO ${docTableName} (name, mime_type, doc_size, dad_charset, last_updated, content_type, blob_content) VALUES (:name, :mime_type, :doc_size, 'ascii', SYSDATE, 'BLOB', :blob_content)`;
101
- const bind = {
102
- name: file.fieldValue,
103
- mime_type: file.mimetype,
104
- doc_size: file.size,
105
- blob_content: {
106
- val: blobContent,
107
- type: oracledb.BUFFER
108
- }
109
- };
110
-
111
- databaseConnection.execute(sql, bind, {autoCommit: true})
112
- .then(() => {
113
- resolve();
114
- }).catch(/* istanbul ignore next */(e: any) => {
115
- reject(new Error(`Unable to insert file "${file.physicalFilename}"\n` + e.toString()));
116
- });
117
- });
118
- }
119
-
120
- /*
121
- * get a randomized filename
122
- */
123
- function getRandomizedFilename(filename: string): string {
124
- ++sequencialID;
125
- return 'F' + (Date.now() + sequencialID).toString() + '/' + path.basename(filename);
126
- }
package/src/index.ts DELETED
@@ -1,65 +0,0 @@
1
- /*
2
- * Express middleware for Oracle PL/SQL
3
- */
4
-
5
- import url from 'url';
6
- import express from 'express';
7
- import oracledb from 'oracledb';
8
- import {processRequest} from './request';
9
- import {validate, oracleExpressMiddleware$options} from './config';
10
- import {RequestError} from './requestError';
11
- import {errorPage} from './errorPage';
12
- import {Trace} from './trace';
13
- const version = require('../package.json').version; // eslint-disable-line @typescript-eslint/no-var-requires
14
-
15
- /**
16
- * Express middleware.
17
- *
18
- * @param {Promise<oracledb.Pool>} databasePoolPromise - The promise that will be fullfilled when the database pool has been allocated.
19
- * @param {Object} options - The configuration options.
20
- * @returns {Function} - The request handler.
21
- */
22
- const webplsql = function (databasePoolPromise: Promise<oracledb.Pool>, options: oracleExpressMiddleware$options) {
23
- // validate the configuration options
24
- const validOptions = validate(options);
25
-
26
- // instantiate trace object
27
- const trace = new Trace(validOptions.trace);
28
-
29
- return function handler(req: express.Request, res: express.Response/*, next: () => void*/) {
30
- requestHandler(req, res, databasePoolPromise, validOptions, trace);
31
- };
32
- };
33
-
34
- webplsql.version = version;
35
- exports = module.exports = webplsql;
36
-
37
- /*
38
- * express.Request handler
39
- */
40
- function requestHandler(req: express.Request, res: express.Response, databasePoolPromise: Promise<oracledb.Pool>, options: oracleExpressMiddleware$options, trace: Trace) {
41
- try {
42
- trace.start(req);
43
-
44
- // should we switch to the default page if there is one defined
45
- if (typeof req.params.name !== 'string' || req.params.name.length === 0) {
46
- if (typeof options.defaultPage === 'string' && options.defaultPage.length > 0) {
47
- const newUrl = url.resolve(req.originalUrl + '/' + options.defaultPage, '');
48
- trace.write(`Redirect to the url "${newUrl}"`);
49
- res.redirect(newUrl);
50
- } else {
51
- /* istanbul ignore next */
52
- errorPage(req, res, options, trace, new RequestError('No procedure name given and no default page has been specified'));
53
- }
54
- } else {
55
- processRequest(req, res, options, databasePoolPromise, trace)
56
- .catch(e => {
57
- /* istanbul ignore next */
58
- errorPage(req, res, options, trace, e);
59
- });
60
- }
61
- } catch (err) {
62
- /* istanbul ignore next */
63
- errorPage(req, res, options, trace, err);
64
- }
65
- }
package/src/page.ts DELETED
@@ -1,275 +0,0 @@
1
- /*
2
- * Page the raw page content and return the content to the client
3
- */
4
-
5
- import {Trace} from './trace';
6
- import express from 'express';
7
-
8
- type cookieType = {
9
- name: string;
10
- value: string;
11
- path?: string;
12
- domain?: string;
13
- secure?: string;
14
- expires?: Date;
15
- httpOnly?: boolean;
16
- };
17
-
18
- type pageType = {
19
- body: string;
20
- head: {
21
- cookies: Array<cookieType>;
22
- contentType?: string;
23
- contentLength?: number;
24
- statusCode?: number;
25
- statusDescription?: string;
26
- redirectLocation?: string;
27
- otherHeaders: Record<string, unknown>;
28
- server?: string;
29
- };
30
- file: {
31
- fileType: any;
32
- fileSize: any;
33
- fileBlob: any;
34
- };
35
- };
36
-
37
- /**
38
- * Parse the header and split it up into the individual components
39
- *
40
- * @param {string} text - The text returned from the PL/SQL procedure.
41
- * @returns {Object} - The parsed page.
42
- */
43
- export function parse(text: string): pageType {
44
- const page: pageType = {
45
- body: '',
46
- head: {
47
- cookies: [],
48
- otherHeaders: {}
49
- },
50
- file: {
51
- fileType: null,
52
- fileSize: null,
53
- fileBlob: null
54
- }
55
- };
56
-
57
- //
58
- // 1) Split up the text in header and body
59
- //
60
-
61
- // Find the end of the header identified by \n\n
62
- let head = '';
63
- const headerEndPosition = text.indexOf('\n\n');
64
- if (headerEndPosition === -1) {
65
- head = text;
66
- } else {
67
- head = text.substring(0, headerEndPosition + 2);
68
- page.body = text.substring(headerEndPosition + 2);
69
- }
70
-
71
- //
72
- // 2) parse the headers
73
- //
74
-
75
- head.split('\n').forEach(line => {
76
- const header = getHeader(line);
77
-
78
- if (header) {
79
- switch (header.name.toLowerCase()) {
80
- case 'set-cookie':
81
- {
82
- const cookie = parseCookie(header.value);
83
- /* istanbul ignore else */
84
- if (cookie !== null) {
85
- page.head.cookies.push(cookie);
86
- }
87
- }
88
- break;
89
-
90
- case 'content-type':
91
- page.head.contentType = header.value;
92
- break;
93
-
94
- case 'x-db-content-length':
95
- {
96
- const contentLength = parseInt(header.value, 10);
97
- /* istanbul ignore else */
98
- if (!Number.isNaN(contentLength)) {
99
- page.head.contentLength = contentLength;
100
- }
101
- }
102
- break;
103
-
104
- case 'status':
105
- {
106
- const statusCode = parseInt(header.value, 10);
107
- /* istanbul ignore else */
108
- if (!Number.isNaN(statusCode)) {
109
- page.head.statusCode = statusCode;
110
- const index = header.value.indexOf(' ');
111
- /* istanbul ignore else */
112
- if (index !== -1) {
113
- page.head.statusDescription = header.value.substr(index + 1);
114
- }
115
- }
116
- }
117
- break;
118
-
119
- case 'location':
120
- page.head.redirectLocation = header.value;
121
- break;
122
-
123
- case 'x-oracle-ignore':
124
- break;
125
-
126
- default:
127
- page.head.otherHeaders[header.name] = header.value;
128
- break;
129
- }
130
- }
131
- });
132
-
133
- return page;
134
- }
135
-
136
- /*
137
- * get a header line
138
- */
139
- function getHeader(line: string): {name: string; value: string} | null {
140
- const index = line.indexOf(':');
141
-
142
- if (index !== -1) {
143
- return {
144
- name: line.substr(0, index).trim(),
145
- value: line.substr(index + 1).trim()
146
- };
147
- }
148
-
149
- return null;
150
- }
151
-
152
- /*
153
- * Send "default" response to the browser
154
- */
155
- export function send(req: express.Request, res: express.Response, page: {body: string; head: any; file: any}, trace: Trace): void {
156
- trace.write('send: ENTER');
157
-
158
- // Send the "cookies"
159
- page.head.cookies.forEach((cookie: Record<string, unknown>) => {
160
- const name = cookie.name as string;
161
- const value = cookie.value as string;
162
-
163
- delete cookie.name;
164
- delete cookie.value;
165
-
166
- res.cookie(name, value, cookie);
167
- trace.append(`send: res.cookie("${name}", "${value}")\n`);
168
- });
169
-
170
- // If there is a "redirectLocation" header, we immediately redirect and return
171
- if (typeof page.head.redirectLocation === 'string' && page.head.redirectLocation.length > 0) {
172
- res.redirect(302, page.head.redirectLocation);
173
- trace.append(`send: res.redirect(302, "${page.head.redirectLocation}")\n`);
174
- return;
175
- }
176
-
177
- // Send all the "otherHeaders"
178
- for (const key in page.head.otherHeaders) {
179
- res.set(key, page.head.otherHeaders[key]);
180
- trace.append(`send: res.set("${key}", "${page.head.otherHeaders[key]}")\n`);
181
- }
182
-
183
- // If this is a file download, we eventually set the "Content-Type" and the file content and then return.
184
- if (page.file.fileType === 'B' || page.file.fileType === 'F') {
185
- if (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {
186
- res.writeHead(200, {'Content-Type': page.head.contentType});
187
- trace.append(`sendFile: res.writeHead("Content-Type", "${page.head.contentType}")\n`);
188
- }
189
- res.end(page.file.fileBlob, 'binary');
190
- trace.append('send: res.end()\n');
191
- return;
192
- }
193
-
194
- // Is the a "contentType" header
195
- if (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {
196
- res.set('Content-Type', page.head.contentType);
197
- trace.append(`send: res.set("Content-Type", "${page.head.contentType}")\n`);
198
- }
199
-
200
- // If we have a "Status" header, we send the header and then return.
201
- if (typeof page.head.statusCode === 'number') {
202
- res.status(page.head.statusCode).send(page.head.statusDescription);
203
- return;
204
- }
205
-
206
- // Send the body
207
- res.send(page.body);
208
- trace.append(`send: res.send\n${'-'.repeat(30)}${page.body}\n${'-'.repeat(30)}\n`);
209
-
210
- trace.write('send: EXIT');
211
- }
212
-
213
- /*
214
- * Parses a cookie string
215
- */
216
- function parseCookie(text: string): cookieType | null {
217
- // validate
218
- /* istanbul ignore next */
219
- if (typeof text !== 'string' || text.trim().length === 0) {
220
- return null;
221
- }
222
-
223
- // split the cookie into it's parts
224
- let cookieElements = text.split(';');
225
-
226
- // trim cookie elements
227
- cookieElements = cookieElements.map(element => element.trim());
228
-
229
- // get name and value
230
- const index = cookieElements[0].indexOf('=');
231
- /* istanbul ignore next */
232
- if (index <= 0) {
233
- // if the index is -1, there is no equal sign and if it's 0 the name is empty
234
- return null;
235
- }
236
- const cookie: any = {};
237
- cookie.name = cookieElements[0].substring(0, index).trim();
238
- cookie.value = cookieElements[0].substring(index + 1).trim();
239
-
240
- // remove the fisrt element
241
- cookieElements.shift();
242
-
243
- // get the other options
244
- cookieElements.forEach(element => {
245
- if (element.indexOf('path=') === 0) {
246
- cookie.path = element.substring(5);
247
- } else if (element.toLowerCase().indexOf('domain=') === 0) {
248
- cookie.domain = element.substring(7);
249
- } else if (element.toLowerCase().indexOf('secure=') === 0) {
250
- /* istanbul ignore next */
251
- cookie.secure = element.substring(7);
252
- } else if (element.toLowerCase().indexOf('expires=') === 0) {
253
- const date = tryDecodeDate(element.substring(8));
254
- if (date) {
255
- cookie.expires = date;
256
- }
257
- } else if (element.toLowerCase().indexOf('httponly') === 0) {
258
- cookie.httpOnly = true;
259
- }
260
- });
261
-
262
- return cookie;
263
- }
264
-
265
- /*
266
- * Decode a date
267
- */
268
- function tryDecodeDate(value: string): Date | null {
269
- try {
270
- return new Date(value);
271
- } catch (err) {
272
- /* istanbul ignore next */
273
- return null;
274
- }
275
- }