@sap/async-xsjs 1.0.2
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/CHANGELOG.md +26 -0
- package/LICENSE +37 -0
- package/README.md +445 -0
- package/differences.md +162 -0
- package/docs/$.Application.html +262 -0
- package/docs/$.Session.html +674 -0
- package/docs/$.db.CallableStatement.html +2524 -0
- package/docs/$.db.Connection.html +511 -0
- package/docs/$.db.ParameterMetaData.html +805 -0
- package/docs/$.db.PreparedStatement.html +1796 -0
- package/docs/$.db.ResultSet.html +1308 -0
- package/docs/$.db.ResultSetMetaData.html +800 -0
- package/docs/$.db.SQLException.html +259 -0
- package/docs/$.db.html +773 -0
- package/docs/$.hdb.ColumnMetadata.html +438 -0
- package/docs/$.hdb.Connection.html +663 -0
- package/docs/$.hdb.ProcedureResult.html +280 -0
- package/docs/$.hdb.ResultSet.html +324 -0
- package/docs/$.hdb.ResultSetIterator.html +315 -0
- package/docs/$.hdb.ResultSetMetaData.html +259 -0
- package/docs/$.hdb.SQLException.html +259 -0
- package/docs/$.hdb.html +557 -0
- package/docs/$.html +471 -0
- package/docs/$.jobs.Job.html +783 -0
- package/docs/$.jobs.JobLog.html +380 -0
- package/docs/$.jobs.JobSchedules.html +852 -0
- package/docs/$.jobs.html +238 -0
- package/docs/$.net.Destination.html +304 -0
- package/docs/$.net.Mail.Part.html +510 -0
- package/docs/$.net.Mail.html +504 -0
- package/docs/$.net.SMTPConnection.html +347 -0
- package/docs/$.net.html +749 -0
- package/docs/$.net.http.Client.html +562 -0
- package/docs/$.net.http.Destination.html +237 -0
- package/docs/$.net.http.Request.html +567 -0
- package/docs/$.net.http.html +292 -0
- package/docs/$.security.AntiVirus.html +361 -0
- package/docs/$.security.Store.html +636 -0
- package/docs/$.security.crypto.html +414 -0
- package/docs/$.security.html +247 -0
- package/docs/$.security.x509.html +373 -0
- package/docs/$.text.analysis.Session.html +983 -0
- package/docs/$.text.analysis.html +242 -0
- package/docs/$.text.html +246 -0
- package/docs/$.text.mining.Session.html +2018 -0
- package/docs/$.text.mining.html +242 -0
- package/docs/$.trace.html +525 -0
- package/docs/$.util.SAXParser.html +955 -0
- package/docs/$.util.Zip.html +474 -0
- package/docs/$.util.codec.html +414 -0
- package/docs/$.util.compression.html +357 -0
- package/docs/$.util.html +325 -0
- package/docs/$.util.sql.html +290 -0
- package/docs/$.web.Body.html +333 -0
- package/docs/$.web.EntityList.html +296 -0
- package/docs/$.web.TupelList.html +496 -0
- package/docs/$.web.WebEntityRequest.html +393 -0
- package/docs/$.web.WebEntityResponse.html +392 -0
- package/docs/$.web.WebRequest.html +560 -0
- package/docs/$.web.WebResponse.html +609 -0
- package/docs/$.web.html +246 -0
- package/docs/Copyright-SAP.html +39 -0
- package/docs/Disclaimer-SAP.html +55 -0
- package/docs/index.html +232 -0
- package/docs/styles/jsdoc-default.css +382 -0
- package/lib/AppConfig.js +36 -0
- package/lib/AuditLogger.js +41 -0
- package/lib/cacert.js +26 -0
- package/lib/ctypes.js +153 -0
- package/lib/destinations/dest-provider.js +57 -0
- package/lib/index.js +235 -0
- package/lib/jobs/Action.js +40 -0
- package/lib/jobs/Job.js +100 -0
- package/lib/jobs/JobManager.js +150 -0
- package/lib/jobs/JobsRuntime.js +133 -0
- package/lib/jobs/SqlScriptJobRunner.js +36 -0
- package/lib/jobs/XsjsJobRunner.js +78 -0
- package/lib/jobs/index.js +11 -0
- package/lib/logging.js +16 -0
- package/lib/middleware.js +125 -0
- package/lib/odata/ODataService.js +125 -0
- package/lib/odata/index.js +7 -0
- package/lib/odata/service-factory.js +26 -0
- package/lib/passport-noauth.js +17 -0
- package/lib/routes.js +115 -0
- package/lib/runtime.js +740 -0
- package/lib/sandbox.js +40 -0
- package/lib/utils/XsJsFunctionRunner.js +57 -0
- package/lib/utils/XsJsLibFunctionRunner.js +57 -0
- package/lib/utils/buffer-utils.js +77 -0
- package/lib/utils/compression-utils.js +14 -0
- package/lib/utils/date-utils.js +104 -0
- package/lib/utils/errors/HttpError.js +20 -0
- package/lib/utils/errors/wrap-app-error.js +18 -0
- package/lib/utils/index.js +17 -0
- package/lib/utils/xs-function-runner.js +51 -0
- package/lib/utils/xs-types.js +21 -0
- package/lib/utils/xspath.js +36 -0
- package/lib/utils/xsstack.js +28 -0
- package/lib/views/error.html +28 -0
- package/lib/xsjs/Application.js +28 -0
- package/lib/xsjs/Locale.js +53 -0
- package/lib/xsjs/Session.js +31 -0
- package/lib/xsjs/constants.js +71 -0
- package/lib/xsjs/db/common/DbBase.js +85 -0
- package/lib/xsjs/db/common/DbOptions.js +163 -0
- package/lib/xsjs/db/common/arguments-validation.js +102 -0
- package/lib/xsjs/db/common/connection.js +12 -0
- package/lib/xsjs/db/common/enums.js +93 -0
- package/lib/xsjs/db/common/execute-batch.js +38 -0
- package/lib/xsjs/db/common/parse-time.js +139 -0
- package/lib/xsjs/db/dbapi/CallableStatement.js +192 -0
- package/lib/xsjs/db/dbapi/Connection.js +78 -0
- package/lib/xsjs/db/dbapi/DB.js +39 -0
- package/lib/xsjs/db/dbapi/ParameterMetaData.js +118 -0
- package/lib/xsjs/db/dbapi/PreparedStatement.js +78 -0
- package/lib/xsjs/db/dbapi/ResultSet.js +220 -0
- package/lib/xsjs/db/dbapi/ResultSetMetaData.js +116 -0
- package/lib/xsjs/db/dbapi/Statement.js +514 -0
- package/lib/xsjs/db/dbapi/conversions.js +113 -0
- package/lib/xsjs/db/dbapi/fetch-rows.js +32 -0
- package/lib/xsjs/db/hdbapi/Connection.js +525 -0
- package/lib/xsjs/db/hdbapi/HDB.js +32 -0
- package/lib/xsjs/db/hdbapi/ResultSetIterator.js +40 -0
- package/lib/xsjs/db/hdbapi/convert.js +77 -0
- package/lib/xsjs/db/hdbapi/table-string-parser.js +52 -0
- package/lib/xsjs/db/index.js +4 -0
- package/lib/xsjs/index.js +13 -0
- package/lib/xsjs/jobs/Job.js +228 -0
- package/lib/xsjs/jobs/Jobs.js +11 -0
- package/lib/xsjs/jobs/Logs.js +127 -0
- package/lib/xsjs/jobs/Schedule.js +110 -0
- package/lib/xsjs/jobs/Schedules.js +108 -0
- package/lib/xsjs/net/Destination.js +43 -0
- package/lib/xsjs/net/http/Client.js +220 -0
- package/lib/xsjs/net/http/HTTP.js +72 -0
- package/lib/xsjs/net/index.js +5 -0
- package/lib/xsjs/net/smtp/Mail.js +38 -0
- package/lib/xsjs/net/smtp/Part.js +30 -0
- package/lib/xsjs/net/smtp/SMTPConnection.js +39 -0
- package/lib/xsjs/net/smtp/index.js +18 -0
- package/lib/xsjs/net/smtp/nodemailer-util.js +77 -0
- package/lib/xsjs/require.js +39 -0
- package/lib/xsjs/security/AntiVirus.js +31 -0
- package/lib/xsjs/security/Store.js +119 -0
- package/lib/xsjs/security/crypto.js +23 -0
- package/lib/xsjs/security/index.js +5 -0
- package/lib/xsjs/security/x509.js +12 -0
- package/lib/xsjs/text/analysis/Session.js +128 -0
- package/lib/xsjs/text/index.js +30 -0
- package/lib/xsjs/text/mining/Session.js +82 -0
- package/lib/xsjs/trace/trace.js +41 -0
- package/lib/xsjs/util/SAXParser.js +174 -0
- package/lib/xsjs/util/Zip.js +220 -0
- package/lib/xsjs/util/codec.js +33 -0
- package/lib/xsjs/util/compression.js +24 -0
- package/lib/xsjs/util/index.js +22 -0
- package/lib/xsjs/web/BasicWebEntity.js +41 -0
- package/lib/xsjs/web/EntityList.js +11 -0
- package/lib/xsjs/web/TupelLists/CookiesTupelList.js +47 -0
- package/lib/xsjs/web/TupelLists/HeadersTupelList.js +55 -0
- package/lib/xsjs/web/TupelLists/ParametersTupelList.js +83 -0
- package/lib/xsjs/web/TupelLists/TupelListBase.js +45 -0
- package/lib/xsjs/web/WebBody.js +135 -0
- package/lib/xsjs/web/WebEntityRequest.js +40 -0
- package/lib/xsjs/web/WebEntityResponse.js +26 -0
- package/lib/xsjs/web/WebRequest.js +209 -0
- package/lib/xsjs/web/WebResponse.js +183 -0
- package/lib/xsjs/web/index.js +4 -0
- package/lib/xsjs/web/utils/HeadersParser.js +53 -0
- package/lib/xsjs/web/utils/HttpRequestParser.js +93 -0
- package/lib/xsjs/web/utils/MultipartParser.js +163 -0
- package/lib/xsjs/web/utils/MultipartResponseBuilder.js +73 -0
- package/lib/xsjs/web/utils/SetCookieParser.js +32 -0
- package/lib/xsjslib/TextBundleWrapper.js +46 -0
- package/lib/xsjslib/index.js +11 -0
- package/npm-shrinkwrap.json +11540 -0
- package/package.json +84 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var WebRequest = require('./WebRequest');
|
|
4
|
+
var WebResponse = require('./WebResponse');
|
|
5
|
+
var WebEntityResponse = require('./WebEntityResponse');
|
|
6
|
+
var CRLF = require('../constants').WEB.MESSAGES.LINE_BREAK;
|
|
7
|
+
var HttpRequestParser = require('./utils/HttpRequestParser');
|
|
8
|
+
var MultipartResponseBuilder = require('./utils/MultipartResponseBuilder');
|
|
9
|
+
var buffUtils = require('../../utils/buffer-utils');
|
|
10
|
+
var Locale = require('../Locale');
|
|
11
|
+
|
|
12
|
+
module.exports = WebBody;
|
|
13
|
+
|
|
14
|
+
function WebBody(bodyOwner, bodyContent, indexOpt) {
|
|
15
|
+
// a WebBody cannot be used on its own. The body owner is an object that has a property named 'body'
|
|
16
|
+
this._bodyOwner = bodyOwner;
|
|
17
|
+
|
|
18
|
+
if (indexOpt) {
|
|
19
|
+
this._content = extractContentOfBlobColumn(bodyContent, indexOpt);
|
|
20
|
+
} else if (isWebResponse(bodyContent)) {
|
|
21
|
+
addSpecificHttpHeadersToBodyOwner(this);
|
|
22
|
+
setBodyFromWebResponse(this, bodyContent);
|
|
23
|
+
} else if (isWebEntityResponse(bodyContent)) {
|
|
24
|
+
addSpecificHttpHeadersToBodyOwner(this);
|
|
25
|
+
setBodyFromWebEntityResponse(this, bodyContent);
|
|
26
|
+
} else {
|
|
27
|
+
this._content = bodyContent;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function extractContentOfBlobColumn(resultSet, index) {
|
|
32
|
+
if (index > resultSet._columnInfo.length) {
|
|
33
|
+
throw new Error('No column found for index ' + index);
|
|
34
|
+
}
|
|
35
|
+
return resultSet._row[index - 1];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function addSpecificHttpHeadersToBodyOwner(webBody) {
|
|
39
|
+
webBody._bodyOwner.headers.set('content-type', 'application/http');
|
|
40
|
+
webBody._bodyOwner.headers.set('content-transfer-encoding', 'binary');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isWebResponse(arg) {
|
|
44
|
+
return arg instanceof WebResponse;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isWebEntityResponse(arg) {
|
|
48
|
+
return arg instanceof WebEntityResponse;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function setBodyFromWebResponse(webBody, webResponse) {
|
|
52
|
+
webBody._content = '';
|
|
53
|
+
addStatusLine(webBody, webResponse);
|
|
54
|
+
addHeaders(webBody, webResponse);
|
|
55
|
+
addCookies(webBody, webResponse);
|
|
56
|
+
addTheBody(webBody, webResponse);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function addTheBody(webBody, webEntityResponse) {
|
|
60
|
+
if (webEntityResponse.entities.length === 0) {
|
|
61
|
+
webBody._content += CRLF;
|
|
62
|
+
webBody._content += webEntityResponse.body.asString();
|
|
63
|
+
} else {
|
|
64
|
+
var boundary = MultipartResponseBuilder.generateBoundary();
|
|
65
|
+
webBody._content += ('content-type: multipart/mixed; boundary=' + boundary) + CRLF;
|
|
66
|
+
webBody._content += CRLF;
|
|
67
|
+
webBody._content += MultipartResponseBuilder.build(webEntityResponse, boundary);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function addStatusLine(webBody, webResponse) {
|
|
72
|
+
webBody._content += webResponse._httpVersion + ' ' + webResponse.status + ' ' + webResponse.statusMessage + CRLF;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isMultipart(name, value) {
|
|
76
|
+
return (name === 'content-type' && value.indexOf('multipart') > -1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function addHeaders(webBody, webEntityResponse) {
|
|
80
|
+
webEntityResponse.headers.forEach(function (singleTupelPair) {
|
|
81
|
+
if (!isMultipart(singleTupelPair.name, singleTupelPair.value)) {
|
|
82
|
+
webBody._content += singleTupelPair.name + ': ' + singleTupelPair.value + CRLF;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function addCookies(webBody, webResponse) {
|
|
88
|
+
webResponse.cookies.forEach(function (singleCookie) {
|
|
89
|
+
webBody._content += 'set-cookie: ' + singleCookie.name + '=' + singleCookie.value + CRLF;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function setBodyFromWebEntityResponse(webBody, webEntityResponse) {
|
|
94
|
+
webBody._content = '';
|
|
95
|
+
addHeaders(webBody, webEntityResponse);
|
|
96
|
+
addTheBody(webBody, webEntityResponse);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
WebBody.prototype.asString = function () {
|
|
100
|
+
if (this._content === null || this._content === undefined || typeof this._content === 'number') {
|
|
101
|
+
return '' + this._content;
|
|
102
|
+
}
|
|
103
|
+
if (buffUtils.isBinary(this._content)) {
|
|
104
|
+
return buffUtils.toBuffer(this._content).toString('utf8');
|
|
105
|
+
}
|
|
106
|
+
if (typeof this._content === 'boolean') {
|
|
107
|
+
return this._content ? '1' : '0';
|
|
108
|
+
}
|
|
109
|
+
return this._content;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
WebBody.prototype._retrieveContent = function () {
|
|
113
|
+
return buffUtils.isBinary(this._content) ? buffUtils.toBuffer(this._content) : this.asString();
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
WebBody.prototype.asArrayBuffer = function () {
|
|
117
|
+
var content = buffUtils.isBinary(this._content) ? this._content : Buffer.from(this._content, 'utf8');
|
|
118
|
+
return buffUtils.toArrayBuffer(content);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
WebBody.prototype.asWebRequest = function () {
|
|
122
|
+
var bodyOwnerHeaders = this._bodyOwner.headers;
|
|
123
|
+
if (!bodyOwnerHeaders) {
|
|
124
|
+
throw new Error('Cannot get Body as WebRequest. The object to which the current body belongs does not have any headers.');
|
|
125
|
+
}
|
|
126
|
+
if (bodyOwnerHeaders.get('Content-Type') !== 'application/http') {
|
|
127
|
+
throw new Error('Cannot get Body as WebRequest. Content-Type header should be equal to "application/http" in order to proceed.');
|
|
128
|
+
}
|
|
129
|
+
if (bodyOwnerHeaders.get('Content-Transfer-Encoding') !== 'binary') {
|
|
130
|
+
throw new Error('Cannot get Body as WebRequest. Content-Transfer-Encoding header should be equal to "binary" in order to proceed.');
|
|
131
|
+
}
|
|
132
|
+
var req = HttpRequestParser.parse(this.asString());
|
|
133
|
+
var locale = new Locale(req);
|
|
134
|
+
return new WebRequest(req, locale);
|
|
135
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var util = require('util');
|
|
4
|
+
var ParametersTupelList = require('./TupelLists/ParametersTupelList');
|
|
5
|
+
var BasicWebEntity = require('./BasicWebEntity');
|
|
6
|
+
|
|
7
|
+
module.exports = WebEntityRequest;
|
|
8
|
+
|
|
9
|
+
function WebEntityRequest(arg) {
|
|
10
|
+
BasicWebEntity.call(this, arg);
|
|
11
|
+
|
|
12
|
+
if (!arg) {
|
|
13
|
+
this.parameters = new ParametersTupelList();
|
|
14
|
+
} else {
|
|
15
|
+
var req = arg;
|
|
16
|
+
this.parameters = new ParametersTupelList();
|
|
17
|
+
this.parameters._addData(req.query);
|
|
18
|
+
addParametersFromBody(this, req);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.entities.create = function() {
|
|
22
|
+
var newEntity = new WebEntityRequest();
|
|
23
|
+
this.push(newEntity);
|
|
24
|
+
return newEntity;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
util.inherits(WebEntityRequest, BasicWebEntity);
|
|
29
|
+
|
|
30
|
+
function addParametersFromBody(webEntityRequest, expressReq) {
|
|
31
|
+
webEntityRequest.parameters._addData(expressReq['form-urlencoded']);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
WebEntityRequest.create = function(headers, parameters, body) {
|
|
35
|
+
var entityRequest = new WebEntityRequest();
|
|
36
|
+
entityRequest.headers._addData(headers);
|
|
37
|
+
entityRequest.parameters._addData(parameters);
|
|
38
|
+
entityRequest.setBody(body);
|
|
39
|
+
return entityRequest;
|
|
40
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var util = require('util');
|
|
4
|
+
var BasicWebEntity = require('./BasicWebEntity');
|
|
5
|
+
|
|
6
|
+
module.exports = WebEntityResponse;
|
|
7
|
+
|
|
8
|
+
function WebEntityResponse(arg) {
|
|
9
|
+
BasicWebEntity.call(this, arg);
|
|
10
|
+
|
|
11
|
+
this.entities.create = function() {
|
|
12
|
+
var newEntity = new WebEntityResponse();
|
|
13
|
+
this.push(newEntity);
|
|
14
|
+
return newEntity;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
util.inherits(WebEntityResponse, BasicWebEntity);
|
|
20
|
+
|
|
21
|
+
WebEntityResponse.create = function(headers, body) {
|
|
22
|
+
var entityResponse = new WebEntityResponse();
|
|
23
|
+
entityResponse.headers._addData(headers);
|
|
24
|
+
entityResponse.setBody(body);
|
|
25
|
+
return entityResponse;
|
|
26
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var util = require('util');
|
|
5
|
+
var parseUrl = require('url').parse;
|
|
6
|
+
var CookiesTupelList = require('./TupelLists/CookiesTupelList');
|
|
7
|
+
var http = require('../constants').webTypes;
|
|
8
|
+
var contentTypeParser = require('content-type');
|
|
9
|
+
var WebEntityRequest = require('./WebEntityRequest');
|
|
10
|
+
var MultipartParser = require('./utils/MultipartParser');
|
|
11
|
+
var MESSAGE_TYPE = require('../constants').WEB.MESSAGE_TYPE;
|
|
12
|
+
var HttpError = require('../../utils/errors/HttpError');
|
|
13
|
+
|
|
14
|
+
module.exports = WebRequest;
|
|
15
|
+
|
|
16
|
+
function WebRequest(arg0, arg1) {
|
|
17
|
+
if (this instanceof WebRequest) {
|
|
18
|
+
WebEntityRequest.call(this, arg0);
|
|
19
|
+
|
|
20
|
+
if (typeof arg0 === 'number') {
|
|
21
|
+
var method = arg0;
|
|
22
|
+
var path = arg1;
|
|
23
|
+
if (typeof path !== 'string') {
|
|
24
|
+
throw new Error('Expected string as a path (second argument)');
|
|
25
|
+
}
|
|
26
|
+
this.method = method;
|
|
27
|
+
this.cookies = new CookiesTupelList();
|
|
28
|
+
this.language = '';
|
|
29
|
+
this.path = path || '';
|
|
30
|
+
this.queryPath = '';
|
|
31
|
+
} else {
|
|
32
|
+
var req = arg0;
|
|
33
|
+
var locale = arg1;
|
|
34
|
+
normalizeRequestHeaders(this);
|
|
35
|
+
setBodyOrEntities(this, req);
|
|
36
|
+
addFormData(this, req);
|
|
37
|
+
this.method = resolveMethod(req.method);
|
|
38
|
+
this.cookies = new CookiesTupelList();
|
|
39
|
+
this.cookies._addData(req.cookies);
|
|
40
|
+
setRequestLanguage(this, locale);
|
|
41
|
+
setPath(this, req.path);
|
|
42
|
+
addTildeHeaders(this, req);
|
|
43
|
+
setQueryPath(this);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
return new WebRequest(arg0, arg1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
util.inherits(WebRequest, WebEntityRequest);
|
|
51
|
+
|
|
52
|
+
function addTildeHeaders(webRequest, req) {
|
|
53
|
+
var originalUrl = parseUrl(req.originalUrl);
|
|
54
|
+
var headers = webRequest.headers;
|
|
55
|
+
headers.set('~request_line', util.format('%s %s HTTP/%s', req.method, originalUrl.path, req.httpVersion));
|
|
56
|
+
headers.set('~request_method', req.method);
|
|
57
|
+
headers.set('~request_uri', originalUrl.path);
|
|
58
|
+
|
|
59
|
+
headers.set('~path', originalUrl.pathname);
|
|
60
|
+
headers.set('~path_translated', webRequest.path);
|
|
61
|
+
if (originalUrl.query) {
|
|
62
|
+
headers.set('~query_string', originalUrl.query);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeRequestHeaders(webRequest) {
|
|
67
|
+
// erase the value of the cookie header if present
|
|
68
|
+
if (webRequest.headers.get('cookie')) {
|
|
69
|
+
webRequest.headers.set('cookie', '');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function setBodyOrEntities(webRequest, req) {
|
|
74
|
+
var boundary = extractBoundaryOfMultipartRequest(webRequest);
|
|
75
|
+
if (boundary) {
|
|
76
|
+
try {
|
|
77
|
+
MultipartParser.parseFromBuffer(req.body, boundary, webRequest, MESSAGE_TYPE.REQUEST);
|
|
78
|
+
webRequest.body = undefined;
|
|
79
|
+
} catch (err) {
|
|
80
|
+
throw new HttpError(400, err.message);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
webRequest.setBody(req.body);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function extractBoundaryOfMultipartRequest(webRequest) {
|
|
88
|
+
var contentType = webRequest.headers.get('content-type');
|
|
89
|
+
if (!contentType) {
|
|
90
|
+
return '';
|
|
91
|
+
}
|
|
92
|
+
var isMultipart = contentType.indexOf('multipart') > -1;
|
|
93
|
+
var isNotFormData = contentType.indexOf('form-data') < 0; // multiparty has alredy handled that
|
|
94
|
+
if (isMultipart && isNotFormData) {
|
|
95
|
+
var boundary = contentTypeParser.parse(contentType).parameters.boundary;
|
|
96
|
+
if (!boundary) {
|
|
97
|
+
throw new HttpError(400, 'Multipart request error. No boundary parameter found on header Content-Type ("' + contentType + '")');
|
|
98
|
+
}
|
|
99
|
+
return boundary;
|
|
100
|
+
}
|
|
101
|
+
return '';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function addFormData(webRequest, expressRequest) {
|
|
105
|
+
var formData = expressRequest['form-data'];
|
|
106
|
+
if (!formData) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
webRequest.body = undefined;
|
|
110
|
+
|
|
111
|
+
reuseInputFieldsData(webRequest, formData);
|
|
112
|
+
reuseFileUploadData(webRequest, formData);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function reuseInputFieldsData(webRequest, formData) {
|
|
116
|
+
var inputFieldNames = Object.keys(formData.fields);
|
|
117
|
+
|
|
118
|
+
inputFieldNames.forEach(function (singleInputFieldName) {
|
|
119
|
+
var valuesForInputField = formData.fields[singleInputFieldName];
|
|
120
|
+
valuesForInputField.forEach(function (singleValue) {
|
|
121
|
+
var headers = { 'content-disposition': 'form-data; name="' + singleInputFieldName + '"' };
|
|
122
|
+
var parameters = {};
|
|
123
|
+
parameters[singleInputFieldName] = singleValue;
|
|
124
|
+
var body = singleValue;
|
|
125
|
+
webRequest.entities.push(WebEntityRequest.create(headers, parameters, body));
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function reuseFileUploadData(webRequest, formData) {
|
|
131
|
+
var uploaderNames = Object.keys(formData.files);
|
|
132
|
+
|
|
133
|
+
uploaderNames.forEach(function (singleUploaderName) {
|
|
134
|
+
var uploadedFiles = formData.files[singleUploaderName];
|
|
135
|
+
uploadedFiles.forEach(function (singleUploadedFile) {
|
|
136
|
+
var headers = singleUploadedFile.headers;
|
|
137
|
+
headers['~content_disposition'] = 'form-data';
|
|
138
|
+
headers['~content_name'] = singleUploaderName;
|
|
139
|
+
headers['~content_filename'] = singleUploadedFile.originalFilename;
|
|
140
|
+
// the last one is extra comparing to the XSEngine headers
|
|
141
|
+
headers['~content_file_size'] = singleUploadedFile.size;
|
|
142
|
+
|
|
143
|
+
var body = readUploadedFile(singleUploadedFile.path);
|
|
144
|
+
removeFileOnFileSystem(singleUploadedFile.path);
|
|
145
|
+
|
|
146
|
+
webRequest.entities.push(WebEntityRequest.create(headers, {}, body));
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function readUploadedFile(filePath) {
|
|
152
|
+
return fs.readFileSync(filePath);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function removeFileOnFileSystem(filePath) {
|
|
156
|
+
fs.unlinkSync(filePath);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function resolveMethod(method) {
|
|
160
|
+
switch (method) {
|
|
161
|
+
case 'OPTIONS':
|
|
162
|
+
return http.OPTIONS;
|
|
163
|
+
case 'GET':
|
|
164
|
+
return http.GET;
|
|
165
|
+
case 'HEAD':
|
|
166
|
+
return http.HEAD;
|
|
167
|
+
case 'POST':
|
|
168
|
+
return http.POST;
|
|
169
|
+
case 'PUT':
|
|
170
|
+
return http.PUT;
|
|
171
|
+
case 'DELETE':
|
|
172
|
+
return http.DEL;
|
|
173
|
+
case 'TRACE':
|
|
174
|
+
return http.TRACE;
|
|
175
|
+
case 'CONNECT':
|
|
176
|
+
return http.CONNECT;
|
|
177
|
+
case 'PATCH':
|
|
178
|
+
return http.PATCH;
|
|
179
|
+
default:
|
|
180
|
+
return http.INVALID;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function setRequestLanguage(webRequest, locale) {
|
|
185
|
+
Object.defineProperty(webRequest, 'language', {
|
|
186
|
+
value: locale.requestLanguage,
|
|
187
|
+
enumerable: true
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function setPath(webRequest, reqPath) {
|
|
192
|
+
var pathPattern = /(.+\.xsjs[^\?]*)(\?.+)?/;
|
|
193
|
+
var result = pathPattern.exec(reqPath);
|
|
194
|
+
if (result && result.length > 1) {
|
|
195
|
+
webRequest.path = result[1];
|
|
196
|
+
} else {
|
|
197
|
+
webRequest.path = reqPath;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function setQueryPath(webRequest) {
|
|
202
|
+
var beginOfQueryPath = webRequest.path.indexOf('.xsjs/');
|
|
203
|
+
if (beginOfQueryPath > 0) {
|
|
204
|
+
beginOfQueryPath += '.xsjs/'.length;
|
|
205
|
+
webRequest.queryPath = webRequest.path.substring(beginOfQueryPath);
|
|
206
|
+
} else {
|
|
207
|
+
webRequest.queryPath = '';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('lodash');
|
|
4
|
+
var util = require('util');
|
|
5
|
+
var status = require('statuses');
|
|
6
|
+
var utils = require('../../utils');
|
|
7
|
+
var CookiesTupelList = require('./TupelLists/CookiesTupelList');
|
|
8
|
+
var bufferUtils = require('../../utils/buffer-utils');
|
|
9
|
+
var contentTypeParser = require('content-type');
|
|
10
|
+
var WebEntityResponse = require('./WebEntityResponse');
|
|
11
|
+
var SetCookieParser = require('./utils/SetCookieParser');
|
|
12
|
+
var MultipartParser = require('./utils/MultipartParser');
|
|
13
|
+
var MultipartResponseBuilder = require('./utils/MultipartResponseBuilder');
|
|
14
|
+
var MESSAGE_TYPE = require('../constants').WEB.MESSAGE_TYPE;
|
|
15
|
+
var logging = require('../../logging');
|
|
16
|
+
var wrapAppError = require('../../utils/errors/wrap-app-error');
|
|
17
|
+
|
|
18
|
+
module.exports = WebResponse;
|
|
19
|
+
|
|
20
|
+
function WebResponse(res, followUpContext) {
|
|
21
|
+
WebEntityResponse.call(this, res);
|
|
22
|
+
|
|
23
|
+
if (!res) {
|
|
24
|
+
this.cookies = new CookiesTupelList();
|
|
25
|
+
this.status = 200;
|
|
26
|
+
} else {
|
|
27
|
+
normalizeResponseHeaders(this);
|
|
28
|
+
setBodyOrEntities(this, res);
|
|
29
|
+
this.cookies = new CookiesTupelList();
|
|
30
|
+
this.cookies._addData(extractCookies(res));
|
|
31
|
+
this.status = res.statusCode;
|
|
32
|
+
this.statusMessage = status[res.statusCode];
|
|
33
|
+
this._httpVersion = 'HTTP/' + res.httpVersion;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (followUpContext) {
|
|
37
|
+
var loggingContext = followUpContext.loggingContext;
|
|
38
|
+
this.followUp = async function (followUpObject) {
|
|
39
|
+
if (typeof followUpObject !== 'object') {
|
|
40
|
+
throw new Error('[$.web.WebResponse].followUp: expected an object as an argument');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
var pathToScript = extractPathToScript(followUpObject.uri);
|
|
44
|
+
var functionName = extractFunctionName(followUpObject.functionName);
|
|
45
|
+
|
|
46
|
+
var context = followUpCreateContext(followUpContext);
|
|
47
|
+
var thisArg = utils.createXsFunctionThisArg(context);
|
|
48
|
+
var runner = new utils.XsJsFunctionRunner(followUpContext.runtime, pathToScript, context);
|
|
49
|
+
try {
|
|
50
|
+
await runner.run(functionName, thisArg, [followUpObject.parameter]);
|
|
51
|
+
} catch (err){
|
|
52
|
+
var logger = loggingContext.getLogger(logging.CATEGORY);
|
|
53
|
+
logger.error(wrapAppError(err), util.format('$.response.followUp - Execution of function "%s" in script "%s" failed', functionName, pathToScript));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
var tracer = loggingContext.getTracer(__filename);
|
|
57
|
+
tracer.info('$.response.followUp - Execution of function "%s" in script "%s" finished successfully', functionName, pathToScript);
|
|
58
|
+
};
|
|
59
|
+
} else {
|
|
60
|
+
this.followUp = function () {
|
|
61
|
+
throw new Error('[$.web.WebResponse].followUp: cannot invoke function on current object');
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
util.inherits(WebResponse, WebEntityResponse);
|
|
67
|
+
|
|
68
|
+
function normalizeResponseHeaders(webResponse) {
|
|
69
|
+
// remove the set-cookie header if exists
|
|
70
|
+
if (webResponse.headers.get('set-cookie')) {
|
|
71
|
+
webResponse.headers.remove('set-cookie');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function setBodyOrEntities(webResponse, internalResponse) {
|
|
76
|
+
var boundary = extractBoundaryOfMultipartResponse(webResponse);
|
|
77
|
+
if (boundary) {
|
|
78
|
+
MultipartParser.parseFromBuffer(internalResponse.body, boundary, webResponse, MESSAGE_TYPE.RESPONSE);
|
|
79
|
+
webResponse.body = undefined;
|
|
80
|
+
} else {
|
|
81
|
+
internalResponse.body && webResponse.setBody(internalResponse.body);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function extractBoundaryOfMultipartResponse(webResponse) {
|
|
86
|
+
var contentType = webResponse.headers.get('content-type');
|
|
87
|
+
if (!contentType) {
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var isMultipart = contentType.indexOf('multipart') > -1;
|
|
92
|
+
if (isMultipart) {
|
|
93
|
+
var boundary = contentTypeParser.parse(contentType).parameters.boundary;
|
|
94
|
+
if (!boundary) {
|
|
95
|
+
throw new Error('Multipart response error. No boundary parameter found on header Content-Type ("' + contentType + '")');
|
|
96
|
+
}
|
|
97
|
+
return boundary;
|
|
98
|
+
}
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function extractCookies(internalResponse) {
|
|
103
|
+
if (!internalResponse.headers) {
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
var setCookieHeader = internalResponse.headers['set-cookie'];
|
|
107
|
+
if (!setCookieHeader) {
|
|
108
|
+
return {};
|
|
109
|
+
}
|
|
110
|
+
return SetCookieParser.parse(setCookieHeader);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function extractPathToScript(uri) {
|
|
114
|
+
if (typeof uri !== 'string') {
|
|
115
|
+
throw new Error('[$.web.WebResponse].followUp argument: uri property missing or not a string');
|
|
116
|
+
}
|
|
117
|
+
uri = uri.trim();
|
|
118
|
+
var result = /([^:]+):([^:]+\.xsjs)/.exec(uri);
|
|
119
|
+
if (!result || result.length !== 3) {
|
|
120
|
+
throw new Error('[$.web.WebResponse].followUp argument uri property got to be in the format: package:script.xsjs');
|
|
121
|
+
}
|
|
122
|
+
var packageName = result[1];
|
|
123
|
+
var fileName = result[2];
|
|
124
|
+
return utils.toPath(packageName, fileName);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function extractFunctionName(functionName) {
|
|
128
|
+
if (functionName === null || functionName === undefined || typeof functionName !== 'string') {
|
|
129
|
+
throw new Error('[$.web.WebResponse].followUp argument: functionName missing or not a string');
|
|
130
|
+
}
|
|
131
|
+
functionName = functionName.trim();
|
|
132
|
+
if (!functionName) {
|
|
133
|
+
throw new Error('[$.web.WebResponse].followUp argument: functionName cannot be empty');
|
|
134
|
+
}
|
|
135
|
+
return functionName;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function adjustContentType(webResponse) {
|
|
139
|
+
if (webResponse.headers.get('content-type')) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
var body = webResponse.body._content;
|
|
143
|
+
var bodyIsJson = _.isObject(body) && !bufferUtils.isBinary(body);
|
|
144
|
+
webResponse.headers.set('content-type', bodyIsJson ? 'application/json' : 'text/html');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
WebResponse.prototype._pipe = function(res) {
|
|
148
|
+
adjustContentType(this);
|
|
149
|
+
res.status(this.status);
|
|
150
|
+
this.headers.forEach(function (header) {
|
|
151
|
+
res.set(header.name, header.value);
|
|
152
|
+
});
|
|
153
|
+
this.cookies.forEach(function (cookie) {
|
|
154
|
+
res.cookie(cookie.name, cookie.value);
|
|
155
|
+
});
|
|
156
|
+
if (this.entities.length > 0) {
|
|
157
|
+
var boundary = MultipartResponseBuilder.generateBoundary();
|
|
158
|
+
res.set('content-type', 'multipart/mixed; boundary=' + boundary);
|
|
159
|
+
var body = MultipartResponseBuilder.build(this, boundary);
|
|
160
|
+
res.send(body);
|
|
161
|
+
} else {
|
|
162
|
+
res.send(this.body._retrieveContent());
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
Object.defineProperties(WebResponse.prototype, {
|
|
167
|
+
cacheControl: {
|
|
168
|
+
set: function (value) {
|
|
169
|
+
this.headers.set('cache-control', value);
|
|
170
|
+
},
|
|
171
|
+
get: function () {
|
|
172
|
+
return this.headers.get('cache-control');
|
|
173
|
+
},
|
|
174
|
+
enumerable: true
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
function followUpCreateContext(followUpContext) {
|
|
179
|
+
// We are using Object.assgin to keep $.trace object
|
|
180
|
+
// And properties like $.trace, $.response and $.application which are currently (probably incorrectly) available in followUp jobs, for backwards compatibility.
|
|
181
|
+
var baseContext = followUpContext.runtime.createBaseContext(followUpContext.req, followUpContext.locale, followUpContext.traceOptions);
|
|
182
|
+
return Object.assign({}, followUpContext.context, baseContext);
|
|
183
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var CRLF = require('../../constants').WEB.MESSAGES.LINE_BREAK;
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
exports.parse = function(headersSection) {
|
|
7
|
+
var parsedHeaders = {};
|
|
8
|
+
|
|
9
|
+
var arrLines = headersSection.split(CRLF);
|
|
10
|
+
handleHeaderLines(arrLines, parsedHeaders);
|
|
11
|
+
|
|
12
|
+
return parsedHeaders;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function handleHeaderLines(arrLines, parsedHeaders) {
|
|
16
|
+
var singleLine;
|
|
17
|
+
var isPartOfMultilineHeader;
|
|
18
|
+
|
|
19
|
+
for (var i = arrLines.length - 1; i >= 0; i--) {
|
|
20
|
+
singleLine = arrLines[i];
|
|
21
|
+
isPartOfMultilineHeader = (singleLine.indexOf(' ') === 0) && (i > 0);
|
|
22
|
+
|
|
23
|
+
if (isPartOfMultilineHeader) {
|
|
24
|
+
singleLine = collapseSpacesAtTheFrontToJustOne(singleLine);
|
|
25
|
+
var indexOfLineForAddingTheCurrentLineTo = i - 1;
|
|
26
|
+
arrLines[indexOfLineForAddingTheCurrentLineTo] += singleLine;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
parseHeaderString(singleLine, parsedHeaders);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function collapseSpacesAtTheFrontToJustOne(str) {
|
|
34
|
+
return str.replace(/[ ]+/, ' ');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function parseHeaderString(str, parsedHeaders) {
|
|
38
|
+
var result = /([^:]+):(.*)/.exec(str);
|
|
39
|
+
if (result && result.length === 3) {
|
|
40
|
+
var name = result[1].trim().toLowerCase();
|
|
41
|
+
var value = result[2].trim();
|
|
42
|
+
var existingValue = parsedHeaders[name];
|
|
43
|
+
if (!existingValue) {
|
|
44
|
+
parsedHeaders[name] = value;
|
|
45
|
+
} else if (typeof existingValue === 'string') {
|
|
46
|
+
parsedHeaders[name] = [existingValue];
|
|
47
|
+
parsedHeaders[name].unshift(value);
|
|
48
|
+
} else {
|
|
49
|
+
// it is an array
|
|
50
|
+
parsedHeaders[name].unshift(value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|