gina 0.0.9-p91b → 0.1.1-alpha.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/INSTALL.md +46 -0
- package/{core/asset/html/static.html → Icon/r} +0 -0
- package/LICENSE +1 -1
- package/README-4Contributors.md +96 -0
- package/README.md +296 -104
- package/bin/cli +287 -0
- package/bin/cli-debug +60 -0
- package/bin/cmd +184 -0
- package/bin/gina +180 -0
- package/config/logger.json +17 -0
- package/doc/framework/cli/doc.json +9 -0
- package/doc/framework/index.md +60 -0
- package/framework/v0.1.1-alpha.2/AUTHORS +7 -0
- package/{core/utils/lib/inherits → framework/v0.1.1-alpha.2}/LICENSE +1 -1
- package/framework/v0.1.1-alpha.2/VERSION +1 -0
- package/{core/locales/dist/language/en.json → framework/v0.1.1-alpha.2/core/asset/html/nolayout.html} +0 -0
- package/{core/locales/dist/language/fr.json → framework/v0.1.1-alpha.2/core/asset/html/static.html} +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/asset/img/android-chrome-192x192.png +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/asset/img/android-chrome-512x512.png +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/asset/img/apple-touch-icon.png +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/asset/img/favicon-16x16.png +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/asset/img/favicon-32x32.png +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/asset/img/favicon.ico +0 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.js +20904 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.js.map +56 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.min.css +1 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.min.css.map +1 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.min.js +736 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.min.js.map +56 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.onload.min.js +5 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/dist/gina.onload.min.js.map +8 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/readme.md +192 -0
- package/framework/v0.1.1-alpha.2/core/asset/js/plugin/uuid.json +23 -0
- package/framework/v0.1.1-alpha.2/core/config.js +2308 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/index.js +757 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/connector.js +20 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/connector.v2.js +429 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/connector.v3.js +432 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/n1ql.js +14 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/session-store.js +21 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/session-store.v2.js +258 -0
- package/framework/v0.1.1-alpha.2/core/connectors/couchbase/lib/session-store.v3.js +341 -0
- package/{core → framework/v0.1.1-alpha.2/core}/controller/controller.framework.js +3 -2
- package/framework/v0.1.1-alpha.2/core/controller/controller.js +3990 -0
- package/{core → framework/v0.1.1-alpha.2/core}/controller/index.js +5 -5
- package/framework/v0.1.1-alpha.2/core/deps/busboy/.travis.yml +17 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/LICENSE +19 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/README.md +225 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/deps/encoding/encoding-indexes.js +73 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/deps/encoding/encoding.js +2391 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/lib/main.js +89 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/lib/types/multipart.js +328 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/lib/types/urlencoded.js +214 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/lib/utils.js +191 -0
- package/framework/v0.1.1-alpha.2/core/deps/busboy/package.json +69 -0
- package/framework/v0.1.1-alpha.2/core/deps/swig-client/swig-2.0.0.min.js +5 -0
- package/{core → framework/v0.1.1-alpha.2/core}/dev/index.js +5 -5
- package/{core → framework/v0.1.1-alpha.2/core}/dev/lib/class.js +1 -1
- package/{core → framework/v0.1.1-alpha.2/core}/dev/lib/factory.js +1 -1
- package/{core → framework/v0.1.1-alpha.2/core}/dev/lib/tools.js +0 -0
- package/framework/v0.1.1-alpha.2/core/gna.js +1070 -0
- package/{core → framework/v0.1.1-alpha.2/core}/locales/README.md +41 -2
- package/{core → framework/v0.1.1-alpha.2/core}/locales/currency.json +0 -0
- package/{core/plugins/README.md → framework/v0.1.1-alpha.2/core/locales/dist/language/en.json} +0 -0
- package/{core/plugins/lib/intl/README.md → framework/v0.1.1-alpha.2/core/locales/dist/language/fr.json} +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/locales/dist/region/en.json +0 -0
- package/framework/v0.1.1-alpha.2/core/locales/dist/region/fr.json +9492 -0
- package/{core → framework/v0.1.1-alpha.2/core}/locales/index.js +5 -4
- package/{core → framework/v0.1.1-alpha.2/core}/locales/src/make.js +15 -12
- package/{core → framework/v0.1.1-alpha.2/core}/locales/src/resources/currency.csv +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/locales/src/resources/region.csv +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/locales/src/resources/region.mapping.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/mime.types +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/model/entity.js +156 -196
- package/{core → framework/v0.1.1-alpha.2/core}/model/index.js +67 -48
- package/{core → framework/v0.1.1-alpha.2/core}/model/template/entityFactory.js +2 -2
- package/{core → framework/v0.1.1-alpha.2/core}/model/template/index.js +8 -10
- package/{core/plugins/lib/storage → framework/v0.1.1-alpha.2/core/plugins}/README.md +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/plugins/index.js +3 -3
- package/{core/plugins/lib/validator → framework/v0.1.1-alpha.2/core/plugins/lib/file}/README.md +0 -0
- package/{core/plugins/lib/intl → framework/v0.1.1-alpha.2/core/plugins/lib/file}/build.json +0 -0
- package/framework/v0.1.1-alpha.2/core/plugins/lib/file/package.json +25 -0
- package/{core/utils/lib/collection → framework/v0.1.1-alpha.2/core/plugins/lib/intl}/README.md +0 -0
- package/{core/plugins/lib/storage → framework/v0.1.1-alpha.2/core/plugins/lib/intl}/build.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/plugins/lib/intl/package.json +3 -3
- package/{core → framework/v0.1.1-alpha.2/core}/plugins/lib/intl/src/main.js +17 -1
- package/{core/utils/lib/routing → framework/v0.1.1-alpha.2/core/plugins/lib/storage}/README.md +0 -0
- package/{core/plugins/lib/validator → framework/v0.1.1-alpha.2/core/plugins/lib/storage}/build.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/plugins/lib/storage/package.json +2 -2
- package/{core → framework/v0.1.1-alpha.2/core}/plugins/lib/storage/src/main.js +91 -85
- package/{core/utils/lib/url → framework/v0.1.1-alpha.2/core/plugins/lib/validator}/README.md +0 -0
- package/{core/utils/lib/collection → framework/v0.1.1-alpha.2/core/plugins/lib/validator}/build.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/plugins/lib/validator/package.json +3 -3
- package/framework/v0.1.1-alpha.2/core/plugins/lib/validator/src/form-validator.js +1762 -0
- package/framework/v0.1.1-alpha.2/core/plugins/lib/validator/src/main.js +6917 -0
- package/framework/v0.1.1-alpha.2/core/router.js +664 -0
- package/framework/v0.1.1-alpha.2/core/server.express.js +213 -0
- package/framework/v0.1.1-alpha.2/core/server.isaac.js +386 -0
- package/framework/v0.1.1-alpha.2/core/server.js +3010 -0
- package/{core → framework/v0.1.1-alpha.2/core}/status.codes +8 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/config/app.json +6 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/config/routing.json +11 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/config/settings.json +9 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/config/settings.server.json +30 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/config/templates.json +42 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/controllers/controller.content.js +39 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/controllers/controller.js +30 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle/controllers/setup.js +111 -0
- package/{core/template/samples → framework/v0.1.1-alpha.2/core/template/boilerplate}/bundle/index.js +0 -0
- package/{core/template/samples/bundle → framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_namespace}/controllers/controller.js +9 -7
- package/{core/template/views → framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_public}/css/default.css +0 -0
- package/{core/template/views → framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_public}/css/vendor/readme.md +0 -0
- package/{core/template/views → framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_public}/favicon.ico +0 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_public/js/vendor/readme.md +1 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_public/readme.md +1 -0
- package/framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_templates/handlers/main.js +24 -0
- package/{core/template/views/html/default.html → framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_templates/html/homepage.html} +0 -0
- package/{core/template/views/html/layout.html → framework/v0.1.1-alpha.2/core/template/boilerplate/bundle_templates/html/layout/main.html} +2 -2
- package/{core → framework/v0.1.1-alpha.2/core}/template/command/gina.bat.tpl +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/command/gina.tpl +1 -1
- package/framework/v0.1.1-alpha.2/core/template/conf/env.json +76 -0
- package/{core/template/conf/project.json → framework/v0.1.1-alpha.2/core/template/conf/manifest.json} +1 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/conf/package.json +2 -2
- package/framework/v0.1.1-alpha.2/core/template/conf/settings.json +92 -0
- package/framework/v0.1.1-alpha.2/core/template/conf/statics.json +10 -0
- package/framework/v0.1.1-alpha.2/core/template/conf/templates.json +37 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/error/client/json/401.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/error/client/json/403.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/error/client/json/404.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/error/server/html/50x.html +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/error/server/json/500.json +0 -0
- package/{core → framework/v0.1.1-alpha.2/core}/template/error/server/json/503.json +0 -0
- package/{core/utils/lib/routing/build.json → framework/v0.1.1-alpha.2/core/template/extensions/logger/config.json} +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/helpers/console.js +3 -3
- package/{core/utils → framework/v0.1.1-alpha.2}/helpers/context.js +240 -49
- package/framework/v0.1.1-alpha.2/helpers/dateFormat.js +528 -0
- package/framework/v0.1.1-alpha.2/helpers/index.js +79 -0
- package/framework/v0.1.1-alpha.2/helpers/json/README.md +0 -0
- package/framework/v0.1.1-alpha.2/helpers/json/package.json +20 -0
- package/framework/v0.1.1-alpha.2/helpers/json/src/main.js +97 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/helpers/path.js +342 -140
- package/framework/v0.1.1-alpha.2/helpers/plugins/README.md +4 -0
- package/framework/v0.1.1-alpha.2/helpers/plugins/package.json +20 -0
- package/framework/v0.1.1-alpha.2/helpers/plugins/src/api-error.js +160 -0
- package/framework/v0.1.1-alpha.2/helpers/plugins/src/main.js +32 -0
- package/framework/v0.1.1-alpha.2/helpers/prototypes.js +218 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/helpers/task.js +49 -29
- package/{core/utils → framework/v0.1.1-alpha.2}/helpers/text.js +7 -7
- package/framework/v0.1.1-alpha.2/lib/archiver/README.md +0 -0
- package/framework/v0.1.1-alpha.2/lib/archiver/build.json +0 -0
- package/framework/v0.1.1-alpha.2/lib/archiver/package.json +20 -0
- package/framework/v0.1.1-alpha.2/lib/archiver/src/dep/jszip.min.js +15 -0
- package/framework/v0.1.1-alpha.2/lib/archiver/src/main.js +499 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/aliases.json +13 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/add.js +507 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/arguments.json +4 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/copy.js +15 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/cp.js +2 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/help.js +28 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/help.txt +67 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/list.js +129 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/remove.js +229 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/rename.js +4 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/restart.js +235 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/rm.js +2 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/start.js +394 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/status.js +3 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/bundle/stop.js +232 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/add.js +436 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/get.js +62 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/help.js +28 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/help.txt +33 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/link-dev.js +80 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/list.js +111 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/remove.js +150 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/rm.js +2 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/set.js +57 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/unset.js +44 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/env/use.js +79 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/dot.js +70 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/get.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/help.js +39 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/help.txt +31 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/init.js +514 -0
- package/{core/utils/lib/cmd → framework/v0.1.1-alpha.2/lib/cmd/framework}/msg.json +3 -3
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/open.js +50 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/restart.js +124 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/set.js +161 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/start.js +96 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/status.js +72 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/stop.js +159 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/tail.js +183 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/update.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/framework/version.js +44 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/gina-dev.1.md +66 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/gina-framework.1.md +100 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/gina.1.md +79 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/helper.js +1147 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/index.js +170 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/msg.json +20 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/port/help.js +28 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/port/help.txt +31 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/port/inc/scan.js +108 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/port/list.js +176 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/port/set.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/add.js +528 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/arguments.json +9 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/build.js +115 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/help.js +28 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/help.txt +76 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/import.js +2 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/list.js +55 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/move.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/remove.js +144 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/rename.js +162 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/restart.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/rm.js +2 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/start.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/status.js +3 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/project/stop.js +0 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/protocol/help.js +27 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/protocol/help.txt +57 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/protocol/list.js +239 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/protocol/set.js +631 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/help.js +28 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/help.txt +33 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/link-local.js +80 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/list.js +116 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/remove.js +150 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/rm.js +2 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/set.js +57 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/unset.js +44 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/scope/use.js +79 -0
- package/framework/v0.1.1-alpha.2/lib/cmd/view/add.js +311 -0
- package/framework/v0.1.1-alpha.2/lib/collection/README.md +5 -0
- package/framework/v0.1.1-alpha.2/lib/collection/build.json +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/collection/package.json +2 -2
- package/framework/v0.1.1-alpha.2/lib/collection/src/main.js +1459 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/config.js +49 -34
- package/framework/v0.1.1-alpha.2/lib/cron/README.md +7 -0
- package/framework/v0.1.1-alpha.2/lib/cron/package.json +20 -0
- package/framework/v0.1.1-alpha.2/lib/cron/src/main.js +176 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/generator/index.js +8 -4
- package/framework/v0.1.1-alpha.2/lib/index.js +116 -0
- package/framework/v0.1.1-alpha.2/lib/inherits/LICENSE +19 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/README.md +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/example/inheriting_eventemitter.js +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/example/protected_inheritance.js +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/example/simple_inheritance.js +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/example/super_attribute_overridden_by_child_on_init.js +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/package.json +2 -2
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/inherits/src/main.js +18 -19
- package/framework/v0.1.1-alpha.2/lib/logger/README.md +7 -0
- package/framework/v0.1.1-alpha.2/lib/logger/package.json +20 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/default/index.js +55 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/file/index.js +251 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/file/lib/logrotator/README.md +100 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/file/lib/logrotator/index.js +274 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/mq/index.js +52 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/mq/listener.js +302 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/containers/mq/speaker.js +118 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/helper.js +131 -0
- package/framework/v0.1.1-alpha.2/lib/logger/src/main.js +734 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/math/index.js +58 -35
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/merge/README.md +5 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/merge/example/merge.js +1 -1
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/merge/example/merge_2_literal objects.js +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/merge/example/merge_and_preserve_first.js +2 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/merge/package.json +2 -2
- package/framework/v0.1.1-alpha.2/lib/merge/src/main.js +531 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/model.js +42 -19
- package/framework/v0.1.1-alpha.2/lib/proc.js +518 -0
- package/framework/v0.1.1-alpha.2/lib/routing/README.md +0 -0
- package/framework/v0.1.1-alpha.2/lib/routing/build.json +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/routing/package.json +2 -2
- package/framework/v0.1.1-alpha.2/lib/routing/src/main.js +1492 -0
- package/framework/v0.1.1-alpha.2/lib/session-store.js +33 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/shell.js +43 -30
- package/framework/v0.1.1-alpha.2/lib/swig-filters/README.md +0 -0
- package/framework/v0.1.1-alpha.2/lib/swig-filters/package.json +20 -0
- package/framework/v0.1.1-alpha.2/lib/swig-filters/src/main.js +322 -0
- package/framework/v0.1.1-alpha.2/lib/url/README.md +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/url/index.js +2 -1
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/url/mocks.json +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/url/routing.json +9 -9
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/url/test.js +0 -0
- package/{core/utils → framework/v0.1.1-alpha.2}/lib/validator.js +7 -7
- package/framework/v0.1.1-alpha.2/package.json +14 -0
- package/package.json +35 -33
- package/resources/etc/init.d/debian/gina +117 -0
- package/resources/home/framework/env.json +34 -0
- package/resources/home/framework/locals.json +14 -0
- package/resources/home/framework/project.json +48 -0
- package/resources/home/framework/projects.json +6 -0
- package/resources/home/main.json +47 -0
- package/resources/home/settings.json +22 -0
- package/resources/home/user/extensions/logger/default/config.json +77 -0
- package/resources/home/user/extensions/logger/file/config.json +11 -0
- package/resources/img/android-chrome-192x192.png +0 -0
- package/resources/img/android-chrome-512x512.png +0 -0
- package/resources/img/apple-touch-icon.png +0 -0
- package/resources/img/favicon-16x16.png +0 -0
- package/resources/img/favicon-32x32.png +0 -0
- package/resources/img/favicon.ico +0 -0
- package/resources/package.json.template +50 -0
- package/script/lib.js +24 -0
- package/script/post_install.js +449 -157
- package/script/pre_install.js +277 -36
- package/script/prepare_version.js +425 -0
- package/utils/helper.js +438 -0
- package/utils/prototypes.js +239 -0
- package/utils/prototypes.json_clone.js +175 -0
- package/.npmignore +0 -6
- package/MIDDLEWARE +0 -1
- package/SUCCESS +0 -1
- package/VERSION +0 -1
- package/core/asset/html/nolayout.html +0 -1
- package/core/asset/js/plugin/build.dev.json +0 -28
- package/core/asset/js/plugin/build.json +0 -31
- package/core/asset/js/plugin/dist/gina.min.css +0 -1
- package/core/asset/js/plugin/dist/gina.min.css.map +0 -1
- package/core/asset/js/plugin/dist/gina.min.js +0 -13731
- package/core/asset/js/plugin/dist/gina.min.js.map +0 -42
- package/core/asset/js/plugin/dist/gina.onload.min.js +0 -3
- package/core/asset/js/plugin/dist/gina.onload.min.js.map +0 -8
- package/core/asset/js/plugin/readme.md +0 -152
- package/core/asset/js/plugin/src/gina/main.js +0 -132
- package/core/asset/js/plugin/src/gina/popin/css/design.css +0 -23
- package/core/asset/js/plugin/src/gina/popin/css/main.css +0 -1112
- package/core/asset/js/plugin/src/gina/popin/css/popin.css +0 -3
- package/core/asset/js/plugin/src/gina/popin/css/popin.css.map +0 -1
- package/core/asset/js/plugin/src/gina/popin/doc/TOC.md +0 -29
- package/core/asset/js/plugin/src/gina/popin/doc/css.md +0 -162
- package/core/asset/js/plugin/src/gina/popin/doc/extend.md +0 -663
- package/core/asset/js/plugin/src/gina/popin/doc/faq.md +0 -46
- package/core/asset/js/plugin/src/gina/popin/doc/html.md +0 -227
- package/core/asset/js/plugin/src/gina/popin/doc/js.md +0 -37
- package/core/asset/js/plugin/src/gina/popin/doc/misc.md +0 -178
- package/core/asset/js/plugin/src/gina/popin/doc/usage.md +0 -130
- package/core/asset/js/plugin/src/gina/popin/main.js +0 -783
- package/core/asset/js/plugin/src/gina/popin/sass/config.sass +0 -37
- package/core/asset/js/plugin/src/gina/popin/sass/gina-design.sass +0 -622
- package/core/asset/js/plugin/src/gina/popin/sass/gina-popin.sass +0 -54
- package/core/asset/js/plugin/src/gina/popin/sass/helper.scss +0 -73
- package/core/asset/js/plugin/src/gina/toolbar/.npmignore +0 -19
- package/core/asset/js/plugin/src/gina/toolbar/css/toolbar.css +0 -433
- package/core/asset/js/plugin/src/gina/toolbar/css/toolbar.css.map +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/index.html +0 -285
- package/core/asset/js/plugin/src/gina/toolbar/index.kit +0 -120
- package/core/asset/js/plugin/src/gina/toolbar/jquery-3.1.0.min.js +0 -4
- package/core/asset/js/plugin/src/gina/toolbar/main.js +0 -693
- package/core/asset/js/plugin/src/gina/toolbar/mock.gina.json +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/mock.user.json +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/readme.md +0 -7
- package/core/asset/js/plugin/src/gina/toolbar/sass/toolbar.sass +0 -563
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/Info-color.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/Info-grey.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/error-color.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/error-grey.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/info-optim.svg +0 -13
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/logo-gina.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/settings-big.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/settings.afdesign +0 -0
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/settings.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/stripe-calendar-optim.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/stripe-calendar.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/stripe-card-optim.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/stripe-card.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/stripe-lock-optim.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/stripe-lock.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/warning-color.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/svg-src/warning-grey.svg +0 -1
- package/core/asset/js/plugin/src/gina/toolbar/test.jpg +0 -0
- package/core/asset/js/plugin/src/gina/toolbar/toolbar.html +0 -104
- package/core/asset/js/plugin/src/gina/utils/dom.js +0 -24
- package/core/asset/js/plugin/src/gina/utils/events.js +0 -201
- package/core/asset/js/plugin/src/gina/utils/loader.js +0 -57
- package/core/asset/js/plugin/src/main.js +0 -235
- package/core/asset/js/plugin/src/vendor/jquery/1.11.1-css-event_alias.min.js +0 -5
- package/core/asset/js/plugin/src/vendor/jquery/1.12.4.min.js +0 -5
- package/core/asset/js/plugin/src/vendor/jquery/2.1.1-css-event_alias-sizzle.min.js +0 -4
- package/core/asset/js/plugin/src/vendor/jquery/README.md +0 -14
- package/core/asset/js/plugin/src/vendor/jquery/slim-3.1.1.min.js +0 -4
- package/core/config.js +0 -1225
- package/core/controller/controller.js +0 -1860
- package/core/gna.js +0 -908
- package/core/plugins/lib/validator/src/form-validator.js +0 -788
- package/core/plugins/lib/validator/src/main.js +0 -2056
- package/core/router.js +0 -717
- package/core/server.js +0 -1363
- package/core/template/conf/env.json +0 -70
- package/core/template/conf/settings.json +0 -48
- package/core/template/conf/statics.json +0 -6
- package/core/template/conf/views.json +0 -16
- package/core/template/samples/bundle/config/app.json +0 -4
- package/core/template/samples/bundle/config/routing.json +0 -9
- package/core/template/samples/bundle/controllers/setup.js +0 -33
- package/core/template/views/js/vendor/readme.md +0 -1
- package/core/template/views/readme.md +0 -1
- package/core/utils/helpers/dateFormat.js +0 -264
- package/core/utils/helpers/index.js +0 -202
- package/core/utils/index.js +0 -75
- package/core/utils/lib/cmd/app.js +0 -686
- package/core/utils/lib/cmd/basic.help.txt +0 -40
- package/core/utils/lib/cmd/basic.js +0 -141
- package/core/utils/lib/cmd/gina-add-bundle.js +0 -328
- package/core/utils/lib/cmd/gina-add-views.js +0 -99
- package/core/utils/lib/cmd/gina-build.js +0 -218
- package/core/utils/lib/cmd/gina-clean.js +0 -26
- package/core/utils/lib/cmd/gina-connect.js +0 -176
- package/core/utils/lib/cmd/gina-delete-bundle.js +0 -176
- package/core/utils/lib/cmd/gina-deploy.js +0 -452
- package/core/utils/lib/cmd/gina-init-project.js +0 -83
- package/core/utils/lib/cmd/gina-start-bundle.js +0 -3
- package/core/utils/lib/cmd/gina-start.js +0 -3
- package/core/utils/lib/cmd/index.js +0 -157
- package/core/utils/lib/cmd/project.js +0 -14
- package/core/utils/lib/collection/src/main.js +0 -650
- package/core/utils/lib/logger/containers/file.js +0 -11
- package/core/utils/lib/logger/index.js +0 -260
- package/core/utils/lib/merge/src/main.js +0 -344
- package/core/utils/lib/proc.js +0 -416
- package/core/utils/lib/routing/src/main.js +0 -165
- package/documentation/css/default.css +0 -3
- package/documentation/html/home.html +0 -6
- package/documentation/html/inc/_footer.html +0 -5
- package/documentation/html/layout.html +0 -21
- package/documentation/img/debug-conf1.png +0 -0
- package/documentation/img/debug-conf2.png +0 -0
- package/documentation/img/debug-conf3.png +0 -0
- package/documentation/img/debug-conf4.png +0 -0
- package/documentation/img/debug-conf5.png +0 -0
- package/documentation/img/debug-conf6.png +0 -0
- package/documentation/img/debug-conf7.png +0 -0
- package/documentation/img/debug-new1.png +0 -0
- package/documentation/img/debug-new2.png +0 -0
- package/documentation/img/debug-start.png +0 -0
- package/documentation/md/api/controller/main.md +0 -74
- package/migration_note.md +0 -7
- package/package-lock.json +0 -611
- package/script/pre_publish.js +0 -207
- package/tutorial/Commands/README.md +0 -56
- package/tutorial/Commands/add-bundle-result.png +0 -0
- package/tutorial/Commands/add-bundle.png +0 -0
- package/tutorial/Commands/delete-bundle.png +0 -0
- package/tutorial/Commands/help.png +0 -0
- package/tutorial/Commands/init-project.png +0 -0
- package/tutorial/Commands/start-bundle-result.png +0 -0
- package/tutorial/Commands/start-bundle-stop.png +0 -0
- package/tutorial/Commands/start-bundle.png +0 -0
- package/tutorial/Commands/version.png +0 -0
- package/tutorial/ETC/README.md +0 -74
- package/tutorial/ETC/add-bundle-result.png +0 -0
- package/tutorial/ETC/add-bundle.png +0 -0
- package/tutorial/ETC/init-project.png +0 -0
- package/tutorial/Install/README.md +0 -54
- package/tutorial/Install/git-get.png +0 -0
- package/tutorial/Install/git-install-end.png +0 -0
- package/tutorial/Install/git-install-result.png +0 -0
- package/tutorial/Install/git-install-start.png +0 -0
- package/tutorial/Install/install-end.png +0 -0
- package/tutorial/Install/install-result.png +0 -0
- package/tutorial/Install/install-start.png +0 -0
- package/tutorial/WebStorm/README.md +0 -30
- package/tutorial/WebStorm/closure-compiler.png +0 -0
- package/tutorial/WebStorm/sass.png +0 -0
|
@@ -0,0 +1,3990 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* This file is part of the gina package.
|
|
4
|
+
* Copyright (c) 2009-2022 Rhinostone <contact@gina.io>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
//Imports.
|
|
11
|
+
var fs = require('fs');
|
|
12
|
+
const {promises: {readFile}} = require("fs");
|
|
13
|
+
var util = require('util');
|
|
14
|
+
var promisify = util.promisify;
|
|
15
|
+
var EventEmitter = require('events').EventEmitter;
|
|
16
|
+
var zlib = require('zlib');
|
|
17
|
+
|
|
18
|
+
//var dns = require('dns');
|
|
19
|
+
// var tls = require('tls');
|
|
20
|
+
// var crypto = require('crypto');
|
|
21
|
+
|
|
22
|
+
var lib = require('./../../lib') || require.cache[require.resolve('./../../lib')];
|
|
23
|
+
var merge = lib.merge;
|
|
24
|
+
var inherits = lib.inherits;
|
|
25
|
+
var console = lib.logger;
|
|
26
|
+
var Collection = lib.Collection;
|
|
27
|
+
var routingUtils = lib.routing;
|
|
28
|
+
var swig = require('swig');
|
|
29
|
+
var SwigFilters = lib.SwigFilters;
|
|
30
|
+
var statusCodes = requireJSON( _( getPath('gina').core + '/status.codes') );
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @class SuperController
|
|
35
|
+
*
|
|
36
|
+
*
|
|
37
|
+
* @package Gina
|
|
38
|
+
* @namespace
|
|
39
|
+
* @author Rhinostone <contact@gina.io>
|
|
40
|
+
*
|
|
41
|
+
* @api Public
|
|
42
|
+
*/
|
|
43
|
+
function SuperController(options) {
|
|
44
|
+
|
|
45
|
+
//public
|
|
46
|
+
this.name = 'SuperController';
|
|
47
|
+
this.engine = {};
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
var self = this;
|
|
51
|
+
//private
|
|
52
|
+
var local = {
|
|
53
|
+
req : null,
|
|
54
|
+
res : null,
|
|
55
|
+
next : null,
|
|
56
|
+
options : options || null,
|
|
57
|
+
query : {},
|
|
58
|
+
_data : {},
|
|
59
|
+
view : {}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* SuperController Constructor
|
|
64
|
+
* @constructor
|
|
65
|
+
* */
|
|
66
|
+
var init = function() {
|
|
67
|
+
|
|
68
|
+
if ( typeof(SuperController.initialized) != 'undefined' ) {
|
|
69
|
+
return getInstance()
|
|
70
|
+
} else {
|
|
71
|
+
|
|
72
|
+
SuperController.instance = self;
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if (local.options) {
|
|
76
|
+
SuperController.instance._options = local.options;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
SuperController.initialized = true;
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var getInstance = function() {
|
|
85
|
+
local.options = SuperController.instance._options = options;
|
|
86
|
+
// 2022-03-07 Fix for none-developpement environnements (without cache)
|
|
87
|
+
self._options = local.options;
|
|
88
|
+
|
|
89
|
+
return SuperController.instance;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
var hasViews = function() {
|
|
93
|
+
return ( typeof(local.options.template) != 'undefined' ) ? true : false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* isHttp2
|
|
98
|
+
* Returns `true` if server configured for HTTP/2
|
|
99
|
+
*
|
|
100
|
+
* @returns {boolean} isHttp2
|
|
101
|
+
*/
|
|
102
|
+
var isHttp2 = function() {
|
|
103
|
+
var options = local.options;
|
|
104
|
+
var protocolVersion = ~~options.conf.server.protocol.match(/\/(.*)$/)[1].replace(/\.\d+/, '');
|
|
105
|
+
var httpLib = options.conf.server.protocol.match(/^(.*)\//)[1] + ( (protocolVersion >= 2) ? protocolVersion : '' );
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
return /http2/.test(httpLib)
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* isSecured
|
|
112
|
+
* Returns `true` if server configured to handle a HTTPS exchanges
|
|
113
|
+
*
|
|
114
|
+
* @returns {boolean} isSecured
|
|
115
|
+
*/
|
|
116
|
+
var isSecured = function() {
|
|
117
|
+
return /https/.test(local.options.conf.server.scheme)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.getRequestObject = function() {
|
|
121
|
+
return local.req;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.getResponseObject = function() {
|
|
125
|
+
return local.res;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.getNextCallback = function() {
|
|
129
|
+
return local.next;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Check if env is running cacheless
|
|
134
|
+
* */
|
|
135
|
+
this.isCacheless = function() {
|
|
136
|
+
return (/^true$/i.test(process.env.NODE_ENV_IS_DEV)) ? true : false;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if the project scope is set for local
|
|
140
|
+
* */
|
|
141
|
+
this.isLocalScope = function() {
|
|
142
|
+
return (/^true$/i.test(process.env.NODE_SCOPE_IS_LOCAL)) ? true : false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
this.setOptions = function(req, res, next, options) {
|
|
146
|
+
local.options = SuperController.instance._options = options;
|
|
147
|
+
local.options.renderingStack = (local.options.renderingStack) ? local.options.renderingStack : [];
|
|
148
|
+
local.options.isRenderingCustomError = (local.options.isRenderingCustomError) ? local.options.isRenderingCustomError : false;
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
// N.B.: Avoid setting `page` properties as much as possible from the routing.json
|
|
152
|
+
// It will be easier for the framework if set from the controller.
|
|
153
|
+
//
|
|
154
|
+
// Here is a sample if you choose to set `page.view.title` from the rule
|
|
155
|
+
// ------rouging rule sample -----
|
|
156
|
+
// {
|
|
157
|
+
// "default": {
|
|
158
|
+
// "url": ["", "/"],
|
|
159
|
+
// "param": {
|
|
160
|
+
// "control": "home",
|
|
161
|
+
// "title": "My Title"
|
|
162
|
+
// }
|
|
163
|
+
// }
|
|
164
|
+
//
|
|
165
|
+
// ------controller action sample -----
|
|
166
|
+
// Here is a sample if you decide to set `page.view.title` from your controller
|
|
167
|
+
//
|
|
168
|
+
// this.home = function(req, res, next) {
|
|
169
|
+
// var data = { page: { view: { title: "My Title"}}};
|
|
170
|
+
// self.render(data)
|
|
171
|
+
// }
|
|
172
|
+
|
|
173
|
+
if ( typeof(options.conf.content.routing[options.rule].param) != 'undefined' ) {
|
|
174
|
+
var str = 'page.'
|
|
175
|
+
, p = options.conf.content.routing[options.rule].param
|
|
176
|
+
;
|
|
177
|
+
|
|
178
|
+
for (var key in p) {
|
|
179
|
+
if ( p.hasOwnProperty(key) && !/^(control)$/.test(key) ) {
|
|
180
|
+
str += key + '.';
|
|
181
|
+
var obj = p[key], value = '';
|
|
182
|
+
for (var prop in obj) {
|
|
183
|
+
if (obj.hasOwnProperty(prop)) {
|
|
184
|
+
value += obj[prop]
|
|
185
|
+
} else {
|
|
186
|
+
|
|
187
|
+
if ( /^:/.test(value) ) {
|
|
188
|
+
str = 'page.view.params.'+ key + '.';
|
|
189
|
+
set(str.substr(0, str.length-1), req.params[value.substr(1)]);
|
|
190
|
+
} else if (/^(file|title)$/.test(key)) {
|
|
191
|
+
str = 'page.view.'+ key + '.';
|
|
192
|
+
set(str.substr(0, str.length-1), value);
|
|
193
|
+
} else {
|
|
194
|
+
set(str.substr(0, str.length-1), value)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
str = 'page.'
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
local.req = req;
|
|
205
|
+
local.res = res;
|
|
206
|
+
local.next = next;
|
|
207
|
+
|
|
208
|
+
getParams(req);
|
|
209
|
+
if ( typeof(local.options.template) != 'undefined' && typeof(local.options.control) != 'undefined' ) {
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
var action = local.options.control
|
|
213
|
+
, rule = local.options.rule
|
|
214
|
+
, ext = 'html' // by default
|
|
215
|
+
, isWithoutLayout = false // by default
|
|
216
|
+
, namespace = local.options.namespace || '';
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if ( typeof(local.options.template) != 'undefined' && local.options.template ) {
|
|
220
|
+
if (
|
|
221
|
+
typeof(local.options.template.ext) != 'undefined'
|
|
222
|
+
&& local.options.template.ext
|
|
223
|
+
&& local.options.template.ext != ''
|
|
224
|
+
) {
|
|
225
|
+
ext = local.options.template.ext
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if ( !/\./.test(ext) ) {
|
|
229
|
+
ext = '.' + ext;
|
|
230
|
+
local.options.template.ext = ext
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (
|
|
234
|
+
typeof(local.options.template.layout) == 'undefined'
|
|
235
|
+
|| /^false$/.test(local.options.template.layout)
|
|
236
|
+
|| local.options.template.layout == ''
|
|
237
|
+
) {
|
|
238
|
+
isWithoutLayout = true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
if ( hasViews() ) {
|
|
244
|
+
|
|
245
|
+
if ( typeof(local.options.file) == 'undefined') {
|
|
246
|
+
local.options.file = 'index'
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if ( typeof(local.options.isWithoutLayout) == 'undefined' || !isWithoutLayout ) {
|
|
250
|
+
local.options.isWithoutLayout = false;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
rule = local.options.rule;
|
|
254
|
+
namespace = local.options.namespace || 'default';
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
set('page.view.file', local.options.file);
|
|
258
|
+
set('page.view.title', rule.replace(new RegExp('@' + options.conf.bundle), ''));
|
|
259
|
+
set('page.view.namespace', namespace);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
var ctx = getContext('gina');
|
|
264
|
+
// new declaration && overrides
|
|
265
|
+
var version = {
|
|
266
|
+
"number" : ctx.version,
|
|
267
|
+
"platform" : process.platform,
|
|
268
|
+
"arch" : process.arch,
|
|
269
|
+
"nodejs" : process.versions.node,
|
|
270
|
+
"middleware" : ctx.middleware
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
set('page.environment.gina', version.number);
|
|
274
|
+
set('page.environment.gina pid', GINA_PID);
|
|
275
|
+
set('page.environment.nodejs', version.nodejs +' '+ version.platform +' '+ version.arch);
|
|
276
|
+
set('page.environment.engine', options.conf.server.engine);//version.middleware
|
|
277
|
+
set('page.environment.env', process.env.NODE_ENV);
|
|
278
|
+
set('page.environment.envIsDev', self.isCacheless());
|
|
279
|
+
set('page.environment.date.now', new Date().format("isoDateTime"));
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
var routing = local.options.conf.routing = ctx.config.envConf.routing; // all routes
|
|
283
|
+
set('page.environment.routing', escape(JSON.stringify(routing))); // export for GFF
|
|
284
|
+
//reverseRouting
|
|
285
|
+
var reverseRouting = local.options.conf.reverseRouting = ctx.config.envConf.reverseRouting; // all routes
|
|
286
|
+
set('page.environment.reverseRouting', escape(JSON.stringify(reverseRouting))); // export for GFF
|
|
287
|
+
|
|
288
|
+
var forms = local.options.conf.forms = options.conf.content.forms // all forms
|
|
289
|
+
set('page.environment.forms', escape(JSON.stringify(forms))); // export for GFF
|
|
290
|
+
set('page.forms', options.conf.content.forms);
|
|
291
|
+
|
|
292
|
+
set('page.environment.hostname', ctx.config.envConf[options.conf.bundle][process.env.NODE_ENV].hostname);
|
|
293
|
+
set('page.environment.webroot', options.conf.server.webroot);
|
|
294
|
+
set('page.environment.bundle', options.conf.bundle);
|
|
295
|
+
set('page.environment.project', options.conf.projectName);
|
|
296
|
+
set('page.environment.protocol', options.conf.server.protocol);
|
|
297
|
+
set('page.environment.scheme', options.conf.server.scheme);
|
|
298
|
+
set('page.environment.port', options.conf.server.port);
|
|
299
|
+
set('page.environment.debugPort', options.conf.server.debugPort);
|
|
300
|
+
set('page.environment.pid', process.pid);
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
set('page.view.ext', ext);
|
|
304
|
+
set('page.view.control', action);
|
|
305
|
+
set('page.view.controller', local.options.controller.replace(options.conf.bundlesPath, ''), true);
|
|
306
|
+
if (typeof (local.options.controlRequired) != 'undefined' ) {
|
|
307
|
+
set('page.view.controlRequired', local.options.controlRequired);
|
|
308
|
+
}
|
|
309
|
+
set('page.view.method', local.options.method);
|
|
310
|
+
set('page.view.namespace', namespace); // by default
|
|
311
|
+
set('page.view.url', req.url);
|
|
312
|
+
if ( local.options.template ) {
|
|
313
|
+
set('page.view.layout', local.options.template.layout.replace(new RegExp(local.options.template.templates+'/'), ''));
|
|
314
|
+
set('page.view.html.properties.mode.javascriptsDeferEnabled', local.options.template.javascriptsDeferEnabled);
|
|
315
|
+
set('page.view.html.properties.mode.routeNameAsFilenameEnabled', local.options.template.routeNameAsFilenameEnabled);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
var parameters = JSON.clone(req.getParams());
|
|
320
|
+
parameters = merge(parameters, options.conf.content.routing[rule].param);
|
|
321
|
+
// excluding default page properties
|
|
322
|
+
delete parameters[0];
|
|
323
|
+
delete parameters.file;
|
|
324
|
+
delete parameters.control;
|
|
325
|
+
delete parameters.title;
|
|
326
|
+
|
|
327
|
+
if (parameters.count() > 0)
|
|
328
|
+
set('page.view.params', parameters); // view parameters passed through URI or route params
|
|
329
|
+
|
|
330
|
+
set('page.view.route', rule);
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
var acceptLanguage = GINA_CULTURE; // by default : language-COUNTRY
|
|
334
|
+
if ( typeof(req.headers['accept-language']) != 'undefined' ) {
|
|
335
|
+
acceptLanguage = req.headers['accept-language']
|
|
336
|
+
} else if ( typeof(local.options.conf.server.response.header['accept-language']) != 'undefined' ) {
|
|
337
|
+
acceptLanguage = local.options.conf.server.response.header['accept-language']
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// set user locale: region & culture
|
|
341
|
+
var userCulture = acceptLanguage.split(',')[0];
|
|
342
|
+
var userCultureCode = userCulture.split(/\-/);
|
|
343
|
+
var userLangCode = userCultureCode[0];
|
|
344
|
+
var userCountryCode = userCultureCode[1];
|
|
345
|
+
|
|
346
|
+
var locales = new Collection( getContext('gina').locales );
|
|
347
|
+
var userLocales = null;
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
userLocales = locales.findOne({ lang: userLangCode }).content;
|
|
351
|
+
} catch (err) {
|
|
352
|
+
//var defaultRegion = (local.options.conf.content.settings.region) ? local.options.conf.content.settings.region.shortCode
|
|
353
|
+
console.warn('language code `'+ userLangCode +'` not handled by current locales setup: replacing by default: `'+ local.options.conf.content.settings.region.shortCode +'`');
|
|
354
|
+
userLocales = locales.findOne({ lang: local.options.conf.content.settings.region.shortCode }).content // by default
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// user locales list
|
|
358
|
+
local.options.conf.locales = userLocales;
|
|
359
|
+
|
|
360
|
+
// user locale
|
|
361
|
+
options.conf.locale = new Collection(userLocales).findOne({ short: userCountryCode }) || {};
|
|
362
|
+
|
|
363
|
+
//set('page.date.now', new Date().format("isoDateTime"));
|
|
364
|
+
if ( typeof(options.conf.locale) == 'undefined' || !options.conf.locale ) {
|
|
365
|
+
options.conf.locale = {}
|
|
366
|
+
}
|
|
367
|
+
options.conf.locale.date = {
|
|
368
|
+
now: new Date().format("isoDateTime")
|
|
369
|
+
}
|
|
370
|
+
set('page.view.locale', options.conf.locale);
|
|
371
|
+
set('page.view.lang', userCulture);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if ( !getContext('isProxyHost') ) {
|
|
375
|
+
var isProxyHost = ( typeof(req.headers.host) != 'undefined' && local.options.conf.server.scheme +'://'+ req.headers.host != local.options.conf.hostname || typeof(req.headers[':authority']) != 'undefined' && local.options.conf.server.scheme +'://'+ req.headers[':authority'] != local.options.conf.hostname ) ? true : false;
|
|
376
|
+
setContext('isProxyHost', isProxyHost);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
//TODO - detect when to use swig
|
|
380
|
+
var dir = null;
|
|
381
|
+
if (local.options.template || self.templates) {
|
|
382
|
+
dir = local.options.template.templates || self.templates;
|
|
383
|
+
|
|
384
|
+
var swigOptions = {
|
|
385
|
+
autoescape : ( typeof(local.options.autoescape) != 'undefined') ? local.options.autoescape : false,
|
|
386
|
+
// `memory` is no working yet ... advanced rendering setup required
|
|
387
|
+
//cache : (local.options.cacheless) ? false : 'memory'
|
|
388
|
+
cache : false
|
|
389
|
+
};
|
|
390
|
+
if (dir) {
|
|
391
|
+
swigOptions.loader = swig.loaders.fs(dir);
|
|
392
|
+
}
|
|
393
|
+
if ( typeof(local._swigOptions) == 'undefined' ) {
|
|
394
|
+
local._swigOptions = JSON.clone(swigOptions);
|
|
395
|
+
}
|
|
396
|
+
swig.setDefaults(swigOptions);
|
|
397
|
+
// used for self.engine.compile(tpl, swigOptions)(data)
|
|
398
|
+
swig.getOptions = function() {
|
|
399
|
+
return local._swigOptions;
|
|
400
|
+
}
|
|
401
|
+
// preserve the same timezone as the system
|
|
402
|
+
var defaultTZOffset = new Date().getTimezoneOffset();
|
|
403
|
+
swig.setDefaultTZOffset(defaultTZOffset);
|
|
404
|
+
|
|
405
|
+
self.engine = swig;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
this.renderWithoutLayout = function (data, displayToolbar) {
|
|
410
|
+
|
|
411
|
+
// preventing multiple call of self.renderWithoutLayout() when controller is rendering from another required controller
|
|
412
|
+
if (local.options.renderingStack.length > 1) {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
local.options.isWithoutLayout = true;
|
|
417
|
+
|
|
418
|
+
self.render(data, displayToolbar);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Render HTML templates : Swig is the default template engine
|
|
423
|
+
*
|
|
424
|
+
* Extend default filters
|
|
425
|
+
* - length
|
|
426
|
+
*
|
|
427
|
+
* Avilable filters:
|
|
428
|
+
* - getWebroot()
|
|
429
|
+
* - getUrl()
|
|
430
|
+
*
|
|
431
|
+
* N.B.: Filters can be extended through your `<project>/src/<bundle>/controllers/setup.js`
|
|
432
|
+
*
|
|
433
|
+
*
|
|
434
|
+
* @param {object} userData
|
|
435
|
+
* @param {boolean} [displayToolbar]
|
|
436
|
+
* @param {object} [errOptions]
|
|
437
|
+
* @returns {void}
|
|
438
|
+
* */
|
|
439
|
+
this.render = async function(userData, displayToolbar, errOptions) {
|
|
440
|
+
var err = null;
|
|
441
|
+
var isRenderingCustomError = (
|
|
442
|
+
typeof(userData.isRenderingCustomError) != 'undefined'
|
|
443
|
+
&& /^true$/i.test(userData.isRenderingCustomError)
|
|
444
|
+
) ? true : false;
|
|
445
|
+
if (isRenderingCustomError)
|
|
446
|
+
delete userData.isRenderingCustomError;
|
|
447
|
+
|
|
448
|
+
var localOptions = (errOptions) ? errOptions : local.options;
|
|
449
|
+
localOptions.renderingStack.push( self.name );
|
|
450
|
+
// preventing multiple call of self.render() when controller is rendering from another required controller
|
|
451
|
+
if ( localOptions.renderingStack.length > 1 && !isRenderingCustomError ) {
|
|
452
|
+
return false
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
var data = null
|
|
457
|
+
, layout = null
|
|
458
|
+
, template = null
|
|
459
|
+
, file = null
|
|
460
|
+
, path = null
|
|
461
|
+
, plugin = null
|
|
462
|
+
, isWithoutLayout = (localOptions.isWithoutLayout) ? true : false
|
|
463
|
+
;
|
|
464
|
+
|
|
465
|
+
localOptions.debugMode = ( typeof(displayToolbar) == 'undefined' ) ? undefined : ( (/true/i.test(displayToolbar)) ? true : false ); // only active for dev env
|
|
466
|
+
|
|
467
|
+
// specific override
|
|
468
|
+
if (
|
|
469
|
+
self.isCacheless()
|
|
470
|
+
&& typeof(local.req[ local.req.method.toLowerCase() ]) != 'undefined'
|
|
471
|
+
&& typeof(local.req[ local.req.method.toLowerCase() ].debug) != 'undefined'
|
|
472
|
+
) {
|
|
473
|
+
localOptions.debugMode = ( /true/i.test(local.req[ local.req.method.toLowerCase() ].debug) ) ? true : false;
|
|
474
|
+
} else if (
|
|
475
|
+
self.isCacheless()
|
|
476
|
+
&& hasViews()
|
|
477
|
+
&& !isWithoutLayout
|
|
478
|
+
&& localOptions.debugMode == undefined
|
|
479
|
+
) {
|
|
480
|
+
localOptions.debugMode = true;
|
|
481
|
+
} else if ( localOptions.debugMode == undefined ) {
|
|
482
|
+
localOptions.debugMode = self.isCacheless()
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
data = getData();
|
|
487
|
+
|
|
488
|
+
if (!userData) {
|
|
489
|
+
userData = { page: { view: {}}}
|
|
490
|
+
} else if ( userData && !userData['page']) {
|
|
491
|
+
|
|
492
|
+
if ( typeof(data['page']['data']) == 'undefined' )
|
|
493
|
+
data['page']['data'] = userData;
|
|
494
|
+
else
|
|
495
|
+
data['page']['data'] = (isRenderingCustomError) ? userData : merge( userData, data['page']['data'] );
|
|
496
|
+
} else {
|
|
497
|
+
data = (isRenderingCustomError) ? userData : merge(userData, data)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
template = localOptions.rule.replace('\@'+ localOptions.bundle, '');
|
|
501
|
+
var localTemplateConf = localOptions.template;
|
|
502
|
+
if ( isWithoutLayout ) {
|
|
503
|
+
localTemplateConf = JSON.clone(localOptions.template);
|
|
504
|
+
localTemplateConf.javascripts = new Collection(localTemplateConf.javascripts).find({ isCommon: false}, { isCommon: true, name: 'gina' });
|
|
505
|
+
localTemplateConf.stylesheets = new Collection(localTemplateConf.stylesheets).find({ isCommon: false}, { isCommon: true, name: 'gina' });
|
|
506
|
+
}
|
|
507
|
+
setResources(localTemplateConf);
|
|
508
|
+
// Allowing file & ext override
|
|
509
|
+
if (
|
|
510
|
+
typeof(local.req.routing.param.file) != 'undefined'
|
|
511
|
+
&& data.page.view.file !== local.req.routing.param.file
|
|
512
|
+
) {
|
|
513
|
+
data.page.view.file = localOptions.file = local.req.routing.param.file
|
|
514
|
+
}
|
|
515
|
+
if (
|
|
516
|
+
typeof(local.req.routing.param.ext) != 'undefined'
|
|
517
|
+
&& data.page.view.ext !== local.req.routing.param.ext
|
|
518
|
+
) {
|
|
519
|
+
data.page.view.ext = localOptions.template.ext = local.req.routing.param.ext
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
file = (isRenderingCustomError) ? localOptions.file : data.page.view.file;
|
|
523
|
+
|
|
524
|
+
// pre-compiling variables
|
|
525
|
+
data = merge(data, getData()); // needed !!
|
|
526
|
+
|
|
527
|
+
if (typeof(data.page.data) == 'undefined' ) {
|
|
528
|
+
data.page.data = {}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
if (
|
|
533
|
+
!local.options.isRenderingCustomError
|
|
534
|
+
&& typeof(data.page.data.status) != 'undefined'
|
|
535
|
+
&& !/^2/.test(data.page.data.status)
|
|
536
|
+
&& typeof(data.page.data.error) != 'undefined'
|
|
537
|
+
) {
|
|
538
|
+
var statusCode = localOptions.conf.server.coreConfiguration.statusCodes;
|
|
539
|
+
var errorObject = {
|
|
540
|
+
status: data.page.data.status,
|
|
541
|
+
//errors: msg.error || msg.errors || msg,
|
|
542
|
+
error: statusCodes[data.page.data.status] || msg.error || msg,
|
|
543
|
+
message: data.page.data.message || data.page.data.error,
|
|
544
|
+
stack: data.page.data.stack
|
|
545
|
+
};
|
|
546
|
+
if ( typeof(data.page.data.session) != 'undefined' ) {
|
|
547
|
+
errorObject.session = data.page.data.session;
|
|
548
|
+
}
|
|
549
|
+
self.throwError(errorObject);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// making path thru [namespace &] file
|
|
554
|
+
if ( typeof(localOptions.namespace) != 'undefined' && localOptions.namespace ) {
|
|
555
|
+
// excepted for custom paths
|
|
556
|
+
if ( !/^(\.|\/|\\)/.test(file) )
|
|
557
|
+
file = ''+ file.replace(localOptions.namespace+'-', '');
|
|
558
|
+
|
|
559
|
+
// means that rule name === namespace -> pointing to root namespace dir
|
|
560
|
+
if (!file || file === localOptions.namespace) {
|
|
561
|
+
file = 'index'
|
|
562
|
+
}
|
|
563
|
+
path = (isRenderingCustomError) ? _(file) : _(localOptions.template.html +'/'+ localOptions.namespace + '/' + file)
|
|
564
|
+
} else {
|
|
565
|
+
if ( localOptions.path && !/(\?|\#)/.test(localOptions.path) ) {
|
|
566
|
+
path = _(localOptions.path);
|
|
567
|
+
var re = new RegExp( data.page.view.ext+'$');
|
|
568
|
+
if ( data.page.view.ext && re.test(data.page.view.file) ) {
|
|
569
|
+
data.page.view.path = path.replace('/'+ data.page.view.file, '');
|
|
570
|
+
|
|
571
|
+
path = path.replace(re, '');
|
|
572
|
+
data.page.view.file = data.page.view.file.replace(re, '');
|
|
573
|
+
|
|
574
|
+
} else {
|
|
575
|
+
data.page.view.path = path.replace('/'+ data.page.view.file, '');
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
} else {
|
|
579
|
+
path = (!isRenderingCustomError && !/^(\.|\/|\\)/.test(file))
|
|
580
|
+
? _(localOptions.template.html +'/'+ file)
|
|
581
|
+
: file
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (data.page.view.ext && !new RegExp(data.page.view.ext+ '$').test(file) /** && hasViews() && fs.existsSync(_(path + data.page.view.ext, true))*/ ) {
|
|
586
|
+
path += data.page.view.ext
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
data.page.view.path = path;
|
|
590
|
+
|
|
591
|
+
var dic = {}, msg = '';
|
|
592
|
+
for (var d in data.page) {
|
|
593
|
+
dic['page.'+d] = data.page[d]
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
// please, do not start with a slashe when including...
|
|
599
|
+
// ex.:
|
|
600
|
+
// /html/inc/_partial.html (BAD)
|
|
601
|
+
// html/inc/_partial.html (GOOD)
|
|
602
|
+
// ./html/namespace/page.html (GOOD)
|
|
603
|
+
|
|
604
|
+
if ( !fs.existsSync(path) ) {
|
|
605
|
+
msg = 'could not open "'+ path +'"' +
|
|
606
|
+
'\n1) The requested file does not exists in your templates/html (check your template directory). Can you find: '+path +
|
|
607
|
+
'\n2) Check the following rule in your `'+localOptions.conf.bundlePath+'/config/routing.json` and look around `param` to make sure that nothing is wrong with your file declaration: '+
|
|
608
|
+
'\n' + options.rule +':'+ JSON.stringify(options.conf.content.routing[options.rule], null, 4) +
|
|
609
|
+
'\n3) At this point, if you still have problems trying to run this portion of code, you can contact us telling us how to reproduce the bug.'
|
|
610
|
+
//'\n\r[ stack trace ] '
|
|
611
|
+
;
|
|
612
|
+
err = new ApiError(msg, 500);
|
|
613
|
+
console.error(err.stack);
|
|
614
|
+
self.throwError(err);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
var isProxyHost = (
|
|
619
|
+
typeof(local.req.headers.host) != 'undefined'
|
|
620
|
+
&& localOptions.conf.server.scheme +'://'+ local.req.headers.host != localOptions.conf.hostname
|
|
621
|
+
|| typeof(local.req.headers[':authority']) != 'undefined'
|
|
622
|
+
&& localOptions.conf.server.scheme +'://'+ local.req.headers[':authority'] != localOptions.conf.hostname
|
|
623
|
+
) ? true : false;
|
|
624
|
+
// setup swig default filters
|
|
625
|
+
var filters = SwigFilters({
|
|
626
|
+
options : JSON.clone(localOptions),
|
|
627
|
+
isProxyHost : isProxyHost,
|
|
628
|
+
throwError : self.throwError,
|
|
629
|
+
req : local.req,
|
|
630
|
+
res : local.res
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
try {
|
|
634
|
+
|
|
635
|
+
// Extends default `length` filter
|
|
636
|
+
swig.setFilter('length', filters.length);
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
// Allows you to get a bundle web root
|
|
641
|
+
swig.setFilter('getWebroot', filters.getWebroot);
|
|
642
|
+
|
|
643
|
+
swig.setFilter('getUrl', filters.getUrl);
|
|
644
|
+
|
|
645
|
+
} catch (err) {
|
|
646
|
+
// [ martin ]
|
|
647
|
+
// i sent an email to [ paul@paularmstrongdesigns.com ] on 2014/08 to see if there is:
|
|
648
|
+
// a way of retrieving swig compilation stack traces
|
|
649
|
+
//var stack = __stack.splice(1).toString().split(',').join('\n');
|
|
650
|
+
// -> no response...
|
|
651
|
+
self.throwError(local.res, 500, new Error('template compilation exception encoutered: [ '+path+' ]\n'+(err.stack||err.message)));
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
var layoutPath = null
|
|
658
|
+
, assets = null
|
|
659
|
+
, mapping = null
|
|
660
|
+
, XHRData = null
|
|
661
|
+
, XHRView = null
|
|
662
|
+
, isDeferModeEnabled = null
|
|
663
|
+
, viewInfos = null
|
|
664
|
+
, filename = null
|
|
665
|
+
, isWithSwigLayout = null
|
|
666
|
+
, isUsingGinaLayout = (!isWithoutLayout && typeof(localOptions.template.layout) != 'undefined' && fs.existsSync(local.options.template.layout)) ? true : false
|
|
667
|
+
;
|
|
668
|
+
|
|
669
|
+
if ( isWithoutLayout || isUsingGinaLayout ) {
|
|
670
|
+
layoutPath = (isWithoutLayout) ? localOptions.template.noLayout : localOptions.template.layout;
|
|
671
|
+
// user layout override
|
|
672
|
+
if ( isUsingGinaLayout && !isWithoutLayout ) {
|
|
673
|
+
layoutPath = localOptions.template.layout;
|
|
674
|
+
}
|
|
675
|
+
if (isWithoutLayout) {
|
|
676
|
+
data.page.view.layout = layoutPath;
|
|
677
|
+
}
|
|
678
|
+
} else { // without layout case
|
|
679
|
+
|
|
680
|
+
// by default
|
|
681
|
+
layoutPath = localOptions.template.layout;
|
|
682
|
+
if ( !/^\//.test(layoutPath)) {
|
|
683
|
+
layoutPath = localOptions.template.templates +'/'+ layoutPath;
|
|
684
|
+
}
|
|
685
|
+
// default layout
|
|
686
|
+
if (
|
|
687
|
+
!isWithoutLayout && !fs.existsSync(layoutPath) && layoutPath == localOptions.template.templates +'/index.html'
|
|
688
|
+
) {
|
|
689
|
+
console.warn('Layout '+ local.options.template.layout +' not found, replacing with `nolayout`: '+ localOptions.template.noLayout);
|
|
690
|
+
layoutPath = localOptions.template.noLayout
|
|
691
|
+
isWithoutLayout = true;
|
|
692
|
+
data.page.view.layout = layoutPath;
|
|
693
|
+
}
|
|
694
|
+
// user defiend layout
|
|
695
|
+
else if ( !isWithoutLayout && !fs.existsSync(layoutPath) ) {
|
|
696
|
+
isWithSwigLayout = true;
|
|
697
|
+
layoutPath = localOptions.template.noLayout;
|
|
698
|
+
data.page.view.layout = layoutPath;
|
|
699
|
+
}
|
|
700
|
+
// layout defiendd but not found
|
|
701
|
+
else if (!fs.existsSync(layoutPath) ) {
|
|
702
|
+
err = new ApiError(options.bundle +' SuperController exception while trying to load your layout `'+ layoutPath +'`.\nIt seems like you have defined a layout, but gina could not locate the file.\nFor more informations, check your `config/templates.json` declaration around `'+ local.options.rule.replace(/\@(.*)/g, '') +'`', 500);
|
|
703
|
+
self.throwError(err);
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
var isLoadingPartial = false;
|
|
711
|
+
try {
|
|
712
|
+
assets = {assets:"${assets}"};
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* retrieve template & layout
|
|
716
|
+
* */
|
|
717
|
+
var tpl = null;
|
|
718
|
+
// tpl = fs.readFileSync(path).toString();
|
|
719
|
+
// layout = fs.readFileSync(layoutPath).toString();
|
|
720
|
+
|
|
721
|
+
await Promise.all([
|
|
722
|
+
readFile(layoutPath),
|
|
723
|
+
readFile(path)
|
|
724
|
+
])
|
|
725
|
+
.then(([_layout, _tpl]) => {
|
|
726
|
+
layout = _layout.toString();
|
|
727
|
+
tpl = _tpl.toString();
|
|
728
|
+
})
|
|
729
|
+
.catch(error => {
|
|
730
|
+
console.error(error.message);
|
|
731
|
+
return;
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
// mappin conf
|
|
736
|
+
mapping = { filename: path };
|
|
737
|
+
if (isRenderingCustomError) {
|
|
738
|
+
// TODO - Test if there is a block call `gina-error` in the layout & replace block name from tpl
|
|
739
|
+
|
|
740
|
+
if ( !/\{\%(\s+extends|extends)/.test(tpl) ) {
|
|
741
|
+
tpl = "\n{% extends '"+ layoutPath +"' %}\n" + tpl;
|
|
742
|
+
}
|
|
743
|
+
if (!/\{\% block content/.test(tpl)) {
|
|
744
|
+
// TODO - test if lyout has <body>
|
|
745
|
+
tpl = '{% block content %}<p>If you view this message you didn’t define a content block in your template.</p>{% endblock %}' + tpl;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
tpl = tpl.replace(/\{\{ page\.content \}\}/g, '');
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if ( isWithoutLayout || isWithSwigLayout) {
|
|
752
|
+
layout = tpl;
|
|
753
|
+
} else if (isUsingGinaLayout) {
|
|
754
|
+
mapping = { filename: path };
|
|
755
|
+
if ( /(\{\{|\{\{\s+)page\.content/.test(layout) ) {
|
|
756
|
+
|
|
757
|
+
if ( /\{\%(\s+extends|extends)/.test(tpl) ) {
|
|
758
|
+
err = new Error('You cannot use at the same time `page.content` in your layout `'+ layoutPath +'` while calling `extends` from your page or content `'+ path +'`. You have to choose one or the other');
|
|
759
|
+
self.throwError(local.res, 500, err);
|
|
760
|
+
return
|
|
761
|
+
}
|
|
762
|
+
layout = layout.replace('{{ page.content }}', tpl);
|
|
763
|
+
} else {
|
|
764
|
+
layout = layout.replace(/\<\/body\>/i, '\t'+tpl+'\n</body>');
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
} else {
|
|
768
|
+
tpl = tpl.replace('{{ page.view.layout }}', data.page.view.layout);
|
|
769
|
+
if (/\<\/body\>/i.test(layout)) {
|
|
770
|
+
layout = layout.replace(/\<\/body\>/i, '\t'+tpl+'\n</body>');
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
layout += tpl;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// precompilation needed in case of `extends` or in order to display the toolbar
|
|
778
|
+
if ( hasViews() && self.isCacheless() || /\{\%(\s+extends|extends)/.test(layout) ) {
|
|
779
|
+
layout = swig.compile(layout, mapping)(data);
|
|
780
|
+
}
|
|
781
|
+
//dic['page.content'] = layout;
|
|
782
|
+
|
|
783
|
+
} catch(err) {
|
|
784
|
+
err.stack = 'Exception, bad syntax or undefined data found: start investigating in '+ mapping.filename +'\n' + err.stack;
|
|
785
|
+
self.throwError(local.res, 500, err);
|
|
786
|
+
return
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
isLoadingPartial = (
|
|
790
|
+
!/\<html/i.test(layout)
|
|
791
|
+
|| !/\<head/i.test(layout)
|
|
792
|
+
|| !/\<body/i.test(layout)
|
|
793
|
+
) ? true : false;
|
|
794
|
+
|
|
795
|
+
// if (isLoadingPartial) {
|
|
796
|
+
// console.warn('----------------> loading partial `'+ path);
|
|
797
|
+
// }
|
|
798
|
+
|
|
799
|
+
isDeferModeEnabled = localOptions.template.javascriptsDeferEnabled || localOptions.conf.content.templates._common.javascriptsDeferEnabled || false;
|
|
800
|
+
|
|
801
|
+
// iframe case - without HTML TAG
|
|
802
|
+
if (!self.isXMLRequest() && !/\<html/.test(layout) ) {
|
|
803
|
+
layout = '<html>\n\t<head></head>\n\t<body class="gina-iframe-body">\n\t\t'+ layout +'\n\t</body>\n</html>';
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// adding stylesheets
|
|
807
|
+
if (!isWithoutLayout && data.page.view.stylesheets && !/\{\{\s+(page\.view\.stylesheets)\s+\}\}/.test(layout) ) {
|
|
808
|
+
layout = layout.replace(/\<\/head\>/i, '\n\t{{ page.view.stylesheets }}\n</head>')
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
if (hasViews() && isWithoutLayout) {
|
|
812
|
+
// $.getScript(...)
|
|
813
|
+
//var isProxyHost = ( typeof(local.req.headers.host) != 'undefined' && localOptions.conf.server.scheme +'://'+ local.req.headers.host != localOptions.conf.hostname || typeof(local.req.headers[':authority']) != 'undefined' && localOptions.conf.server.scheme +'://'+ local.req.headers[':authority'] != localOptions.conf.hostname ) ? true : false;
|
|
814
|
+
//var hostname = (isProxyHost) ? localOptions.conf.hostname.replace(/\:\d+$/, '') : localOptions.conf.hostname;
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
var scripts = data.page.view.scripts;
|
|
819
|
+
scripts = scripts.replace(/\s+\<script/g, '\n<script');
|
|
820
|
+
|
|
821
|
+
if (!isProxyHost) {
|
|
822
|
+
var webroot = data.page.environment.webroot;
|
|
823
|
+
scripts = scripts.replace(/src\=\"\/(.*)\"/g, 'src="'+ webroot +'$1"');
|
|
824
|
+
//stylesheets = stylesheets.replace(/href\=\"\/(.*)\"/g, 'href="'+ webroot +'$1"')
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// iframe case - without HTML TAG
|
|
828
|
+
if (self.isXMLRequest() || !/\<html/.test(layout) ) {
|
|
829
|
+
layout += scripts;
|
|
830
|
+
//layout += stylesheets;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// adding plugins
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
if (
|
|
839
|
+
hasViews() && self.isCacheless() && !isWithoutLayout
|
|
840
|
+
&& localOptions.debugMode
|
|
841
|
+
||
|
|
842
|
+
hasViews() && self.isCacheless() && !isWithoutLayout
|
|
843
|
+
&& typeof(localOptions.debugMode) == 'undefined'
|
|
844
|
+
||
|
|
845
|
+
hasViews() && localOptions.debugMode
|
|
846
|
+
) {
|
|
847
|
+
|
|
848
|
+
layout = ''
|
|
849
|
+
+ '{%- set ginaDataInspector = JSON.clone(page) -%}'
|
|
850
|
+
+ '{%- set ginaDataInspector.view.assets = {} -%}'
|
|
851
|
+
+ '{%- set ginaDataInspector.view.scripts = "ignored-by-toolbar" -%}'
|
|
852
|
+
+ '{%- set ginaDataInspector.view.stylesheets = "ignored-by-toolbar" -%}'
|
|
853
|
+
+ layout
|
|
854
|
+
;
|
|
855
|
+
|
|
856
|
+
plugin = '\t'
|
|
857
|
+
+ '{# Gina Toolbar #}'
|
|
858
|
+
+ '{%- set userDataInspector = JSON.clone(page) -%}'
|
|
859
|
+
+ '{%- set userDataInspector.view.scripts = "ignored-by-toolbar" -%}'
|
|
860
|
+
+ '{%- set userDataInspector.view.stylesheets = "ignored-by-toolbar" -%}'
|
|
861
|
+
+ '{%- set userDataInspector.view.assets = '+ JSON.stringify(assets) +' -%}'
|
|
862
|
+
+ '{%- include "'+ getPath('gina').core +'/asset/js/plugin/src/gina/toolbar/toolbar.html" with { gina: ginaDataInspector, user: userDataInspector } -%}'
|
|
863
|
+
+ '{# END Gina Toolbar #}'
|
|
864
|
+
;
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
if (isWithoutLayout && localOptions.debugMode || localOptions.debugMode ) {
|
|
868
|
+
|
|
869
|
+
XHRData = '\t<input type="hidden" id="gina-without-layout-xhr-data" value="'+ encodeURIComponent(JSON.stringify(data.page.data)) +'">\n\r';
|
|
870
|
+
|
|
871
|
+
layout = layout.replace(/<\/body>/i, XHRData + '\n\t</body>');
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (self.isCacheless() || localOptions.debugMode ) {
|
|
875
|
+
layout = layout.replace(/<\/body>/i, plugin + '\n\t</body>');
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// adding javascripts
|
|
879
|
+
layout.replace('{{ page.view.scripts }}', '');
|
|
880
|
+
// placed in the HEAD excepted when rendering a partial or when `isDeferModeEnabled` == true
|
|
881
|
+
if (isLoadingPartial) {
|
|
882
|
+
layout += '\t{{ page.view.scripts }}';
|
|
883
|
+
} else {
|
|
884
|
+
if ( isDeferModeEnabled ) {
|
|
885
|
+
layout = layout.replace(/\<\/head\>/i, '\t{{ page.view.scripts }}\n\t</head>');
|
|
886
|
+
} else { // placed in the BODY
|
|
887
|
+
layout = layout.replace(/\<\/body\>/i, '\t{{ page.view.scripts }}\n</body>');
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// ginaLoader cannot be deferred
|
|
892
|
+
if ( !localOptions.template.javascriptsExcluded || localOptions.template.javascriptsExcluded != '**' ) {
|
|
893
|
+
layout = layout.replace(/\<\/head\>/i, '\t'+ localOptions.template.ginaLoader +'\n</head>');
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
} else if ( hasViews() && self.isCacheless() && self.isXMLRequest() ) {
|
|
897
|
+
|
|
898
|
+
if (isWithoutLayout) {
|
|
899
|
+
delete data.page.view.scripts;
|
|
900
|
+
delete data.page.view.stylesheets;
|
|
901
|
+
}
|
|
902
|
+
// means that we don't want GFF context or we already have it loaded
|
|
903
|
+
viewInfos = JSON.clone(data.page.view);
|
|
904
|
+
if ( !isWithoutLayout )
|
|
905
|
+
viewInfos.assets = assets;
|
|
906
|
+
|
|
907
|
+
XHRData = '\n<input type="hidden" id="gina-without-layout-xhr-data" value="'+ encodeURIComponent(JSON.stringify(data.page.data)) +'">';
|
|
908
|
+
XHRView = '\n<input type="hidden" id="gina-without-layout-xhr-view" value="'+ encodeURIComponent(JSON.stringify(viewInfos)) +'">';
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
layout += XHRData + XHRView;
|
|
912
|
+
|
|
913
|
+
} else { // other envs like prod ...
|
|
914
|
+
|
|
915
|
+
// adding javascripts
|
|
916
|
+
// cleanup first
|
|
917
|
+
layout.replace('{{ page.view.scripts }}', '');
|
|
918
|
+
// placed in the HEAD excepted when rendering a partial or when `isDeferModeEnabled` == true
|
|
919
|
+
// if (isLoadingPartial) {
|
|
920
|
+
// layout += '\t{{ page.view.scripts }}';
|
|
921
|
+
// } else {
|
|
922
|
+
// if ( isDeferModeEnabled ) {
|
|
923
|
+
// layout = layout.replace(/\<\/head\>/i, '\t{{ page.view.scripts }}\n\t</head>');
|
|
924
|
+
// } else { // placed in the BODY
|
|
925
|
+
// layout = layout.replace(/\<\/body\>/i, '\t{{ page.view.scripts }}\n</body>');
|
|
926
|
+
// }
|
|
927
|
+
// }
|
|
928
|
+
|
|
929
|
+
// // ginaLoader cannot be deferred
|
|
930
|
+
// if ( !localOptions.template.javascriptsExcluded || localOptions.template.javascriptsExcluded != '**' ) {
|
|
931
|
+
// layout = layout.replace(/\<\/head\>/i, '\t'+ localOptions.template.ginaLoader +'\n</head>');
|
|
932
|
+
// }
|
|
933
|
+
|
|
934
|
+
// adding javascripts
|
|
935
|
+
layout.replace('{{ page.view.scripts }}', '');
|
|
936
|
+
if (isLoadingPartial) {
|
|
937
|
+
layout += '\t{{ page.view.scripts }}\n';
|
|
938
|
+
if ( !localOptions.template.javascriptsExcluded || localOptions.template.javascriptsExcluded != '**' ) {
|
|
939
|
+
layout += '\t'+ localOptions.template.ginaLoader +'\n';
|
|
940
|
+
}
|
|
941
|
+
} else {
|
|
942
|
+
if ( isDeferModeEnabled && /\<\/head\>/i.test(layout) ) { // placed in the HEAD
|
|
943
|
+
layout = layout.replace(/\<\/head\>/i, '\t{{ page.view.scripts }}\n\t</head>');
|
|
944
|
+
|
|
945
|
+
} else { // placed in the BODY
|
|
946
|
+
layout = layout.replace(/\<\/body\>/i, '\t{{ page.view.scripts }}\n</body>');
|
|
947
|
+
}
|
|
948
|
+
// ginaLoader cannot be deferred
|
|
949
|
+
if ( !localOptions.template.javascriptsExcluded || localOptions.template.javascriptsExcluded != '**' ) {
|
|
950
|
+
layout = layout.replace(/\<\/head\>/i, '\t'+ localOptions.template.ginaLoader +'\n</head>');
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
layout = whisper(dic, layout, /\{{ ([a-zA-Z.]+) \}}/g );
|
|
957
|
+
dic['page.content'] = layout;
|
|
958
|
+
/**
|
|
959
|
+
// special case for template without layout in debug mode - dev only
|
|
960
|
+
if ( hasViews() && localOptions.debugMode && self.isCacheless() && !/\{\# Gina Toolbar \#\}/.test(layout) ) {
|
|
961
|
+
try {
|
|
962
|
+
|
|
963
|
+
layout = layout.replace(/<\/body>/i, plugin + '\n\t</body>');
|
|
964
|
+
layout = whisper(dic, layout, /\{{ ([a-zA-Z.]+) \}}/g );
|
|
965
|
+
//swig.invalidateCache();
|
|
966
|
+
layout = swig.compile(layout, mapping)(data);
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
} catch (err) {
|
|
970
|
+
filename = localOptions.template.html;
|
|
971
|
+
filename += ( typeof(data.page.view.namespace) != 'undefined' && data.page.view.namespace != '' && new RegExp('^' + data.page.view.namespace +'-').test(data.page.view.file) ) ? '/' + data.page.view.namespace + data.page.view.file.split(data.page.view.namespace +'-').join('/') + ( (data.page.view.ext != '') ? data.page.view.ext: '' ) : '/' + data.page.view.file+ ( (data.page.view.ext != '') ? data.page.view.ext: '' );
|
|
972
|
+
self.throwError(local.res, 500, new Error('Compilation error encountered while trying to process template `'+ filename + '`\n'+(err.stack||err.message)));
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
else if (hasViews() && localOptions.debugMode && self.isCacheless()) {
|
|
977
|
+
try {
|
|
978
|
+
//layout = whisper(dic, layout, /\{{ ([a-zA-Z.]+) \}}/g );
|
|
979
|
+
layout = swig.compile(layout, mapping)(data);
|
|
980
|
+
} catch (err) {
|
|
981
|
+
filename = localOptions.template.html;
|
|
982
|
+
filename += ( typeof(data.page.view.namespace) != 'undefined' && data.page.view.namespace != '' && new RegExp('^' + data.page.view.namespace +'-').test(data.page.view.file) ) ? '/' + data.page.view.namespace + data.page.view.file.split(data.page.view.namespace +'-').join('/') + ( (data.page.view.ext != '') ? data.page.view.ext: '' ) : '/' + data.page.view.file+ ( (data.page.view.ext != '') ? data.page.view.ext: '' );
|
|
983
|
+
self.throwError(local.res, 500, new Error('Compilation error encountered while trying to process template `'+ filename + '`\n'+(err.stack||err.message)));
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
*/
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
if ( !local.res.headersSent ) {
|
|
991
|
+
local.res.statusCode = ( typeof(localOptions.conf.server.coreConfiguration.statusCodes[data.page.data.status]) != 'undefined' ) ? data.page.data.status : 200; // by default
|
|
992
|
+
//catching errors
|
|
993
|
+
if (
|
|
994
|
+
typeof(data.page.data.errno) != 'undefined' && /^2/.test(data.page.data.status) && typeof(localOptions.conf.server.coreConfiguration.statusCodes[data.page.data.status]) != 'undefined'
|
|
995
|
+
|| typeof(data.page.data.status) != 'undefined' && !/^2/.test(data.page.data.status) && typeof(localOptions.conf.server.coreConfiguration.statusCodes[data.page.data.status]) != 'undefined'
|
|
996
|
+
) {
|
|
997
|
+
|
|
998
|
+
try {
|
|
999
|
+
local.res.statusMessage = localOptions.conf.server.coreConfiguration.statusCodes[data.page.data.status];
|
|
1000
|
+
} catch (err){
|
|
1001
|
+
local.res.statusCode = 500;
|
|
1002
|
+
local.res.statusMessage = err.stack||err.message||localOptions.conf.server.coreConfiguration.statusCodes[local.res.statusCode];
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
local.res.setHeader('content-type', localOptions.conf.server.coreConfiguration.mime['html'] + '; charset='+ localOptions.conf.encoding );
|
|
1007
|
+
|
|
1008
|
+
try {
|
|
1009
|
+
|
|
1010
|
+
// escape special chars
|
|
1011
|
+
var blacklistRe = new RegExp('[\<\>]', 'g');
|
|
1012
|
+
// DO NOT REPLACE IT BY JSON.clone() !!!!
|
|
1013
|
+
|
|
1014
|
+
data.page.data = JSON.parse(JSON.stringify(data.page.data).replace(blacklistRe, '\$&'));
|
|
1015
|
+
|
|
1016
|
+
} catch (err) {
|
|
1017
|
+
filename = localOptions.template.html;
|
|
1018
|
+
filename += ( typeof(data.page.view.namespace) != 'undefined' && data.page.view.namespace != '' && new RegExp('^' + data.page.view.namespace +'-').test(data.page.view.file) ) ? '/' + data.page.view.namespace + data.page.view.file.split(data.page.view.namespace +'-').join('/') + ( (data.page.view.ext != '') ? data.page.view.ext: '' ) : '/' + data.page.view.file+ ( (data.page.view.ext != '') ? data.page.view.ext: '' );
|
|
1019
|
+
self.throwError(local.res, 500, new Error('Controller::render(...) compilation error encountered while trying to process template `'+ filename + '`\n' + (err.stack||err.message||err) ));
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
// Only available for http/2.0 for now
|
|
1025
|
+
if ( !self.isXMLRequest() && /http\/2/.test(localOptions.conf.server.protocol) ) {
|
|
1026
|
+
try {
|
|
1027
|
+
// TODO - button in toolbar to empty url assets cache
|
|
1028
|
+
if ( /** self.isCacheless() ||*/ typeof(localOptions.template.assets) == 'undefined' || typeof(localOptions.template.assets[local.req.url]) == 'undefined' ) {
|
|
1029
|
+
// assets string -> object
|
|
1030
|
+
//assets = self.serverInstance.getAssets(localOptions.conf, layout.toString(), swig, data);
|
|
1031
|
+
assets = self.serverInstance.getAssets(localOptions.conf, layout, swig, data);
|
|
1032
|
+
localOptions.template.assets = JSON.parse(assets);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// only for toolbar - TODO hasToolbar()
|
|
1036
|
+
if (
|
|
1037
|
+
self.isCacheless() && hasViews() && !isWithoutLayout
|
|
1038
|
+
|| hasViews() && localOptions.debugMode
|
|
1039
|
+
|| self.isCacheless() && hasViews() && self.isXMLRequest()
|
|
1040
|
+
) {
|
|
1041
|
+
layout = layout.replace('{"assets":"${assets}"}', assets );
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
self.throwError(local.res, 500, new Error('Controller::render(...) calling getAssets(...) \n' + (err.stack||err.message||err) ));
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// Last compilation before rendering
|
|
1051
|
+
layout = swig.compile(layout, mapping)(data);
|
|
1052
|
+
|
|
1053
|
+
if ( !local.res.headersSent ) {
|
|
1054
|
+
if ( local.options.isRenderingCustomError ) {
|
|
1055
|
+
local.options.isRenderingCustomError = false;
|
|
1056
|
+
}
|
|
1057
|
+
local.res.end(layout);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
console.info(local.req.method +' ['+local.res.statusCode +'] '+ local.req.url);
|
|
1061
|
+
|
|
1062
|
+
} else if (typeof(local.next) != 'undefined') {
|
|
1063
|
+
// local.next();
|
|
1064
|
+
return local.next();
|
|
1065
|
+
} else {
|
|
1066
|
+
if ( typeof(local.req.params.errorObject) != 'undefined' ) {
|
|
1067
|
+
self.throwError(local.req.params.errorObject);
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
local.res.end('Unexpected controller error while trying to render.');
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
} catch (err) {
|
|
1074
|
+
self.throwError(local.res, 500, err);
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
this.isXMLRequest = function() {
|
|
1081
|
+
return local.options.isXMLRequest;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
this.isWithCredentials = function() {
|
|
1085
|
+
return ( /true/.test(local.options.withCredentials) ) ? true : false;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Render JSON
|
|
1090
|
+
*
|
|
1091
|
+
* @param {object|string} jsonObj
|
|
1092
|
+
* @param {object} [req]
|
|
1093
|
+
* @param {object} [res]
|
|
1094
|
+
*
|
|
1095
|
+
* @callback {function} [next]
|
|
1096
|
+
*
|
|
1097
|
+
* */
|
|
1098
|
+
this.renderJSON = function(jsonObj) {
|
|
1099
|
+
|
|
1100
|
+
// preventing multiple call of self.renderJSON() when controller is rendering from another required controller
|
|
1101
|
+
if (local.options.renderingStack.length > 1) {
|
|
1102
|
+
return false
|
|
1103
|
+
}
|
|
1104
|
+
if ( self.isProcessingError ) {
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
var request = local.req;
|
|
1109
|
+
var response = local.res;
|
|
1110
|
+
var next = local.next || null;
|
|
1111
|
+
// var stream = null;
|
|
1112
|
+
// if ( /http\/2/.test(local.options.conf.server.protocol) ) {
|
|
1113
|
+
// stream = response.stream;
|
|
1114
|
+
// }
|
|
1115
|
+
|
|
1116
|
+
if (!jsonObj) {
|
|
1117
|
+
jsonObj = {}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
try {
|
|
1121
|
+
// just in case
|
|
1122
|
+
if ( typeof(jsonObj) == 'string') {
|
|
1123
|
+
jsonObj = JSON.parse(jsonObj)
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// if( typeof(local.options) != "undefined" && typeof(local.options.charset) != "undefined" ){
|
|
1127
|
+
// response.setHeader("charset", local.options.charset);
|
|
1128
|
+
// }
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
//catching errors
|
|
1132
|
+
if (
|
|
1133
|
+
typeof(jsonObj.errno) != 'undefined' && response.statusCode == 200
|
|
1134
|
+
|| typeof(jsonObj.status) != 'undefined' && jsonObj.status != 200 && typeof(local.options.conf.server.coreConfiguration.statusCodes[jsonObj.status]) != 'undefined'
|
|
1135
|
+
) {
|
|
1136
|
+
|
|
1137
|
+
try {
|
|
1138
|
+
response.statusCode = jsonObj.status;
|
|
1139
|
+
response.statusMessage = local.options.conf.server.coreConfiguration.statusCodes[jsonObj.status];
|
|
1140
|
+
} catch (err){
|
|
1141
|
+
response.statusCode = 500;
|
|
1142
|
+
response.statusMessage = err.stack;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
// Internet Explorer override
|
|
1148
|
+
if ( /msie/i.test(request.headers['user-agent']) ) {
|
|
1149
|
+
response.setHeader('content-type', 'text/plain' + '; charset='+ local.options.conf.encoding)
|
|
1150
|
+
} else {
|
|
1151
|
+
response.setHeader('content-type', local.options.conf.server.coreConfiguration.mime['json'] + '; charset='+ local.options.conf.encoding)
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
if ( !response.headersSent ) {
|
|
1155
|
+
console.info(request.method +' ['+ response.statusCode +'] '+ request.url);
|
|
1156
|
+
|
|
1157
|
+
if ( local.options.isXMLRequest && self.isWithCredentials() ) {
|
|
1158
|
+
|
|
1159
|
+
var data = JSON.stringify(jsonObj);
|
|
1160
|
+
var len = 0;
|
|
1161
|
+
// content length must be the right size !
|
|
1162
|
+
if ( typeof(data) === 'string') {
|
|
1163
|
+
len = Buffer.byteLength(data, 'utf8')
|
|
1164
|
+
} else {
|
|
1165
|
+
len = data.length
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
if (!response.headersSent)
|
|
1169
|
+
response.setHeader("content-length", len);
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
// if (stream && !stream.destroyed) {
|
|
1173
|
+
// //stream.respond(header);
|
|
1174
|
+
// stream.end(data);
|
|
1175
|
+
// } else {
|
|
1176
|
+
response.write(data);
|
|
1177
|
+
|
|
1178
|
+
// required to close connection
|
|
1179
|
+
setTimeout(function () {
|
|
1180
|
+
response.end();
|
|
1181
|
+
try {
|
|
1182
|
+
response.headersSent = true;
|
|
1183
|
+
} catch(err) {
|
|
1184
|
+
// Ignoring warning
|
|
1185
|
+
//console.warn(err);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
if ( next ) {
|
|
1189
|
+
next()
|
|
1190
|
+
}
|
|
1191
|
+
}, 200);
|
|
1192
|
+
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
return // force completion
|
|
1196
|
+
// }
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
} else { // normal case
|
|
1200
|
+
response.end(JSON.stringify(jsonObj));
|
|
1201
|
+
if (!response.headersSent) {
|
|
1202
|
+
try {
|
|
1203
|
+
response.headersSent = true;
|
|
1204
|
+
} catch(err) {
|
|
1205
|
+
// Ignoring warning
|
|
1206
|
+
//console.warn(err);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
if ( next ) {
|
|
1210
|
+
next()
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
} catch (err) {
|
|
1217
|
+
self.throwError(response, 500, err);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
this.renderTEXT = function(content) {
|
|
1225
|
+
|
|
1226
|
+
// preventing multiple call of self.renderTEXT() when controller is rendering from another required controller
|
|
1227
|
+
if (local.options.renderingStack.length > 1) {
|
|
1228
|
+
return false
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
if ( typeof(content) != "string" ) {
|
|
1232
|
+
content = content.toString();
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// if (typeof(options) != "undefined" && typeof(options.charset) !="undefined") {
|
|
1236
|
+
// local.res.setHeader("charset", options.charset);
|
|
1237
|
+
// }
|
|
1238
|
+
if ( !local.res.getHeaders()['content-type'] ) {
|
|
1239
|
+
local.res.setHeader('content-type', 'text/plain' + '; charset='+ local.options.conf.encoding);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
if ( !local.res.headersSent ) {
|
|
1243
|
+
console.info(local.req.method +' ['+local.res.statusCode +'] '+ local.req.url);
|
|
1244
|
+
local.res.end(content);
|
|
1245
|
+
try {
|
|
1246
|
+
local.res.headersSent = true
|
|
1247
|
+
} catch(err) {
|
|
1248
|
+
// Ignoring warning
|
|
1249
|
+
//console.warn(err);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
var parseDataObject = function(o, obj, override) {
|
|
1255
|
+
|
|
1256
|
+
for (var i in o) {
|
|
1257
|
+
if ( o[i] !== null && typeof(o[i]) == 'object' || override && o[i] !== null && typeof(o[i]) == 'object' ) {
|
|
1258
|
+
parseDataObject(o[i], obj);
|
|
1259
|
+
} else if (o[i] == '_content_'){
|
|
1260
|
+
o[i] = obj
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
return o
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* Set data
|
|
1269
|
+
*
|
|
1270
|
+
* @param {string} nave - variable name to set
|
|
1271
|
+
* @param {string|object} value - value to set
|
|
1272
|
+
* @param {boolean} [override]
|
|
1273
|
+
*
|
|
1274
|
+
* @returns {void}
|
|
1275
|
+
* */
|
|
1276
|
+
var set = function(name, value, override) {
|
|
1277
|
+
|
|
1278
|
+
var override = ( typeof(override) != 'undefined' ) ? override : false;
|
|
1279
|
+
|
|
1280
|
+
if ( typeof(name) == 'string' && /\./.test(name) ) {
|
|
1281
|
+
var keys = name.split(/\./g)
|
|
1282
|
+
, newObj = {}
|
|
1283
|
+
, str = '{'
|
|
1284
|
+
, _count = 0;
|
|
1285
|
+
|
|
1286
|
+
for (var k = 0, len = keys.length; k<len; ++k) {
|
|
1287
|
+
str += "\""+ keys.splice(0,1)[0] + "\":{";
|
|
1288
|
+
|
|
1289
|
+
++_count;
|
|
1290
|
+
if (k == len-1) {
|
|
1291
|
+
str = str.substr(0, str.length-1);
|
|
1292
|
+
str += "\"_content_\"";
|
|
1293
|
+
for (var c = 0; c<_count; ++c) {
|
|
1294
|
+
str += "}"
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
newObj = parseDataObject(JSON.parse(str), value, override);
|
|
1300
|
+
local.userData = merge(local.userData, newObj);
|
|
1301
|
+
|
|
1302
|
+
} else if ( typeof(local.userData[name]) == 'undefined' ) {
|
|
1303
|
+
local.userData[name] = value.replace(/\\/g, '')
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* Get data
|
|
1309
|
+
*
|
|
1310
|
+
* @param {String} variable Data name to set
|
|
1311
|
+
* @returns {Object | String} data Data object or String
|
|
1312
|
+
* */
|
|
1313
|
+
var get = function(variable) {
|
|
1314
|
+
return local.userData[variable]
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* Set resources
|
|
1319
|
+
*
|
|
1320
|
+
* @param {object} template - template configuration
|
|
1321
|
+
* */
|
|
1322
|
+
var setResources = function(viewConf) {
|
|
1323
|
+
if (!viewConf) {
|
|
1324
|
+
self.throwError(500, new Error('No views configuration found. Did you try to add views before using Controller::render(...) ? Try to run: gina view:add '+ options.conf.bundle +' @'+ options.conf.projectName));
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
var authority = ( typeof(local.req.headers['x-forwarded-proto']) != 'undefined' ) ? local.req.headers['x-forwarded-proto'] : local.options.conf.server.scheme;
|
|
1329
|
+
authority += '://'+ local.req.headers.host;
|
|
1330
|
+
var useWebroot = false;
|
|
1331
|
+
if ( !/^\/$/.test(local.options.conf.server.webroot) && local.options.conf.server.webroot.length > 0 && local.options.conf.hostname.replace(/\:\d+$/, '') == authority ) {
|
|
1332
|
+
useWebroot = true
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
var reURL = new RegExp('^'+ local.options.conf.server.webroot);
|
|
1336
|
+
|
|
1337
|
+
var cssStr = '', jsStr = '';
|
|
1338
|
+
|
|
1339
|
+
//Get css
|
|
1340
|
+
if( viewConf.stylesheets ) {
|
|
1341
|
+
cssStr = getNodeRes('css', viewConf.stylesheets, useWebroot, reURL)
|
|
1342
|
+
}
|
|
1343
|
+
//Get js
|
|
1344
|
+
if( viewConf.javascripts ) {
|
|
1345
|
+
jsStr = getNodeRes('js', viewConf.javascripts, useWebroot, reURL)
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
set('page.view.stylesheets', cssStr);
|
|
1349
|
+
set('page.view.scripts', jsStr);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* Get node resources
|
|
1354
|
+
*
|
|
1355
|
+
* @param {string} type
|
|
1356
|
+
* @param {string} resStr
|
|
1357
|
+
* @param {array} resArr
|
|
1358
|
+
* @param {object} resObj
|
|
1359
|
+
*
|
|
1360
|
+
* @returns {object} content
|
|
1361
|
+
*
|
|
1362
|
+
* @private
|
|
1363
|
+
* */
|
|
1364
|
+
var getNodeRes = function(type, resArr, useWebroot, reURL) {
|
|
1365
|
+
|
|
1366
|
+
var r = 0
|
|
1367
|
+
, rLen = resArr.length
|
|
1368
|
+
, obj = null
|
|
1369
|
+
, str = ''
|
|
1370
|
+
;
|
|
1371
|
+
switch(type){
|
|
1372
|
+
case 'css':
|
|
1373
|
+
for (; r < rLen; ++r) {
|
|
1374
|
+
obj = resArr[r];
|
|
1375
|
+
if (useWebroot && !reURL.test(obj.url) ) {
|
|
1376
|
+
obj.url = local.options.conf.server.webroot + obj.url.substr(1);
|
|
1377
|
+
}
|
|
1378
|
+
// TODO - add support for cdn
|
|
1379
|
+
if (!/\:\/\//.test(obj.url) ) {
|
|
1380
|
+
obj.url = local.options.conf.hostname + obj.url;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
if (obj.media)
|
|
1384
|
+
str += '\n\t\t<link href="'+ obj.url +'" media="'+ obj.media +'" rel="'+ obj.rel +'" type="'+ obj.type +'">';
|
|
1385
|
+
else
|
|
1386
|
+
str += '\n\t\t<link href="'+ obj.url +'" rel="'+ obj.rel +'" type="'+ obj.type +'">';
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
return str;
|
|
1390
|
+
break;
|
|
1391
|
+
|
|
1392
|
+
case 'js':
|
|
1393
|
+
var deferMode = (local.options.template.javascriptsDeferEnabled) ? ' defer' : '';
|
|
1394
|
+
|
|
1395
|
+
for (; r < rLen; ++r) {
|
|
1396
|
+
obj = resArr[r];
|
|
1397
|
+
if (useWebroot && !reURL.test(obj.url) ) {
|
|
1398
|
+
obj.url = local.options.conf.server.webroot + obj.url.substr(1);
|
|
1399
|
+
}
|
|
1400
|
+
// TODO - add support for cdn
|
|
1401
|
+
if (!/\:\/\//.test(obj.url) ) {
|
|
1402
|
+
obj.url = local.options.conf.hostname + obj.url;
|
|
1403
|
+
}
|
|
1404
|
+
str += '\n\t\t<script'+ deferMode +' type="'+ obj.type +'" src="'+ obj.url +'"></script>'
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
return str;
|
|
1408
|
+
break;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* TODO - SuperController.setMeta()
|
|
1414
|
+
* */
|
|
1415
|
+
// this.setMeta = function(metaName, metacontent) {
|
|
1416
|
+
//
|
|
1417
|
+
// }
|
|
1418
|
+
|
|
1419
|
+
var getData = function() {
|
|
1420
|
+
return refToObj( local.userData )
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
|
|
1424
|
+
var isValidURL = function(url){
|
|
1425
|
+
var re = /(http|ftp|https|sftp):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/;
|
|
1426
|
+
return (re.test(url)) ? true : false
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* Set method - Override current method
|
|
1431
|
+
* E.g.: in case of redirect, to force PUT to GET
|
|
1432
|
+
*
|
|
1433
|
+
* @param {string} requestMethod - GET, POST, PUT, DELETE
|
|
1434
|
+
*/
|
|
1435
|
+
var localRequestMethod = null, localRequestMethodParams = null;
|
|
1436
|
+
this.setRequestMethod = function(requestMethod, conf) {
|
|
1437
|
+
// http/2 case
|
|
1438
|
+
if ( /http\/2/i.test(conf.server.protocolShort) ) {
|
|
1439
|
+
local.req.headers[':method'] = local.req.method.toUpperCase()
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
localRequestMethod = local.req.method = local.req.routing.method = requestMethod.toUpperCase();
|
|
1443
|
+
|
|
1444
|
+
local.res.setHeader('access-control-allow-methods', localRequestMethod);
|
|
1445
|
+
|
|
1446
|
+
return localRequestMethod;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
this.getRequestMethod = function() {
|
|
1450
|
+
return localRequestMethod;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
this.setRequestMethodParams = function(params) {
|
|
1454
|
+
localRequestMethodParams = local.req[local.req.method.toLowerCase()] = localRequestMethodParams = params
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
this.getRequestMethodParams = function() {
|
|
1458
|
+
return (localRequestMethodParams) ? localRequestMethodParams : local.req[local.req.method.toLowerCase()]
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/**
|
|
1462
|
+
* isStaticRoute
|
|
1463
|
+
* Trying to determine if url is a `statics` ressource
|
|
1464
|
+
*
|
|
1465
|
+
* @param {string} url
|
|
1466
|
+
* @param {string} method
|
|
1467
|
+
*
|
|
1468
|
+
* @returns {boolean} isStaticRoute
|
|
1469
|
+
*/
|
|
1470
|
+
var isStaticRoute = function(url, method, bundle, env, conf) {
|
|
1471
|
+
|
|
1472
|
+
if ( !/get/i.test(method) ) {
|
|
1473
|
+
return false
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// priority to statics - this portion of code has been duplicated to Server.js
|
|
1477
|
+
|
|
1478
|
+
var staticsArr = conf[bundle][env].publicResources;
|
|
1479
|
+
var staticProps = {
|
|
1480
|
+
firstLevel : '/' + url.split(/\//g)[1] + '/',
|
|
1481
|
+
// to be considered as a stativ content, url must content at least 2 caracters after last `.`: .js, .html are ok
|
|
1482
|
+
isStaticFilename : /(\.([A-Za-z0-9]+){2}|\/)$/.test(url)
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1485
|
+
// handle resources from public with webroot in url
|
|
1486
|
+
if ( staticProps.isStaticFilename && conf[bundle][env].server.webroot != '/' && staticProps.firstLevel == conf[bundle][env].server.webroot ) {
|
|
1487
|
+
var matchedFirstInUrl = url.replace(conf[bundle][env].server.webroot, '').match(/[A-Za-z0-9_-]+\/?/);
|
|
1488
|
+
if ( matchedFirstInUrl && matchedFirstInUrl.length > 0 ) {
|
|
1489
|
+
staticProps.firstLevel = conf[bundle][env].server.webroot + matchedFirstInUrl[0]
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
if (
|
|
1494
|
+
staticProps.isStaticFilename && staticsArr.indexOf(url) > -1
|
|
1495
|
+
|| staticProps.isStaticFilename && staticsArr.indexOf( url.replace(url.substr(url.lastIndexOf('/')+1), '') ) > -1
|
|
1496
|
+
|| staticProps.isStaticFilename && staticsArr.indexOf(staticProps.firstLevel) > -1
|
|
1497
|
+
) {
|
|
1498
|
+
return true
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
return false;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* redirect
|
|
1506
|
+
*
|
|
1507
|
+
* TODO - improve redirect based on `utils.routing`
|
|
1508
|
+
* e.g.: self.redirect('project-get', { companyId: companyId, clientId: clientId, id: projectId }, true)
|
|
1509
|
+
*
|
|
1510
|
+
* How to avoid redirect inside popin context
|
|
1511
|
+
* N.B.: When you are in a popin context, add an `id` to your template tag so it can be ignored by the default PopinHandler
|
|
1512
|
+
* E.g.: id="delete-link" -> <a href="#" id="delete-link">delete</a>
|
|
1513
|
+
*
|
|
1514
|
+
* You have to ways of using this method
|
|
1515
|
+
*
|
|
1516
|
+
* 1) Through routing.json
|
|
1517
|
+
* ---------------------
|
|
1518
|
+
* Allows you to redirect to an internal [ route ], an internal [ path ], or an external [ url ]
|
|
1519
|
+
*
|
|
1520
|
+
* For this to work you have to set in your routing.json a new route using "param":
|
|
1521
|
+
* { "control": "redirect", "route": "one-valid-route" }
|
|
1522
|
+
* OR
|
|
1523
|
+
* { "control": "redirect", "url": "http://www.somedomain.com/page.html" }
|
|
1524
|
+
*
|
|
1525
|
+
* OR
|
|
1526
|
+
* { "control": "redirect", "path": "/", "ignoreWebRoot": true }
|
|
1527
|
+
*
|
|
1528
|
+
* OR
|
|
1529
|
+
* { "control": "redirect", "url": "http://home@public/production", "ignoreWebRoot": true }
|
|
1530
|
+
*
|
|
1531
|
+
* if you are free to use the redirection [ code ] of your choice, we've set it to 301 by default
|
|
1532
|
+
*
|
|
1533
|
+
*
|
|
1534
|
+
* 2) By calling this.redirect(rule, [ignoreWebRoot]):
|
|
1535
|
+
* ------------------------------------------------
|
|
1536
|
+
* where `this` is :
|
|
1537
|
+
* - a Controller instance
|
|
1538
|
+
*
|
|
1539
|
+
* Where `rule` is either a string defining
|
|
1540
|
+
* - the rule/route name
|
|
1541
|
+
* => home (will use same bundle, same protocol scheme & same environment)
|
|
1542
|
+
* => home@public (will use same protocol scheme & same environment)
|
|
1543
|
+
* => http://home@public/dev (port style for more precision)
|
|
1544
|
+
*
|
|
1545
|
+
* - an URI
|
|
1546
|
+
* => /home
|
|
1547
|
+
*
|
|
1548
|
+
* - a URL
|
|
1549
|
+
* => http://www.google.com/
|
|
1550
|
+
*
|
|
1551
|
+
*
|
|
1552
|
+
* And Where `ignoreWebRoot` is an optional parameter used to ignore web root settings (Standalone mode or user set web root)
|
|
1553
|
+
* `ignoreWebRoot` behaves the like set to `false` by default
|
|
1554
|
+
*
|
|
1555
|
+
* N.B.: Gina will tell browsers not to cache redirections if you are using `dev` environement
|
|
1556
|
+
*
|
|
1557
|
+
* Trobleshouting:
|
|
1558
|
+
* ---------------
|
|
1559
|
+
*
|
|
1560
|
+
* Redirecting to a popin from the controller while posting from a form
|
|
1561
|
+
* If this does not work, like doing a real redirect, this
|
|
1562
|
+
* only means that the ID you are using for the form might be
|
|
1563
|
+
* a duplicate one from the the main document !!!
|
|
1564
|
+
*
|
|
1565
|
+
* @param {object|string} req|rule - Request Object or Rule/Route name
|
|
1566
|
+
* @param {object|boolean} res|ignoreWebRoot - Response Object or Ignore WebRoot & start from domain root: /
|
|
1567
|
+
* @param {object} [params] TODO
|
|
1568
|
+
*
|
|
1569
|
+
* @callback [ next ]
|
|
1570
|
+
* */
|
|
1571
|
+
this.redirect = function(req, res, next) {
|
|
1572
|
+
var conf = self.getConfig();
|
|
1573
|
+
var bundle = conf.bundle;
|
|
1574
|
+
var env = conf.env;
|
|
1575
|
+
var wroot = conf.server.webroot;
|
|
1576
|
+
var ctx = getContext('gina');
|
|
1577
|
+
var routing = ctx.config.getRouting();//conf.content.routing;
|
|
1578
|
+
var route = '', rte = '';
|
|
1579
|
+
var ignoreWebRoot = null, isRelative = false;
|
|
1580
|
+
var originalUrl = null;
|
|
1581
|
+
var method = null;
|
|
1582
|
+
var originalMethod = null;
|
|
1583
|
+
|
|
1584
|
+
if ( typeof(req) === 'string' ) {
|
|
1585
|
+
|
|
1586
|
+
// if ( typeof(res) == 'undefined') {
|
|
1587
|
+
// // nothing to do
|
|
1588
|
+
// ignoreWebRoot = false
|
|
1589
|
+
// } else
|
|
1590
|
+
if (typeof(res) === 'string' || typeof(res) === 'number' || typeof(res) === 'boolean') {
|
|
1591
|
+
if ( /true|1/.test(res) ) {
|
|
1592
|
+
ignoreWebRoot = true
|
|
1593
|
+
} else if ( /false|0/.test(res) ) {
|
|
1594
|
+
ignoreWebRoot = false
|
|
1595
|
+
} else {
|
|
1596
|
+
res = local.res;
|
|
1597
|
+
var stack = __stack.splice(1).toString().split(',').join('\n');
|
|
1598
|
+
self.throwError(res, 500, new Error('RedirectError: @param `ignoreWebRoot` must be a boolean\n' + stack));
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
} else {
|
|
1602
|
+
// detect by default
|
|
1603
|
+
if (!ignoreWebRoot) {
|
|
1604
|
+
var re = new RegExp('^'+wroot)
|
|
1605
|
+
if ( re.test(req) ) {
|
|
1606
|
+
ignoreWebRoot = true;
|
|
1607
|
+
} else {
|
|
1608
|
+
ignoreWebRoot = false;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
if ( req.substr(0,1) === '/') { // is relative (not checking if the URI is defined in the routing.json)
|
|
1615
|
+
// if (wroot.substr(wroot.length-1,1) == '/') {
|
|
1616
|
+
// wroot = wroot.substr(wroot.length-1,1).replace('/', '')
|
|
1617
|
+
// }
|
|
1618
|
+
|
|
1619
|
+
if ( /^\//.test(req) && !ignoreWebRoot )
|
|
1620
|
+
req = req.substr(1);
|
|
1621
|
+
|
|
1622
|
+
rte = ( ignoreWebRoot != null && ignoreWebRoot ) ? req : wroot + req;
|
|
1623
|
+
// cleaning url in case of ?param=value
|
|
1624
|
+
originalUrl = rte;
|
|
1625
|
+
rte = rte.replace(/\?(.*)/, '');
|
|
1626
|
+
|
|
1627
|
+
req = local.req;
|
|
1628
|
+
originalMethod = ( typeof(req.originalMethod) != 'undefined') ? req.originalMethod : req.method;
|
|
1629
|
+
console.debug('[ BUNDLE ][ '+ local.options.conf.bundle +' ][ Controller ] trying to get route: ', rte, bundle, req.method);
|
|
1630
|
+
if ( !ignoreWebRoot || !isStaticRoute(rte, req.method, bundle, env, ctx.config.envConf) && !ignoreWebRoot ) {
|
|
1631
|
+
req.routing = lib.routing.getRouteByUrl(rte, bundle, req.method, req);
|
|
1632
|
+
// try alternative method
|
|
1633
|
+
if (!req.routing) {
|
|
1634
|
+
req.routing = lib.routing.getRouteByUrl(rte, bundle, 'GET', req, true); // true == override
|
|
1635
|
+
// if still (!req.routing) { should throw a 404 }
|
|
1636
|
+
if (req.routing) {
|
|
1637
|
+
method = req.method = 'GET'
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
//route = route = req.routing.name;
|
|
1642
|
+
} else {
|
|
1643
|
+
req.routing = {
|
|
1644
|
+
param : {
|
|
1645
|
+
url: rte
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
res = local.res;
|
|
1651
|
+
next = local.next;
|
|
1652
|
+
isRelative = true;
|
|
1653
|
+
|
|
1654
|
+
req.routing.param.path = rte
|
|
1655
|
+
} else if ( isValidURL(req) ) { // might be an URL
|
|
1656
|
+
rte = req;
|
|
1657
|
+
originalUrl = rte;
|
|
1658
|
+
rte = rte.replace(/\?(.*)/, '');
|
|
1659
|
+
|
|
1660
|
+
req = local.req;
|
|
1661
|
+
res = local.res;
|
|
1662
|
+
next = local.next;
|
|
1663
|
+
|
|
1664
|
+
req.routing.param.url = rte
|
|
1665
|
+
} else { // is by default a route name
|
|
1666
|
+
|
|
1667
|
+
if ( /\@/.test(req) ) {
|
|
1668
|
+
var rteArr = req.split(/\//);
|
|
1669
|
+
if ( typeof(rteArr[1]) != 'undefined' )
|
|
1670
|
+
env = rteArr[1];
|
|
1671
|
+
|
|
1672
|
+
rte = route = rteArr[0];
|
|
1673
|
+
rteArr = rteArr[0].split(/\@/);
|
|
1674
|
+
|
|
1675
|
+
bundle = rteArr[1];
|
|
1676
|
+
|
|
1677
|
+
} else {
|
|
1678
|
+
rte = route = ( new RegExp('^/'+conf.bundle+'-$').test(req) ) ? req : wroot.match(/[^/]/g).join('') +'-'+ req;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
|
|
1682
|
+
req = local.req;
|
|
1683
|
+
res = local.res;
|
|
1684
|
+
next = local.next;
|
|
1685
|
+
|
|
1686
|
+
req.routing.param.route = routing[rte]
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
} else {
|
|
1690
|
+
route = req.routing.param.route;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
if ( !originalMethod ) {
|
|
1694
|
+
originalMethod = ( typeof(req.originalMethod) != 'undefined') ? req.originalMethod : req.method;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
var path = originalUrl || req.routing.param.path || '';
|
|
1698
|
+
var url = req.routing.param.url;
|
|
1699
|
+
var code = req.routing.param.code || 301;
|
|
1700
|
+
|
|
1701
|
+
var keepParams = req.routing.param['keep-params'] || false;
|
|
1702
|
+
|
|
1703
|
+
var condition = true; //set by default for url @ path redirect
|
|
1704
|
+
|
|
1705
|
+
if (route) { // will go with route first
|
|
1706
|
+
condition = ( typeof(routing[route]) != 'undefined') ? true : false;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
if ( !self.forward404Unless(condition, req, res) ) { // forward to 404 if bad route
|
|
1710
|
+
|
|
1711
|
+
var isProxyHost = ( typeof(local.req.headers.host) != 'undefined' && local.options.conf.server.scheme +'://'+ local.req.headers.host != local.options.conf.hostname || typeof(local.req.headers[':authority']) != 'undefined' && local.options.conf.server.scheme +'://'+ local.req.headers[':authority'] != local.options.conf.hostname ) ? true : false;
|
|
1712
|
+
var hostname = (isProxyHost) ? ctx.config.envConf[bundle][env].hostname.replace(/\:\d+$/, '') : ctx.config.envConf[bundle][env].hostname;
|
|
1713
|
+
|
|
1714
|
+
// if ( !/\:\d+$/.test(req.headers.host) )
|
|
1715
|
+
// hostname = hostname.replace(/\:\d+$/, '');
|
|
1716
|
+
|
|
1717
|
+
if (route) { // will go with route first
|
|
1718
|
+
|
|
1719
|
+
if ( /\,/.test(routing[route].url) ) {
|
|
1720
|
+
var paths = routing[route].url.split(/\,/g);
|
|
1721
|
+
path = (ignoreWebRoot) ? paths[0].replace(wroot, '') : paths[0];
|
|
1722
|
+
} else {
|
|
1723
|
+
path = (ignoreWebRoot) ? routing[route].url.replace(wroot, '') : routing[route].url;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
if (bundle != conf.bundle) {
|
|
1727
|
+
path = hostname + path;
|
|
1728
|
+
}
|
|
1729
|
+
} else if (url && !path) {
|
|
1730
|
+
path = ( (/\:\/\//).test(url) ) ? url : req.scheme + '://' + url;
|
|
1731
|
+
|
|
1732
|
+
if (/\@/.test(path)) {
|
|
1733
|
+
path = lib.routing.getRoute(path).toUrl(ignoreWebRoot);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
//} else if(path && typeof(isRelative) != 'undefined') {
|
|
1737
|
+
// nothing to do, just ignoring
|
|
1738
|
+
//} else {
|
|
1739
|
+
} else if ( !path && typeof(isRelative) == 'undefined' ) {
|
|
1740
|
+
|
|
1741
|
+
path = hostname + path
|
|
1742
|
+
//path = local.req.headers.host + path
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
if (!local.res.headersSent) {
|
|
1748
|
+
|
|
1749
|
+
// backing up oldParams
|
|
1750
|
+
var oldParams = local.req[originalMethod.toLowerCase()];
|
|
1751
|
+
var requestParams = req[req.method.toLowerCase()] || {};
|
|
1752
|
+
if ( typeof(requestParams) != 'undefined' && typeof(requestParams.error) != 'undefined' ) {
|
|
1753
|
+
var redirectError = requestParams.error;
|
|
1754
|
+
self.throwError(requestParams.error);
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
if (
|
|
1759
|
+
!/GET/i.test(req.method)
|
|
1760
|
+
||
|
|
1761
|
+
originalMethod && !/GET/i.test(originalMethod)
|
|
1762
|
+
) { // trying to redirect using the wrong method ?
|
|
1763
|
+
|
|
1764
|
+
console.warn(new Error('Your are trying to redirect using the wrong method: `'+ req.method+'`.\nThis can often occur while redirecting from a controller to another controller or from a bundle to another.\nA redirection is not permitted in this scenario.\nD\'ont panic :)\nSwitching request method to `GET` method instead.\n').message);
|
|
1765
|
+
method = local.req.method = self.setRequestMethod('GET', conf);
|
|
1766
|
+
code = 303;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
// merging new & olds params
|
|
1771
|
+
requestParams = merge(requestParams, oldParams);
|
|
1772
|
+
// remove session to prevent reaching the 2000 chars limit
|
|
1773
|
+
// if you need the session, you need to find another way to retrieve while in the next route
|
|
1774
|
+
if ( typeof(requestParams.session) != 'undefined' ) {
|
|
1775
|
+
delete requestParams.session;
|
|
1776
|
+
}
|
|
1777
|
+
if ( typeof(requestParams) != 'undefined' && requestParams.count() > 0 ) {
|
|
1778
|
+
//if ( typeof(requestParams.error) != 'undefined' )
|
|
1779
|
+
|
|
1780
|
+
var inheritedData = null;
|
|
1781
|
+
if ( /\?/.test(path) ) {
|
|
1782
|
+
inheritedData = '&inheritedData='+ encodeURIComponent(JSON.stringify(requestParams));
|
|
1783
|
+
} else {
|
|
1784
|
+
inheritedData = '?inheritedData='+ encodeURIComponent(JSON.stringify(requestParams));
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
if ( inheritedData.length > 2000 ) {
|
|
1788
|
+
var error = new ApiError('Controller::redirect(...) exceptions: `inheritedData` reached 2000 chars limit', 424);
|
|
1789
|
+
self.throwError(error);
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// if redirecting from a xhrRequest
|
|
1794
|
+
if ( self.isXMLRequest() ) {
|
|
1795
|
+
// `requestParams` should be stored in the session to avoid passing datas in clear
|
|
1796
|
+
var redirectObj = { location: path, isXhrRedirect: true };
|
|
1797
|
+
if (requestParams.count() > 0) {
|
|
1798
|
+
var userSession = req.session.user || req.session;
|
|
1799
|
+
if ( userSession && local.haltedRequestUrlResumed ) {
|
|
1800
|
+
// will be reused for server.js on `case : 'GET'`
|
|
1801
|
+
userSession.inheritedData = requestParams;
|
|
1802
|
+
} else { // will be passed in clear
|
|
1803
|
+
redirectObj.location += inheritedData;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
self.renderJSON(redirectObj);
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
path += inheritedData;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
var ext = 'html';
|
|
1815
|
+
res.setHeader('content-type', local.options.conf.server.coreConfiguration.mime[ext]);
|
|
1816
|
+
|
|
1817
|
+
if (
|
|
1818
|
+
typeof(local.res._headers) != 'undefined'
|
|
1819
|
+
&& typeof(local.res._headers['access-control-allow-methods']) != 'undefined'
|
|
1820
|
+
&& local.res._headers['access-control-allow-methods'] != req.method
|
|
1821
|
+
||
|
|
1822
|
+
!new RegExp(req.method, 'i').test( res.getHeader('access-control-allow-methods') )
|
|
1823
|
+
) {
|
|
1824
|
+
res.setHeader('access-control-allow-methods', req.method.toUpperCase() );
|
|
1825
|
+
}
|
|
1826
|
+
//path += '?query='+ JSON.stringify(self.getRequestMethodParams());
|
|
1827
|
+
local.req[req.method.toLowerCase()] = self.getRequestMethodParams() || {};
|
|
1828
|
+
|
|
1829
|
+
var headInfos = {
|
|
1830
|
+
'location': path
|
|
1831
|
+
};
|
|
1832
|
+
|
|
1833
|
+
if (self.isCacheless()) {
|
|
1834
|
+
res.writeHead(code, merge(headInfos, {
|
|
1835
|
+
'cache-control': 'no-cache, no-store, must-revalidate', // preventing browsers from using cache
|
|
1836
|
+
'pragma': 'no-cache',
|
|
1837
|
+
'expires': '0'
|
|
1838
|
+
}))
|
|
1839
|
+
} else {
|
|
1840
|
+
res.writeHead(code, headInfos)
|
|
1841
|
+
}
|
|
1842
|
+
// in case of query from another bundle waiting for a response
|
|
1843
|
+
var redirectObject = JSON.stringify({ status: code, headers: headInfos });
|
|
1844
|
+
res.end(redirectObject);
|
|
1845
|
+
try {
|
|
1846
|
+
local.res.headersSent = true;// done for the render() method
|
|
1847
|
+
} catch(err){
|
|
1848
|
+
// ignoring the warning
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
console.info(local.req.method.toUpperCase() +' ['+code+'] '+ path);
|
|
1852
|
+
|
|
1853
|
+
if ( typeof(next) != 'undefined' )
|
|
1854
|
+
next();
|
|
1855
|
+
else
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* Move files to assets dir
|
|
1864
|
+
*
|
|
1865
|
+
* @param {object} res
|
|
1866
|
+
* @param {collection} files
|
|
1867
|
+
*
|
|
1868
|
+
* @callback cb
|
|
1869
|
+
* @param {object} [err]
|
|
1870
|
+
* */
|
|
1871
|
+
var movefiles = function (i, res, files, cb) {
|
|
1872
|
+
if (!files.length || files.length == 0) {
|
|
1873
|
+
cb(false)
|
|
1874
|
+
} else {
|
|
1875
|
+
if ( fs.existsSync(files[i].target) ) new _(files[i].target).rmSync();
|
|
1876
|
+
|
|
1877
|
+
var sourceStream = fs.createReadStream(files[i].source);
|
|
1878
|
+
var destinationStream = fs.createWriteStream(files[i].target);
|
|
1879
|
+
|
|
1880
|
+
sourceStream
|
|
1881
|
+
.pipe(destinationStream)
|
|
1882
|
+
.on('error', function () {
|
|
1883
|
+
var err = 'Error on SuperController::copyFile(...): Not found ' + files[i].source + ' or ' + files[i].target;
|
|
1884
|
+
cb(err)
|
|
1885
|
+
})
|
|
1886
|
+
.on('close', function () {
|
|
1887
|
+
|
|
1888
|
+
try {
|
|
1889
|
+
fs.unlinkSync(files[i].source);
|
|
1890
|
+
files.splice(i, 1);
|
|
1891
|
+
} catch (err) {
|
|
1892
|
+
cb(err)
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
movefiles(i, res, files, cb)
|
|
1896
|
+
})
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
this.getBundleStatus = function(req, res, next) {
|
|
1901
|
+
self.renderJSON({
|
|
1902
|
+
status: 200,
|
|
1903
|
+
isAlive: true,
|
|
1904
|
+
message: 'I am alive !'
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
this.checkBundleStatus = async function(bundle, cb) {
|
|
1909
|
+
var opt = self.getConfig('app').proxy[bundle];
|
|
1910
|
+
var route = lib.routing.getRoute('bundle-status@'+bundle);
|
|
1911
|
+
opt.method = 'GET';
|
|
1912
|
+
opt.path = route.url;
|
|
1913
|
+
var response = { isAlive: false }, error = false;
|
|
1914
|
+
await util.promisify(self.query)(opt, {})
|
|
1915
|
+
.then( function onQueryResponse(_status) {
|
|
1916
|
+
response = _status
|
|
1917
|
+
});
|
|
1918
|
+
|
|
1919
|
+
if (cb) {
|
|
1920
|
+
cb(error, response);
|
|
1921
|
+
} else {
|
|
1922
|
+
return response;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* downloadFromURL
|
|
1928
|
+
* Download from an URL
|
|
1929
|
+
* - attachment/inline
|
|
1930
|
+
* OR
|
|
1931
|
+
* - locally: `Controller.store(target, cb)` must be called to store on `onComplete` event
|
|
1932
|
+
*
|
|
1933
|
+
* @param {string} url - eg.: https://upload.wikimedia.org/wikipedia/fr/2/2f/Firefox_Old_Logo.png
|
|
1934
|
+
* @param {object} [options]
|
|
1935
|
+
*
|
|
1936
|
+
*
|
|
1937
|
+
* */
|
|
1938
|
+
this.downloadFromURL = function(url, options) {
|
|
1939
|
+
|
|
1940
|
+
var defaultOptions = {
|
|
1941
|
+
// file name i you want to rename the file
|
|
1942
|
+
file: null,
|
|
1943
|
+
fileSize: null,
|
|
1944
|
+
// only if you want to store locally the downloaded file
|
|
1945
|
+
toLocalDir: false, // this option will disable attachment download
|
|
1946
|
+
// content-disposition (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
|
|
1947
|
+
contentDisposition: 'attachment',
|
|
1948
|
+
// content-type (https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Configuring_server_MIME_types)
|
|
1949
|
+
contentType: 'application/octet-stream',
|
|
1950
|
+
|
|
1951
|
+
agent: false,
|
|
1952
|
+
// set to false to ignore certificate verification
|
|
1953
|
+
rejectUnauthorized: true,
|
|
1954
|
+
//responseType: 'blob',
|
|
1955
|
+
port: 80,
|
|
1956
|
+
method: 'GET',
|
|
1957
|
+
keepAlive: true,
|
|
1958
|
+
headers: {}
|
|
1959
|
+
};
|
|
1960
|
+
|
|
1961
|
+
var opt = ( typeof(options) != 'undefined' ) ? merge(options, defaultOptions) : defaultOptions;
|
|
1962
|
+
|
|
1963
|
+
var requestOptions = {};
|
|
1964
|
+
for (var o in opt) {
|
|
1965
|
+
if ( !/(toLocalDir|contentDisposition|contentType|file)/.test(o) )
|
|
1966
|
+
requestOptions[o] = opt[o];
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
// defining protocol & scheme
|
|
1970
|
+
var protocol = null;
|
|
1971
|
+
var scheme = null;
|
|
1972
|
+
|
|
1973
|
+
if ( /\:\/\//.test(url) ) {
|
|
1974
|
+
scheme = url.match(/^\w+\:/)[0];
|
|
1975
|
+
scheme = scheme.substr(0, scheme.length-1);
|
|
1976
|
+
|
|
1977
|
+
if ( !/^http/.test(scheme) ) {
|
|
1978
|
+
self.throwError(local.res, 500, new Error('[ '+ scheme +' ] Scheme not supported. Ref.: `http` or `https` only'));
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
|
|
1983
|
+
|
|
1984
|
+
} else { // by default
|
|
1985
|
+
scheme = 'http';
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
requestOptions.scheme = scheme +':';
|
|
1989
|
+
|
|
1990
|
+
//defining port
|
|
1991
|
+
var port = url.match(/\:\d+\//) || null;
|
|
1992
|
+
if ( port != null ) {
|
|
1993
|
+
port = port[0].substr(1, port[0].length-2);
|
|
1994
|
+
requestOptions.port = ~~port;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// defining hostname & path
|
|
1998
|
+
var parts = url.replace(new RegExp( scheme + '\:\/\/'), '').split(/\//g);
|
|
1999
|
+
requestOptions.host = parts[0].replace(/\:\d+/, '');
|
|
2000
|
+
requestOptions.path = '/' + parts.splice(1).join('/');
|
|
2001
|
+
|
|
2002
|
+
|
|
2003
|
+
// extension and mime
|
|
2004
|
+
var filename = url.split(/\//g).pop();
|
|
2005
|
+
if (!filename) {
|
|
2006
|
+
self.throwError(local.res, 500, new Error('Filename not found in url: `'+ url +'`'));
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
|
|
2011
|
+
if ( !/\.\w+$/.test(filename) ) {
|
|
2012
|
+
self.throwError(local.res, 500, new Error('[ '+ filename +' ] extension not found.'));
|
|
2013
|
+
return;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
|
|
2017
|
+
// filename renaming
|
|
2018
|
+
if (opt.file)
|
|
2019
|
+
filename = opt.file;
|
|
2020
|
+
|
|
2021
|
+
if ( opt.contentDisposition == 'attachment') {
|
|
2022
|
+
opt.contentDisposition += '; filename=' + filename;
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
var ext = filename.match(/\.\w+$/)[0].substr(1)
|
|
2026
|
+
, contentType = null
|
|
2027
|
+
, tmp = _(GINA_TMPDIR +'/'+ filename, true)
|
|
2028
|
+
;
|
|
2029
|
+
|
|
2030
|
+
if ( typeof(local.options.conf.server.coreConfiguration.mime[ext]) != 'undefined' ) {
|
|
2031
|
+
|
|
2032
|
+
contentType = (opt.contentType != defaultOptions.contentType) ? opt.contentType : local.options.conf.server.coreConfiguration.mime[ext];
|
|
2033
|
+
|
|
2034
|
+
} else { // extension not supported
|
|
2035
|
+
self.throwError(local.res, 500, new Error('[ '+ ext +' ] Extension not supported. Ref.: gina/core mime.types'));
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// defining responseType
|
|
2040
|
+
requestOptions.headers['content-type'] = contentType;
|
|
2041
|
+
requestOptions.headers['content-disposition'] = opt.contentDisposition;
|
|
2042
|
+
|
|
2043
|
+
var browser = require(''+ scheme);
|
|
2044
|
+
//console.debug('requestOptions: \n', JSON.stringify(requestOptions, null, 4));
|
|
2045
|
+
|
|
2046
|
+
browser.get(requestOptions, function(response) {
|
|
2047
|
+
|
|
2048
|
+
local.res.setHeader('content-type', contentType + '; charset='+ local.options.conf.encoding);
|
|
2049
|
+
local.res.setHeader('content-disposition', opt.contentDisposition);
|
|
2050
|
+
if (opt.fileSize) {
|
|
2051
|
+
local.res.setHeader('content-length', opt.fileSize);
|
|
2052
|
+
}
|
|
2053
|
+
//local.res.setHeader('content-length', opt.fileSize);
|
|
2054
|
+
// local.res.setHeader('cache-control', 'must-revalidate');
|
|
2055
|
+
// local.res.setHeader('pragma', 'must-revalidate');
|
|
2056
|
+
|
|
2057
|
+
// response.on('end', function onResponsePipeEnd(){
|
|
2058
|
+
// self.renderJSON({ url: url});
|
|
2059
|
+
// //local.res.end( Buffer.from(data) );
|
|
2060
|
+
// //local.res.headersSent = true;
|
|
2061
|
+
|
|
2062
|
+
// // if ( typeof(local.next) != 'undefined')
|
|
2063
|
+
// // local.next();
|
|
2064
|
+
// // else
|
|
2065
|
+
// // return;
|
|
2066
|
+
// });
|
|
2067
|
+
|
|
2068
|
+
response.pipe(local.res);
|
|
2069
|
+
});
|
|
2070
|
+
|
|
2071
|
+
return;
|
|
2072
|
+
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
|
|
2076
|
+
/**
|
|
2077
|
+
* Download to targeted filename.ext - Will create target if new
|
|
2078
|
+
* Use `cb` callback or `onComplete` event
|
|
2079
|
+
*
|
|
2080
|
+
* @param {string} filename
|
|
2081
|
+
* @param {object} options
|
|
2082
|
+
**/
|
|
2083
|
+
this.downloadFromLocal = function(filename) {
|
|
2084
|
+
|
|
2085
|
+
var file = filename.split(/\//g).pop();
|
|
2086
|
+
var ext = file.split(/\./g).pop()
|
|
2087
|
+
, contentType = null
|
|
2088
|
+
;
|
|
2089
|
+
|
|
2090
|
+
if ( typeof(local.options.conf.server.coreConfiguration.mime[ext]) != 'undefined' ) {
|
|
2091
|
+
|
|
2092
|
+
contentType = local.options.conf.server.coreConfiguration.mime[ext];
|
|
2093
|
+
local.res.setHeader('content-type', contentType);
|
|
2094
|
+
local.res.setHeader('content-disposition', 'attachment; filename=' + file);
|
|
2095
|
+
|
|
2096
|
+
var filestream = fs.createReadStream(filename);
|
|
2097
|
+
filestream.pipe(local.res);
|
|
2098
|
+
|
|
2099
|
+
} else { // extension not supported
|
|
2100
|
+
self.throwError(local.res, 500, new Error('[ '+ ext +' ] Extension not supported. Ref.: gina/core mime.types'));
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
|
|
2106
|
+
/**
|
|
2107
|
+
* Store file(s) to a targeted directory - Will create target if new
|
|
2108
|
+
* You only need to provide the destination path
|
|
2109
|
+
* Use `cb` callback or `onComplete` event
|
|
2110
|
+
*
|
|
2111
|
+
* @param {string} target is the upload dir destination
|
|
2112
|
+
* @param {array} [files]
|
|
2113
|
+
*
|
|
2114
|
+
* @callback [cb]
|
|
2115
|
+
* @param {object} error
|
|
2116
|
+
* @param {array} files
|
|
2117
|
+
*
|
|
2118
|
+
* @event
|
|
2119
|
+
* @param {object} error
|
|
2120
|
+
* @param {array} files
|
|
2121
|
+
*
|
|
2122
|
+
* */
|
|
2123
|
+
this.store = async function(target, files, cb) {
|
|
2124
|
+
|
|
2125
|
+
|
|
2126
|
+
var start = function(target, files, cb) {
|
|
2127
|
+
|
|
2128
|
+
if (arguments.length == 2 && typeof(arguments[1]) == 'function' ) {
|
|
2129
|
+
var cb = arguments[1];
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
if ( typeof(files) == 'undefined' || typeof(files) == 'function' ) {
|
|
2133
|
+
files = local.req.files
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
var uploadedFiles = [];
|
|
2137
|
+
|
|
2138
|
+
if ( typeof(files) == 'undefined' || files.count() == 0 ) {
|
|
2139
|
+
if (cb) {
|
|
2140
|
+
cb(new Error('No file to upload'))
|
|
2141
|
+
} else {
|
|
2142
|
+
self.emit('uploaded', new Error('No file to upload'))
|
|
2143
|
+
}
|
|
2144
|
+
} else {
|
|
2145
|
+
// saving files
|
|
2146
|
+
var uploadDir = new _(target)
|
|
2147
|
+
, list = []
|
|
2148
|
+
, i = 0
|
|
2149
|
+
, folder = uploadDir.mkdirSync();
|
|
2150
|
+
|
|
2151
|
+
if (folder instanceof Error) {
|
|
2152
|
+
if (cb) {
|
|
2153
|
+
cb(folder)
|
|
2154
|
+
} else {
|
|
2155
|
+
self.emit('uploaded', folder)
|
|
2156
|
+
}
|
|
2157
|
+
} else {
|
|
2158
|
+
// files list
|
|
2159
|
+
var fileName = null;
|
|
2160
|
+
for (var len = files.length; i < len; ++i ){
|
|
2161
|
+
|
|
2162
|
+
fileName = files[i].filename || files[i].originalFilename
|
|
2163
|
+
|
|
2164
|
+
list[i] = {
|
|
2165
|
+
source: files[i].path,
|
|
2166
|
+
target: _(uploadDir.toString() + '/' + fileName)
|
|
2167
|
+
};
|
|
2168
|
+
|
|
2169
|
+
uploadedFiles[i] = {
|
|
2170
|
+
file : fileName,
|
|
2171
|
+
filename : list[i].target,
|
|
2172
|
+
size : files[i].size,
|
|
2173
|
+
type : files[i].type,
|
|
2174
|
+
encoding : files[i].encoding
|
|
2175
|
+
};
|
|
2176
|
+
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
movefiles(0, local.res, list, function (err) {
|
|
2180
|
+
if (err) {
|
|
2181
|
+
if (cb) {
|
|
2182
|
+
cb(new Error('No file to upload'))
|
|
2183
|
+
} else {
|
|
2184
|
+
self.emit('uploaded', new Error('No file to upload'))
|
|
2185
|
+
}
|
|
2186
|
+
} else {
|
|
2187
|
+
if (cb) {
|
|
2188
|
+
cb(false, uploadedFiles)
|
|
2189
|
+
} else {
|
|
2190
|
+
self.emit('uploaded', false, uploadedFiles)
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
})
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
if ( typeof(cb) == 'undefined' ) {
|
|
2199
|
+
|
|
2200
|
+
return {
|
|
2201
|
+
onComplete : function(cb){
|
|
2202
|
+
self.on('uploaded', cb);
|
|
2203
|
+
start(target, files)
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
} else {
|
|
2207
|
+
start(target, files, cb)
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
|
|
2212
|
+
/**
|
|
2213
|
+
* Query
|
|
2214
|
+
*
|
|
2215
|
+
* Allows you to act as a proxy between your frontend and a 1/3 API
|
|
2216
|
+
* */
|
|
2217
|
+
function sha256(s) {
|
|
2218
|
+
return crypto.createHash('sha256').update(s).digest('base64');
|
|
2219
|
+
}
|
|
2220
|
+
local.query.data = {};
|
|
2221
|
+
local.query.options = {
|
|
2222
|
+
host : undefined, // Must be an IP
|
|
2223
|
+
hostname : undefined, // cname of the host e.g.: `www.google.com` or `localhost`
|
|
2224
|
+
path : undefined, // e.g.: /test.html
|
|
2225
|
+
port : 80, // #80 by default but can be 3000 or <bundle>@<project>/<environment>
|
|
2226
|
+
method : 'GET', // POST | GET | PUT | DELETE
|
|
2227
|
+
keepAlive: true,
|
|
2228
|
+
auth: undefined, // use `"username:password"` for basic authentification
|
|
2229
|
+
|
|
2230
|
+
// set to false to ignore certificate verification when requesting on https (443)
|
|
2231
|
+
// same as process.env.NODE_TLS_REJECT_UNAUTHORIZED = "1";
|
|
2232
|
+
rejectUnauthorized: true,
|
|
2233
|
+
|
|
2234
|
+
headers: {
|
|
2235
|
+
'content-type': 'application/json',
|
|
2236
|
+
'content-length': local.query.data.length
|
|
2237
|
+
},
|
|
2238
|
+
agent : false/**,
|
|
2239
|
+
checkServerIdentity: function(host, cert) {
|
|
2240
|
+
// Make sure the certificate is issued to the host we are connected to
|
|
2241
|
+
const err = tls.checkServerIdentity(host, cert);
|
|
2242
|
+
if (err) {
|
|
2243
|
+
return err;
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
// Pin the public key, similar to HPKP pin-sha25 pinning
|
|
2247
|
+
const pubkey256 = 'pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=';
|
|
2248
|
+
if (sha256(cert.pubkey) !== pubkey256) {
|
|
2249
|
+
const msg = 'Certificate verification error: ' +
|
|
2250
|
+
`The public key of '${cert.subject.CN}' ` +
|
|
2251
|
+
'does not match our pinned fingerprint';
|
|
2252
|
+
return new Error(msg);
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
// Pin the exact certificate, rather then the pub key
|
|
2256
|
+
const cert256 = '25:FE:39:32:D9:63:8C:8A:FC:A1:9A:29:87:' +
|
|
2257
|
+
'D8:3E:4C:1D:98:DB:71:E4:1A:48:03:98:EA:22:6A:BD:8B:93:16';
|
|
2258
|
+
if (cert.fingerprint256 !== cert256) {
|
|
2259
|
+
const msg = 'Certificate verification error: ' +
|
|
2260
|
+
`The certificate of '${cert.subject.CN}' ` +
|
|
2261
|
+
'does not match our pinned fingerprint';
|
|
2262
|
+
return new Error(msg);
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
// This loop is informational only.
|
|
2266
|
+
// Print the certificate and public key fingerprints of all certs in the
|
|
2267
|
+
// chain. Its common to pin the public key of the issuer on the public
|
|
2268
|
+
// internet, while pinning the public key of the service in sensitive
|
|
2269
|
+
// environments.
|
|
2270
|
+
do {
|
|
2271
|
+
console.debug('Subject Common Name:', cert.subject.CN);
|
|
2272
|
+
console.debug(' Certificate SHA256 fingerprint:', cert.fingerprint256);
|
|
2273
|
+
|
|
2274
|
+
hash = crypto.createHash('sha256');
|
|
2275
|
+
console.debug(' Public key ping-sha256:', sha256(cert.pubkey));
|
|
2276
|
+
|
|
2277
|
+
lastprint256 = cert.fingerprint256;
|
|
2278
|
+
cert = cert.issuerCertificate;
|
|
2279
|
+
} while (cert.fingerprint256 !== lastprint256);
|
|
2280
|
+
|
|
2281
|
+
}*/
|
|
2282
|
+
|
|
2283
|
+
};
|
|
2284
|
+
|
|
2285
|
+
this.query = function() { // options, data, callback
|
|
2286
|
+
var err = null;
|
|
2287
|
+
var options = arguments[0];
|
|
2288
|
+
var data = arguments[1] || {};
|
|
2289
|
+
var callback = null;
|
|
2290
|
+
if ( typeof(arguments[arguments.length-1]) == 'function' ) {
|
|
2291
|
+
callback = arguments[arguments.length-1];
|
|
2292
|
+
} else {
|
|
2293
|
+
data = arguments[arguments.length-1]
|
|
2294
|
+
}
|
|
2295
|
+
// preventing multiple call of self.query() when controller is rendering from another required controller
|
|
2296
|
+
if (
|
|
2297
|
+
typeof(local.options) != 'undefined'
|
|
2298
|
+
&& typeof(local.options.renderingStack) != 'undefined'
|
|
2299
|
+
&& local.options.renderingStack.length > 1
|
|
2300
|
+
) {
|
|
2301
|
+
return false
|
|
2302
|
+
}
|
|
2303
|
+
self.isProcessingError = false; // by default
|
|
2304
|
+
|
|
2305
|
+
var queryData = {}
|
|
2306
|
+
, defaultOptions = local.query.options
|
|
2307
|
+
, path = options.path
|
|
2308
|
+
, browser = null
|
|
2309
|
+
;
|
|
2310
|
+
|
|
2311
|
+
// options must be used as a copy in case of multiple calls of self.query(options, ...)
|
|
2312
|
+
options = merge(JSON.clone(options), defaultOptions);
|
|
2313
|
+
|
|
2314
|
+
for (var o in options) {//cleaning
|
|
2315
|
+
if ( typeof(options[o]) == 'undefined' || options[o] == undefined) {
|
|
2316
|
+
delete options[o]
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
if (self.isCacheless() || self.isLocalScope() ) {
|
|
2321
|
+
options.rejectUnauthorized = false;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
if ( !options.host && !options.hostname ) {
|
|
2325
|
+
err = new Error('SuperController::query() needs at least a `host IP` or a `hostname`');
|
|
2326
|
+
if (callback) {
|
|
2327
|
+
return callback(err)
|
|
2328
|
+
}
|
|
2329
|
+
self.emit('query#complete', err)
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
|
|
2333
|
+
|
|
2334
|
+
// if (arguments.length <3) {
|
|
2335
|
+
// if ( typeof(data) == 'function') {
|
|
2336
|
+
// var callback = data;
|
|
2337
|
+
// var data = undefined;
|
|
2338
|
+
// } else {
|
|
2339
|
+
// callback = undefined;
|
|
2340
|
+
// }
|
|
2341
|
+
// }
|
|
2342
|
+
if ( typeof(data) != 'undefined' && data.count() > 0) {
|
|
2343
|
+
|
|
2344
|
+
queryData = '?';
|
|
2345
|
+
// TODO - if 'application/json' && method == (put|post)
|
|
2346
|
+
if ( ['put', 'post'].indexOf(options.method.toLowerCase()) >-1 && /(text\/plain|application\/json|application\/x\-www\-form)/i.test(options.headers['content-type']) ) {
|
|
2347
|
+
// replacing
|
|
2348
|
+
queryData = encodeURIComponent(JSON.stringify(data))
|
|
2349
|
+
//queryData = JSON.stringify(data)
|
|
2350
|
+
|
|
2351
|
+
} else {
|
|
2352
|
+
//Sample request.
|
|
2353
|
+
//options.path = '/updater/start?release={"version":"0.0.5-dev","url":"http://10.1.0.1:8080/project/bundle/repository/archive?ref=0.0.5-dev","date":1383669077141}&pid=46493';
|
|
2354
|
+
// do not alter the orignal data
|
|
2355
|
+
var tmpData = JSON.clone(data);
|
|
2356
|
+
for (let d in tmpData) {
|
|
2357
|
+
if ( typeof(tmpData[d]) == 'object') {
|
|
2358
|
+
tmpData[d] = JSON.stringify(tmpData[d]);
|
|
2359
|
+
}
|
|
2360
|
+
queryData += d + '=' + encodeURIComponent(tmpData[d]) + '&';
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
queryData = queryData.substring(0, queryData.length-1);
|
|
2364
|
+
queryData = queryData.replace(/\s/g, '%20');
|
|
2365
|
+
|
|
2366
|
+
options.path += queryData;
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
} else {
|
|
2370
|
+
queryData = ''
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
|
|
2374
|
+
// Internet Explorer override
|
|
2375
|
+
if ( local.req != null && /msie/i.test(local.req.headers['user-agent']) ) {
|
|
2376
|
+
options.headers['content-type'] = 'text/plain';
|
|
2377
|
+
} else {
|
|
2378
|
+
options.headers['content-type'] = local.options.conf.server.coreConfiguration.mime['json'];
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
// if ( typeof(local.req.headers.cookie) == 'undefined' && typeof(local.res._headers['set-cookie']) != 'undefined' ) { // useful for CORS : forward cookies from the original request
|
|
2382
|
+
// //options.headers.cookie = local.req.headers.cookie;
|
|
2383
|
+
// var originalResponseCookies = local.res._headers['set-cookie'];
|
|
2384
|
+
// options.headers.cookie = [];
|
|
2385
|
+
// for (var c = 0, cLen = originalResponseCookies.length; c < cLen; ++c) {
|
|
2386
|
+
// options.headers.cookie.push(originalResponseCookies[c])
|
|
2387
|
+
// }
|
|
2388
|
+
// }
|
|
2389
|
+
|
|
2390
|
+
//you need this, even when empty.
|
|
2391
|
+
options.headers['content-length'] = queryData.length;
|
|
2392
|
+
|
|
2393
|
+
// adding gina headers
|
|
2394
|
+
if ( local.req != null && typeof(local.req.ginaHeaders) != 'undefined' ) {
|
|
2395
|
+
// gina form headers
|
|
2396
|
+
for (let h in local.req.ginaHeaders.form) {
|
|
2397
|
+
let k = h.substr(0,1).toUpperCase() + h.substr(1);
|
|
2398
|
+
options.headers['X-Gina-Form-' + k ] = local.req.ginaHeaders.form[h];
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
var ctx = getContext()
|
|
2403
|
+
, protocol = null
|
|
2404
|
+
, scheme = null
|
|
2405
|
+
;
|
|
2406
|
+
// cleanup options.path
|
|
2407
|
+
if (/\:\/\//.test(options.path)) {
|
|
2408
|
+
|
|
2409
|
+
var hArr = options.path.split(/^(https|http)\:\/\//);
|
|
2410
|
+
var domain = hArr[1] +'://';
|
|
2411
|
+
var host = hArr[2].split(/\//)[0];
|
|
2412
|
+
var port = parseInt(host.split(/\:/)[1] || 80);
|
|
2413
|
+
|
|
2414
|
+
options.port = port;
|
|
2415
|
+
options.host = domain + host.replace(':'+port, '');
|
|
2416
|
+
options.path = options.path
|
|
2417
|
+
.replace(options.host, '')
|
|
2418
|
+
.replace(':'+port, '');
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// retrieve protocol & scheme: if empty, take the bundles protocol
|
|
2422
|
+
protocol = options.protocol || ctx.gina.config.envConf[ctx.bundle][ctx.env].server.protocol;// bundle servers's protocol by default
|
|
2423
|
+
protocol = protocol.match(/[.a-z 0-9]+/ig)[0];
|
|
2424
|
+
scheme = options.scheme || ctx.gina.config.envConf[ctx.bundle][ctx.env].server.scheme;// bundle servers's scheme by default
|
|
2425
|
+
scheme = scheme.match(/[a-z 0-9]+/ig)[0];
|
|
2426
|
+
|
|
2427
|
+
//retrieving dynamic host, hostname & port
|
|
2428
|
+
if ( /\@/.test(options.hostname) ) {
|
|
2429
|
+
|
|
2430
|
+
var bundle = ( options.hostname.replace(/(.*)\:\/\//, '') ).split(/\@/)[0];
|
|
2431
|
+
|
|
2432
|
+
// No shorcut possible because conf.hostname might differ from user inputs
|
|
2433
|
+
options.host = ctx.gina.config.envConf[bundle][ctx.env].host.replace(/(.*)\:\/\//, '').replace(/\:\d+/, '');
|
|
2434
|
+
options.hostname = ctx.gina.config.envConf[bundle][ctx.env].hostname;
|
|
2435
|
+
options.port = ctx.gina.config.envConf[bundle][ctx.env].server.port;
|
|
2436
|
+
|
|
2437
|
+
options.protocol = ctx.gina.config.envConf[bundle][ctx.env].server.protocol;
|
|
2438
|
+
options.scheme = ctx.gina.config.envConf[bundle][ctx.env].server.scheme;
|
|
2439
|
+
// might be != from the bundle requesting
|
|
2440
|
+
//options.protocol = ctx.gina.config.envConf[bundle][ctx.env].content.settings.server.protocol || ctx.gina.config.envConf[bundle][ctx.env].server.protocol;
|
|
2441
|
+
//options.scheme = ctx.gina.config.envConf[bundle][ctx.env].content.settings.server.scheme || ctx.gina.config.envConf[bundle][ctx.env].server.scheme;
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
if ( typeof(options.protocol) == 'undefined' ) {
|
|
2445
|
+
options.protocol = protocol
|
|
2446
|
+
}
|
|
2447
|
+
if ( typeof(options.scheme) == 'undefined' ) {
|
|
2448
|
+
options.scheme = scheme
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
|
|
2452
|
+
// reformating scheme
|
|
2453
|
+
if( !/\:$/.test(options.scheme) )
|
|
2454
|
+
options.scheme += ':';
|
|
2455
|
+
|
|
2456
|
+
try {
|
|
2457
|
+
options.queryData = queryData;
|
|
2458
|
+
var protocolVersion = ~~options.protocol.match(/\/(.*)$/)[1].replace(/\.\d+/, '');
|
|
2459
|
+
var httpLib = options.protocol.match(/^(.*)\//)[1] + ( (protocolVersion >= 2) ? protocolVersion : '' );
|
|
2460
|
+
if ( !/http2/.test(httpLib) && /https/.test(options.scheme) ) {
|
|
2461
|
+
httpLib += 's';
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
browser = require(''+ httpLib);
|
|
2465
|
+
|
|
2466
|
+
if ( /http2/.test(httpLib) ) {
|
|
2467
|
+
return handleHTTP2ClientRequest(browser, options, callback);
|
|
2468
|
+
} else {
|
|
2469
|
+
return handleHTTP1ClientRequest(browser, options, callback);
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
|
|
2473
|
+
} catch(err) {
|
|
2474
|
+
if (callback) {
|
|
2475
|
+
return callback(err)
|
|
2476
|
+
}
|
|
2477
|
+
self.emit('query#complete', err)
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
var handleHTTP1ClientRequest = function(browser, options, callback) {
|
|
2483
|
+
|
|
2484
|
+
var altOpt = JSON.clone(options);
|
|
2485
|
+
|
|
2486
|
+
altOpt.protocol = options.scheme;
|
|
2487
|
+
altOpt.hostname = options.host;
|
|
2488
|
+
altOpt.port = options.port;
|
|
2489
|
+
if ( typeof(altOpt.encKey) != 'undefined' ) {
|
|
2490
|
+
try {
|
|
2491
|
+
altOpt.encKey = fs.readFileSync(options.encKey);
|
|
2492
|
+
} catch(err) {
|
|
2493
|
+
self.emit('query#complete', err);
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
} else {
|
|
2497
|
+
console.warn('[ CONTROLLER ][ HTTP/1.0#query ] options.encKey not found !');
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
if ( typeof(altOpt.encCert) != 'undefined' ) {
|
|
2501
|
+
try {
|
|
2502
|
+
altOpt.encCert = fs.readFileSync(options.encCert);
|
|
2503
|
+
} catch(err) {
|
|
2504
|
+
self.emit('query#complete', err);
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
} else {
|
|
2508
|
+
console.warn('[ CONTROLLER ][ HTTP/1.0#query ] options.encCert not found !');
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
altOpt.agent = new browser.Agent(altOpt);
|
|
2512
|
+
|
|
2513
|
+
var req = browser.request(altOpt, function(res) {
|
|
2514
|
+
|
|
2515
|
+
res.setEncoding('utf8');
|
|
2516
|
+
|
|
2517
|
+
// upgrade response headers to handler
|
|
2518
|
+
if ( typeof(res.headers['access-control-allow-credentials']) != 'undefined' )
|
|
2519
|
+
local.options.withCredentials = res.headers['access-control-allow-credentials'];
|
|
2520
|
+
|
|
2521
|
+
|
|
2522
|
+
var data = '', err = false;
|
|
2523
|
+
|
|
2524
|
+
res.on('data', function onData (chunk) {
|
|
2525
|
+
data += chunk;
|
|
2526
|
+
});
|
|
2527
|
+
|
|
2528
|
+
res.on('end', function onEnd(err) {
|
|
2529
|
+
|
|
2530
|
+
|
|
2531
|
+
// exceptions filter
|
|
2532
|
+
if ( typeof(data) == 'string' && /^Unknown ALPN Protocol/.test(data) ) {
|
|
2533
|
+
err = {
|
|
2534
|
+
status: 500,
|
|
2535
|
+
error: new Error(data)
|
|
2536
|
+
};
|
|
2537
|
+
|
|
2538
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2539
|
+
callback(err)
|
|
2540
|
+
} else {
|
|
2541
|
+
self.emit('query#complete', err)
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
return
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
//Only when needed.
|
|
2548
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2549
|
+
if ( typeof(data) == 'string' && /^(\{|%7B|\[{)|\[\]/.test(data) ) {
|
|
2550
|
+
try {
|
|
2551
|
+
data = JSON.parse(data)
|
|
2552
|
+
} catch (err) {
|
|
2553
|
+
data = {
|
|
2554
|
+
status : 500,
|
|
2555
|
+
error : err
|
|
2556
|
+
};
|
|
2557
|
+
console.error(err);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
try {
|
|
2562
|
+
if ( data.status && !/^2/.test(data.status) && typeof(local.options.conf.server.coreConfiguration.statusCodes[data.status]) != 'undefined' ) {
|
|
2563
|
+
self.throwError(data);
|
|
2564
|
+
return;
|
|
2565
|
+
} else {
|
|
2566
|
+
callback( false, data );
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
2569
|
+
} catch (e) {
|
|
2570
|
+
var infos = local.options, controllerName = infos.controller.substr(infos.controller.lastIndexOf('/'));
|
|
2571
|
+
var msg = 'Controller Query Exception while catching back.\nBundle: '+ infos.bundle +'\nController File: /controllers'+ controllerName +'\nControl: this.'+ infos.control +'(...)\n\r' + e.stack;
|
|
2572
|
+
var exception = new Error(msg);
|
|
2573
|
+
exception.status = 500;
|
|
2574
|
+
self.throwError(exception);
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
} else {
|
|
2579
|
+
if ( typeof(data) == 'string' && /^(\{|%7B|\[{)|\[\]/.test(data) ) {
|
|
2580
|
+
try {
|
|
2581
|
+
data = JSON.parse(data)
|
|
2582
|
+
} catch (err) {
|
|
2583
|
+
data = {
|
|
2584
|
+
status : 500,
|
|
2585
|
+
error : data
|
|
2586
|
+
}
|
|
2587
|
+
self.emit('query#complete', data)
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
if ( data.status && !/^2/.test(data.status) && typeof(local.options.conf.server.coreConfiguration.statusCodes[data.status]) != 'undefined' ) {
|
|
2592
|
+
self.emit('query#complete', data)
|
|
2593
|
+
} else {
|
|
2594
|
+
self.emit('query#complete', false, data)
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
})
|
|
2598
|
+
});
|
|
2599
|
+
|
|
2600
|
+
|
|
2601
|
+
//starting from from >0.10.15
|
|
2602
|
+
req.on('error', function onError(err) {
|
|
2603
|
+
|
|
2604
|
+
|
|
2605
|
+
if (
|
|
2606
|
+
typeof(err.code) != 'undefined' && /ECONNREFUSED|ECONNRESET/.test(err.code)
|
|
2607
|
+
|| typeof(err.cause) != 'undefined' && typeof(err.cause.code) != 'undefined' && /ECONNREFUSED|ECONNRESET/.test(err.cause.code)
|
|
2608
|
+
) {
|
|
2609
|
+
|
|
2610
|
+
var port = getContext('gina').ports[options.protocol][options.scheme.replace(/\:/, '')][ options.port ];//err.port || err.cause.port
|
|
2611
|
+
if ( typeof(port) != 'undefined' ) {
|
|
2612
|
+
err.accessPoint = port;
|
|
2613
|
+
err.message = '`Controller::query()` could not connect to [ ' + err.accessPoint + ' ] using port '+options.port+'.\n';
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
|
|
2618
|
+
console.error(err.stack||err.message);
|
|
2619
|
+
// you can get here if :
|
|
2620
|
+
// - you are trying to query using: `enctype="multipart/form-data"`
|
|
2621
|
+
// -
|
|
2622
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2623
|
+
|
|
2624
|
+
callback(err)
|
|
2625
|
+
|
|
2626
|
+
} else {
|
|
2627
|
+
var error = {
|
|
2628
|
+
status : 500,
|
|
2629
|
+
error : err.stack || err.message
|
|
2630
|
+
};
|
|
2631
|
+
|
|
2632
|
+
self.emit('query#complete', error)
|
|
2633
|
+
}
|
|
2634
|
+
});
|
|
2635
|
+
|
|
2636
|
+
|
|
2637
|
+
if (req) { // don't touch this please
|
|
2638
|
+
if (req.write) req.write(options.queryData);
|
|
2639
|
+
if (req.end) req.end();
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
return {
|
|
2643
|
+
onComplete : function(cb) {
|
|
2644
|
+
self.once('query#complete', function(err, data){
|
|
2645
|
+
|
|
2646
|
+
if ( typeof(data) == 'string' && /^(\{|%7B|\[{)|\[\]/.test(data) ) {
|
|
2647
|
+
try {
|
|
2648
|
+
data = JSON.parse(data)
|
|
2649
|
+
} catch (err) {
|
|
2650
|
+
data = {
|
|
2651
|
+
status : 500,
|
|
2652
|
+
error : data
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
try {
|
|
2658
|
+
if ( data.status && !/^2/.test(data.status) && typeof(local.options.conf.server.coreConfiguration.statusCodes[data.status]) != 'undefined') {
|
|
2659
|
+
cb(data)
|
|
2660
|
+
} else {
|
|
2661
|
+
cb(err, data)
|
|
2662
|
+
}
|
|
2663
|
+
} catch (e) {
|
|
2664
|
+
var infos = local.options, controllerName = infos.controller.substr(infos.controller.lastIndexOf('/'));
|
|
2665
|
+
var msg = 'Controller Query Exception while catching back.\nBundle: '+ infos.bundle +'\nController File: /controllers'+ controllerName +'\nControl: this.'+ infos.control +'(...)\n\r' + e.stack;
|
|
2666
|
+
var exception = new Error(msg);
|
|
2667
|
+
exception.status = 500;
|
|
2668
|
+
self.throwError(exception);
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2671
|
+
})
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
var handleHTTP2ClientRequest = function(browser, options, callback) {
|
|
2678
|
+
|
|
2679
|
+
//cleanup
|
|
2680
|
+
options[':authority'] = options.hostname;
|
|
2681
|
+
|
|
2682
|
+
delete options.host;
|
|
2683
|
+
|
|
2684
|
+
if ( typeof(options[':path']) == 'undefined' ) {
|
|
2685
|
+
options[':path'] = options.path;
|
|
2686
|
+
delete options.path;
|
|
2687
|
+
}
|
|
2688
|
+
if ( typeof(options[':method']) == 'undefined' ) {
|
|
2689
|
+
options[':method'] = options.method.toUpperCase();
|
|
2690
|
+
delete options.method;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
// only if binary !!
|
|
2694
|
+
// if ( typeof(options['content-length']) == 'undefined' ) {
|
|
2695
|
+
// options['content-length'] = options.headers['content-length'] ;
|
|
2696
|
+
// delete options.headers['content-length'];
|
|
2697
|
+
// }
|
|
2698
|
+
// if ( typeof(options['content-type']) == 'undefined' ) {
|
|
2699
|
+
// options['content-type'] = options.headers['content-type'] ;
|
|
2700
|
+
// delete options.headers['content-type'];
|
|
2701
|
+
// }
|
|
2702
|
+
|
|
2703
|
+
if ( typeof(options[':scheme']) == 'undefined' ) {
|
|
2704
|
+
options[':scheme'] = options.scheme ;
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
if ( typeof(options.ca) != 'undefined' ) {
|
|
2708
|
+
try {
|
|
2709
|
+
options.ca = fs.readFileSync(options.ca);
|
|
2710
|
+
} catch(err) {
|
|
2711
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2712
|
+
callback(err)
|
|
2713
|
+
} else {
|
|
2714
|
+
self.emit('query#complete', err);
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
} else {
|
|
2721
|
+
console.warn('[ CONTROLLER ][ HTTP/2.0#query ] options.ca not found !');
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
|
|
2725
|
+
var body = Buffer.from(options.queryData);
|
|
2726
|
+
options.headers['content-length'] = body.length;
|
|
2727
|
+
delete options.queryData;
|
|
2728
|
+
|
|
2729
|
+
|
|
2730
|
+
|
|
2731
|
+
const client = browser.connect(options.hostname, options);
|
|
2732
|
+
|
|
2733
|
+
|
|
2734
|
+
const {
|
|
2735
|
+
HTTP2_HEADER_PROTOCOL,
|
|
2736
|
+
HTTP2_HEADER_SCHEME,
|
|
2737
|
+
HTTP2_HEADER_AUTHORITY,
|
|
2738
|
+
HTTP2_HEADER_PATH,
|
|
2739
|
+
HTTP2_HEADER_METHOD,
|
|
2740
|
+
HTTP2_HEADER_STATUS
|
|
2741
|
+
} = browser.constants;
|
|
2742
|
+
|
|
2743
|
+
|
|
2744
|
+
if ( typeof(local.req.headers['x-requested-with']) != 'undefined' ) {
|
|
2745
|
+
options.headers['x-requested-with'] = local.req.headers['x-requested-with']
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
if ( typeof(local.req.headers['access-control-allow-credentials']) != 'undefined' ) {
|
|
2749
|
+
options.headers['access-control-allow-credentials'] = local.req.headers['access-control-allow-credentials']
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
if ( typeof(local.req.headers['content-type']) != 'undefined' && local.req.headers['content-type'] != options.headers['content-type'] ) {
|
|
2753
|
+
options.headers['content-type'] = local.req.headers['content-type']
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
var headers = merge({
|
|
2757
|
+
[HTTP2_HEADER_METHOD]: options[':method'],
|
|
2758
|
+
[HTTP2_HEADER_PATH]: options[':path']
|
|
2759
|
+
}, options.headers);
|
|
2760
|
+
|
|
2761
|
+
// merging with user options
|
|
2762
|
+
for (var o in options) {
|
|
2763
|
+
if (!/^\:/.test(o) && !/headers/.test(o) && typeof(headers[o]) == 'undefined' ) {
|
|
2764
|
+
headers[o] = options[o]
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
/**
|
|
2769
|
+
* sessionOptions
|
|
2770
|
+
* endStream <boolean> true if the Http2Stream writable side should be closed initially, such as when sending a GET request that should not expect a payload body.
|
|
2771
|
+
* exclusive <boolean> When true and parent identifies a parent Stream, the created stream is made the sole direct dependency of the parent, with all other existing dependents made a dependent of the newly created stream. Default: false.
|
|
2772
|
+
* parent <number> Specifies the numeric identifier of a stream the newly created stream is dependent on.
|
|
2773
|
+
* weight <number> Specifies the relative dependency of a stream in relation to other streams with the same parent. The value is a number between 1 and 256 (inclusive).
|
|
2774
|
+
* waitForTrailers <boolean> When true, the Http2Stream will emit the 'wantTrailers' event after the final DATA frame has been sent.
|
|
2775
|
+
*/
|
|
2776
|
+
var sessionOptions = {}, endStream = true;
|
|
2777
|
+
if ( body.length > 0 || options.headers['x-requested-with'] ) {
|
|
2778
|
+
endStream = false;
|
|
2779
|
+
sessionOptions.endStream = endStream;
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
|
|
2783
|
+
client.on('error', (error) => {
|
|
2784
|
+
|
|
2785
|
+
console.error( '`'+ options[':path']+ '` : '+ error.stack||error.message);
|
|
2786
|
+
if (
|
|
2787
|
+
typeof(error.cause) != 'undefined' && typeof(error.cause.code) != 'undefined' && /ECONNREFUSED|ECONNRESET/.test(error.cause.code)
|
|
2788
|
+
|| /ECONNREFUSED|ECONNRESET/.test(error.code)
|
|
2789
|
+
) {
|
|
2790
|
+
|
|
2791
|
+
var port = getContext('gina').ports[options.protocol][options.scheme.replace(/\:/, '')][ options.port ];
|
|
2792
|
+
if ( typeof(port) != 'undefined' ) {
|
|
2793
|
+
error.accessPoint = port;
|
|
2794
|
+
error.message = 'Could not connect to [ ' + error.accessPoint + ' ].\nThe `'+port.split(/\@/)[0]+'` bundle is offline or unreachable.\n';
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
self.throwError(error);
|
|
2798
|
+
return;
|
|
2799
|
+
});
|
|
2800
|
+
|
|
2801
|
+
client.on('connect', () => {
|
|
2802
|
+
|
|
2803
|
+
var req = client.request( headers, sessionOptions );
|
|
2804
|
+
|
|
2805
|
+
|
|
2806
|
+
// req.on('response', function onQueryResponse(headers, flags) {
|
|
2807
|
+
// for (const name in headers) {
|
|
2808
|
+
// console.debug(`${name}: ${headers[name]}`);
|
|
2809
|
+
// }
|
|
2810
|
+
// });
|
|
2811
|
+
|
|
2812
|
+
req.setEncoding('utf8');
|
|
2813
|
+
var data = '';
|
|
2814
|
+
req.on('data', function onQueryDataChunk(chunk) {
|
|
2815
|
+
data += chunk;
|
|
2816
|
+
});
|
|
2817
|
+
|
|
2818
|
+
req.on('error', function onQueryError(error) {
|
|
2819
|
+
|
|
2820
|
+
if (
|
|
2821
|
+
typeof(error.cause) != 'undefined' && typeof(error.cause.code) != 'undefined' && /ECONNREFUSED|ECONNRESET/.test(error.cause.code)
|
|
2822
|
+
|| /ECONNREFUSED|ECONNRESET/.test(error.code)
|
|
2823
|
+
) {
|
|
2824
|
+
|
|
2825
|
+
var port = getContext('gina').ports[options.protocol][options.scheme.replace(/\:/, '')][ options.port ];
|
|
2826
|
+
if ( typeof(port) != 'undefined' ) {
|
|
2827
|
+
error.accessPoint = port;
|
|
2828
|
+
error.message = 'Could not connect to [ ' + error.accessPoint + ' ].\n' + error.message;
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
|
|
2833
|
+
console.error(error.stack||error.message);
|
|
2834
|
+
// you can get here if :
|
|
2835
|
+
// - you are trying to query using: `enctype="multipart/form-data"`
|
|
2836
|
+
// - server responded with an error
|
|
2837
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2838
|
+
callback(error);
|
|
2839
|
+
} else {
|
|
2840
|
+
error = {
|
|
2841
|
+
status : 500,
|
|
2842
|
+
error : error.stack ||error.message
|
|
2843
|
+
};
|
|
2844
|
+
|
|
2845
|
+
self.emit('query#complete', error)
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
return;
|
|
2849
|
+
});
|
|
2850
|
+
|
|
2851
|
+
req.on('end', function onEnd() {
|
|
2852
|
+
|
|
2853
|
+
// exceptions filter
|
|
2854
|
+
if ( typeof(data) == 'string' && /^Unknown ALPN Protocol/.test(data) ) {
|
|
2855
|
+
var err = {
|
|
2856
|
+
status: 500,
|
|
2857
|
+
error: new Error(data)
|
|
2858
|
+
};
|
|
2859
|
+
|
|
2860
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2861
|
+
callback(err)
|
|
2862
|
+
} else {
|
|
2863
|
+
self.emit('query#complete', err)
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
return
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
//Only when needed.
|
|
2870
|
+
if ( typeof(callback) != 'undefined' ) {
|
|
2871
|
+
if ( typeof(data) == 'string' && /^(\{|%7B|\[{)|\[\]/.test(data) ) {
|
|
2872
|
+
try {
|
|
2873
|
+
data = JSON.parse(data);
|
|
2874
|
+
// just in case
|
|
2875
|
+
if ( typeof(data.status) == 'undefined' ) {
|
|
2876
|
+
var currentRule = local.options.rule || local.req.routing.rule;
|
|
2877
|
+
console.warn( '['+ currentRule +'] ' + 'Response status code is `undefined`: switching to `200`');
|
|
2878
|
+
data.status = 200;
|
|
2879
|
+
}
|
|
2880
|
+
} catch (err) {
|
|
2881
|
+
data = {
|
|
2882
|
+
status : 500,
|
|
2883
|
+
error : err
|
|
2884
|
+
}
|
|
2885
|
+
console.error(err);
|
|
2886
|
+
}
|
|
2887
|
+
} else if ( !data && this.aborted && this.destroyed) {
|
|
2888
|
+
data = {
|
|
2889
|
+
status : 500,
|
|
2890
|
+
error : new Error('request aborted')
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
//console.debug(options[':method']+ ' ['+ (data.status || 200) +'] '+ options[':path']);
|
|
2894
|
+
try {
|
|
2895
|
+
// intercepting fallback redirect
|
|
2896
|
+
if ( data.status && /^3/.test(data.status) && typeof(data.headers) != 'undefined' ) {
|
|
2897
|
+
local.res.writeHead(data.status, data.headers);
|
|
2898
|
+
return local.res.end();
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
if ( data.status && !/^2/.test(data.status) && typeof(local.options.conf.server.coreConfiguration.statusCodes[data.status]) != 'undefined' ) {
|
|
2902
|
+
if ( /^5/.test(data.status) ) {
|
|
2903
|
+
return callback(data)
|
|
2904
|
+
} else {
|
|
2905
|
+
self.throwError(data);
|
|
2906
|
+
return;
|
|
2907
|
+
}
|
|
2908
|
+
} else {
|
|
2909
|
+
// required when control is used in an halted state
|
|
2910
|
+
// Ref.: resumeRequest()
|
|
2911
|
+
if ( self && self.isHaltedRequest() && typeof(local.onHaltedRequestResumed) != 'undefined' ) {
|
|
2912
|
+
local.onHaltedRequestResumed(false);
|
|
2913
|
+
}
|
|
2914
|
+
return callback( false, data )
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
} catch (e) {
|
|
2918
|
+
var infos = local.options, controllerName = infos.controller.substr(infos.controller.lastIndexOf('/'));
|
|
2919
|
+
var msg = 'Controller Query Exception while catching back.\nBundle: '+ infos.bundle +'\nController File: /controllers'+ controllerName +'\nControl: this.'+ infos.control +'(...)\n\r' + e.stack;
|
|
2920
|
+
var exception = new Error(msg);
|
|
2921
|
+
exception.status = 500;
|
|
2922
|
+
self.throwError(exception);
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
} else {
|
|
2927
|
+
if ( typeof(data) == 'string' && /^(\{|%7B|\[{)|\[\]/.test(data) ) {
|
|
2928
|
+
try {
|
|
2929
|
+
data = JSON.parse(data)
|
|
2930
|
+
} catch (e) {
|
|
2931
|
+
data = {
|
|
2932
|
+
status : 500,
|
|
2933
|
+
error : data
|
|
2934
|
+
}
|
|
2935
|
+
self.emit('query#complete', data)
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
// intercepting fallback redirect
|
|
2940
|
+
if ( data.status && /^3/.test(data.status) && typeof(data.headers) != 'undefined' ) {
|
|
2941
|
+
self.removeAllListeners(['query#complete']);
|
|
2942
|
+
local.res.writeHead(data.status, data.headers);
|
|
2943
|
+
return local.res.end();
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2946
|
+
if ( data.status && !/^2/.test(data.status) && typeof(local.options.conf.server.coreConfiguration.statusCodes[data.status]) != 'undefined' ) {
|
|
2947
|
+
self.emit('query#complete', data)
|
|
2948
|
+
} else {
|
|
2949
|
+
// required when control is used in an halted state
|
|
2950
|
+
// Ref.: resumeRequest()
|
|
2951
|
+
if ( self.isHaltedRequest() && typeof(local.onHaltedRequestResumed) != 'undefined' ) {
|
|
2952
|
+
local.onHaltedRequestResumed(false);
|
|
2953
|
+
}
|
|
2954
|
+
self.emit('query#complete', false, data)
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
client.close();
|
|
2959
|
+
});
|
|
2960
|
+
|
|
2961
|
+
if (!endStream) {
|
|
2962
|
+
req.end(body);
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
|
|
2966
|
+
|
|
2967
|
+
return {
|
|
2968
|
+
onComplete : function(cb) {
|
|
2969
|
+
|
|
2970
|
+
self.once('query#complete', function(err, data){
|
|
2971
|
+
|
|
2972
|
+
if ( typeof(data) == 'string' && /^(\{|%7B|\[{)|\[\]/.test(data) ) {
|
|
2973
|
+
try {
|
|
2974
|
+
data = JSON.parse(data)
|
|
2975
|
+
} catch (err) {
|
|
2976
|
+
data = {
|
|
2977
|
+
status : 500,
|
|
2978
|
+
error : data
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
try {
|
|
2984
|
+
if ( data.status && !/^2/.test(data.status) && typeof(local.options.conf.server.coreConfiguration.statusCodes[data.status]) != 'undefined') {
|
|
2985
|
+
cb(data)
|
|
2986
|
+
} else {
|
|
2987
|
+
// required when control is used in an halted state
|
|
2988
|
+
// Ref.: resumeRequest()
|
|
2989
|
+
if ( self.isHaltedRequest() && typeof(local.onHaltedRequestResumed) != 'undefined' ) {
|
|
2990
|
+
local.onHaltedRequestResumed(err);
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
cb(err, data)
|
|
2994
|
+
}
|
|
2995
|
+
} catch (e) {
|
|
2996
|
+
var infos = local.options, controllerName = infos.controller.substr(infos.controller.lastIndexOf('/'));
|
|
2997
|
+
var msg = 'Controller Query Exception while catching back.\nBundle: '+ infos.bundle +'\nController File: /controllers'+ controllerName +'\nControl: this.'+ infos.control +'(...)\n\r' + e.stack;
|
|
2998
|
+
var exception = new Error(msg);
|
|
2999
|
+
exception.status = 500;
|
|
3000
|
+
self.throwError(exception);
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
})
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
|
|
3009
|
+
/**
|
|
3010
|
+
* forward404Unless
|
|
3011
|
+
*
|
|
3012
|
+
* @param {boolean} condition
|
|
3013
|
+
* @param {object} req
|
|
3014
|
+
* @param {object} res
|
|
3015
|
+
*
|
|
3016
|
+
* @callback [ next ]
|
|
3017
|
+
* @param {string | boolean} err
|
|
3018
|
+
*
|
|
3019
|
+
* @returns {string | boolean} err
|
|
3020
|
+
* */
|
|
3021
|
+
this.forward404Unless = function(condition, req, res, next) {
|
|
3022
|
+
var pathname = req.url;
|
|
3023
|
+
|
|
3024
|
+
if (!condition) {
|
|
3025
|
+
self.throwError(res, 404, 'Page not found\n' + pathname);
|
|
3026
|
+
var err = new Error('Page not found\n' + pathname);
|
|
3027
|
+
if ( typeof(next) != 'undefined')
|
|
3028
|
+
next(err)
|
|
3029
|
+
else
|
|
3030
|
+
return err
|
|
3031
|
+
} else {
|
|
3032
|
+
if ( typeof(next) != 'undefined' )
|
|
3033
|
+
next(false)
|
|
3034
|
+
else
|
|
3035
|
+
return false
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
/**
|
|
3040
|
+
* Get all Params
|
|
3041
|
+
* */
|
|
3042
|
+
var getParams = function(req) {
|
|
3043
|
+
|
|
3044
|
+
req.getParams = function() {
|
|
3045
|
+
// Clone
|
|
3046
|
+
var params = JSON.clone(req.params);
|
|
3047
|
+
switch( req.method.toLowerCase() ) {
|
|
3048
|
+
case 'get':
|
|
3049
|
+
params = merge(params, req.get, true);
|
|
3050
|
+
break;
|
|
3051
|
+
|
|
3052
|
+
case 'post':
|
|
3053
|
+
params = merge(params, req.post, true);
|
|
3054
|
+
break;
|
|
3055
|
+
|
|
3056
|
+
case 'put':
|
|
3057
|
+
params = merge(params, req.put, true);
|
|
3058
|
+
break;
|
|
3059
|
+
|
|
3060
|
+
case 'delete':
|
|
3061
|
+
params = merge(params, req.delete, true);
|
|
3062
|
+
break;
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
return params
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
req.getParam = function(name) {
|
|
3069
|
+
|
|
3070
|
+
var param = null;
|
|
3071
|
+
switch( req.method.toLowerCase() ) {
|
|
3072
|
+
case 'get':
|
|
3073
|
+
param = req.get[name];
|
|
3074
|
+
break;
|
|
3075
|
+
|
|
3076
|
+
case 'post':
|
|
3077
|
+
param = req.post[name];
|
|
3078
|
+
break;
|
|
3079
|
+
|
|
3080
|
+
case 'put':
|
|
3081
|
+
param= req.put[name];
|
|
3082
|
+
break;
|
|
3083
|
+
|
|
3084
|
+
case 'delete':
|
|
3085
|
+
param = req.delete[name];
|
|
3086
|
+
break;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
return param
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
|
|
3093
|
+
/**
|
|
3094
|
+
* Forward request
|
|
3095
|
+
* Allowing x-bundle forward
|
|
3096
|
+
* Attention: this is a work in progres, do not use it yet
|
|
3097
|
+
*
|
|
3098
|
+
* @param {object} req
|
|
3099
|
+
* @param {object} res
|
|
3100
|
+
* @param {callback} next
|
|
3101
|
+
* @returns
|
|
3102
|
+
*/
|
|
3103
|
+
this.forward = function(req, res, next) {
|
|
3104
|
+
var route = req.routing;
|
|
3105
|
+
if ( typeof(route.param.url) == 'undefined' || /^(null|\s*)$/.test(route.param.url) ) {
|
|
3106
|
+
self.throwError( new Error('`route.param.url` must be defiend in your route: `'+ route.rule +'`') );
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
var param = {};
|
|
3111
|
+
for (let p in route.param) {
|
|
3112
|
+
if ( /^(url|urlIndex|control|file|title|bundle|project|hostname|port|path|method)$/.test(p) ) {
|
|
3113
|
+
continue;
|
|
3114
|
+
}
|
|
3115
|
+
param[p] = route.param[p]
|
|
3116
|
+
}
|
|
3117
|
+
var routeObj = null;
|
|
3118
|
+
if ( typeof(route.param.urlIndex) != 'undefined' ) {
|
|
3119
|
+
routeObj = lib.routing.getRoute(route.param.url, param, route.param.urlIndex);
|
|
3120
|
+
} else {
|
|
3121
|
+
routeObj = lib.routing.getRoute(route.param.url, param);
|
|
3122
|
+
}
|
|
3123
|
+
var ca = self.getConfig('settings').server.credentials.ca;
|
|
3124
|
+
var hostname = null, port = null, path = null;
|
|
3125
|
+
// by default
|
|
3126
|
+
var project = local.options.conf.projectName;
|
|
3127
|
+
if ( typeof(route.param.project) != 'undefined' && /^(null|\s*)$/.test(route.param.project) ) {
|
|
3128
|
+
project = route.param.project;
|
|
3129
|
+
} // TODO - add support for project pointer : getContext('gina').projects[project]
|
|
3130
|
+
if (/\@(.*)$/.test(route.param.url)) {
|
|
3131
|
+
var targetedBundle = route.param.url.substr(route.param.url.lastIndexOf('@')+1);
|
|
3132
|
+
hostname = targetedBundle +'@'+ project;
|
|
3133
|
+
port = hostname;
|
|
3134
|
+
var webroot = getContext('gina').config.envConf[targetedBundle][local.options.conf.env].server.webroot;
|
|
3135
|
+
path = (/\/$/.test(webroot)) ? webroot.substr(0, webroot.length-1) : webroot;
|
|
3136
|
+
} else {
|
|
3137
|
+
hostname = route.param.hostname;
|
|
3138
|
+
port = route.param.port;
|
|
3139
|
+
path = route.param.port;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
var method = null;
|
|
3143
|
+
if ( typeof(route.param.method) != 'undefined' ) {
|
|
3144
|
+
method = route.param.method.toLowerCase();
|
|
3145
|
+
} else {
|
|
3146
|
+
method = req.method.toLowerCase();
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
var opt = {
|
|
3150
|
+
ca: ca,
|
|
3151
|
+
hostname: hostname,
|
|
3152
|
+
port: port,
|
|
3153
|
+
path: path,
|
|
3154
|
+
method: method
|
|
3155
|
+
}
|
|
3156
|
+
if (self.isCacheless() || self.isLocalScope() ) {
|
|
3157
|
+
opt.rejectUnauthorized = false;
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
var obj = req[ req.method.toLowerCase() ];
|
|
3161
|
+
// if ( req.files != 'undefined' ) {
|
|
3162
|
+
// obj.files = req.files;
|
|
3163
|
+
// }
|
|
3164
|
+
self.query(opt, obj, function onForward(err, result){
|
|
3165
|
+
if (err) {
|
|
3166
|
+
self.throwError(err);
|
|
3167
|
+
return;
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
// TODO - filter : redirect & location
|
|
3171
|
+
|
|
3172
|
+
// if ( self.isXMLRequest() || !hasViews() || !local.options.isUsingTemplate && !hasViews() || hasViews() && !local.options.isUsingTemplate ) {
|
|
3173
|
+
self.renderJSON(result)
|
|
3174
|
+
// } else {
|
|
3175
|
+
// self.render(result)
|
|
3176
|
+
// }
|
|
3177
|
+
});
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
|
|
3181
|
+
/**
|
|
3182
|
+
* Get config
|
|
3183
|
+
*
|
|
3184
|
+
* @param {string} [name] - Conf name without extension.
|
|
3185
|
+
* @returns {object} config
|
|
3186
|
+
*
|
|
3187
|
+
* */
|
|
3188
|
+
this.getConfig = function(name) {
|
|
3189
|
+
if ( typeof(name) != 'undefined' ) {
|
|
3190
|
+
try {
|
|
3191
|
+
// needs to be read only
|
|
3192
|
+
//config = JSON.clone(local.options.conf.content[name]);
|
|
3193
|
+
//config = Object.freeze(local.options.conf.content[name]);
|
|
3194
|
+
//Object.seal(local.options.conf.content[name]);
|
|
3195
|
+
//Object.freeze(local.options.conf.content[name]);
|
|
3196
|
+
return JSON.clone(local.options.conf.content[name]);
|
|
3197
|
+
} catch (err) {
|
|
3198
|
+
return undefined;
|
|
3199
|
+
}
|
|
3200
|
+
} else {
|
|
3201
|
+
// config = JSON.stringify(local.options.conf);
|
|
3202
|
+
// return JSON.parse(config)
|
|
3203
|
+
return JSON.clone(local.options.conf);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
|
|
3207
|
+
/**
|
|
3208
|
+
* Get locales
|
|
3209
|
+
*
|
|
3210
|
+
* @param {string} [shortCountryCode] - e.g. EN
|
|
3211
|
+
*
|
|
3212
|
+
* @returns {object} locales
|
|
3213
|
+
* */
|
|
3214
|
+
this.getLocales = function (shortCountryCode) {
|
|
3215
|
+
|
|
3216
|
+
var userLocales = local.options.conf.locales;
|
|
3217
|
+
|
|
3218
|
+
if ( typeof(shortCountryCode) != 'undefined' ) {
|
|
3219
|
+
shortCountryCode = shortCountryCode.toLowerCase();
|
|
3220
|
+
var locales = new Collection( getContext('gina').locales );
|
|
3221
|
+
|
|
3222
|
+
try {
|
|
3223
|
+
userLocales = locales.findOne({ lang: shortCountryCode }).content
|
|
3224
|
+
} catch (err) {
|
|
3225
|
+
console.warn('language code `'+ shortCountryCode +'` not handled to setup locales: replacing by `'+ local.options.conf.content.settings.region.shortCode +'`');
|
|
3226
|
+
userLocales = locales.findOne({ lang: local.options.conf.content.settings.region.shortCode }).content // by default
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
|
|
3231
|
+
/**
|
|
3232
|
+
* Get countries list
|
|
3233
|
+
*
|
|
3234
|
+
* @param {string} [code] - e.g.: short, long, fifa, m49
|
|
3235
|
+
*
|
|
3236
|
+
* @returns {object} countries - countries code & value list
|
|
3237
|
+
* */
|
|
3238
|
+
var getCountries = function (code) {
|
|
3239
|
+
var list = {}, cde = 'short', name = null;
|
|
3240
|
+
|
|
3241
|
+
if ( typeof(code) != 'undefined' && typeof(userLocales[0][code]) == 'string' ) {
|
|
3242
|
+
cde = code
|
|
3243
|
+
} else if ( typeof(code) != 'undefined' ) (
|
|
3244
|
+
console.warn('`'+ code +'` not supported : sticking with `short` code')
|
|
3245
|
+
)
|
|
3246
|
+
|
|
3247
|
+
|
|
3248
|
+
for ( var i = 0, len = userLocales.length; i< len; ++i ) {
|
|
3249
|
+
|
|
3250
|
+
if (userLocales[i][cde]) {
|
|
3251
|
+
|
|
3252
|
+
name = userLocales[i].officialName.short || userLocales[i].full;
|
|
3253
|
+
|
|
3254
|
+
if ( name )
|
|
3255
|
+
list[ userLocales[i][cde] ] = name;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
return list
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
return {
|
|
3263
|
+
'getCountries': getCountries
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
/**
|
|
3268
|
+
* Get forms rules
|
|
3269
|
+
*
|
|
3270
|
+
*
|
|
3271
|
+
* @returns {object} rules
|
|
3272
|
+
*
|
|
3273
|
+
* */
|
|
3274
|
+
this.getFormsRules = function () {
|
|
3275
|
+
var bundle = local.options.conf.bundle; // by default
|
|
3276
|
+
var form = null;
|
|
3277
|
+
var rule = null;
|
|
3278
|
+
var isGettingRulesFromAnotherBundle = false;
|
|
3279
|
+
var rules = {};
|
|
3280
|
+
if ( typeof(local.req.ginaHeaders) != 'undefined' && typeof(local.req.ginaHeaders.form) != 'undefined' ) {
|
|
3281
|
+
form = local.req.ginaHeaders.form;
|
|
3282
|
+
if ( typeof(form.rule) != 'undefined' ) {
|
|
3283
|
+
var ruleInfos = form.rule.split(/\@/);
|
|
3284
|
+
rule = ruleInfos[0];
|
|
3285
|
+
// rules might be located in another bundle
|
|
3286
|
+
if (ruleInfos[1] && ruleInfos[1] != '' && ruleInfos[1] != bundle) {
|
|
3287
|
+
bundle = ruleInfos[1];
|
|
3288
|
+
isGettingRulesFromAnotherBundle = true;
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
if ( form && typeof(form.id) != 'undefined' ) {
|
|
3294
|
+
try {
|
|
3295
|
+
if (isGettingRulesFromAnotherBundle) {
|
|
3296
|
+
rules = JSON.clone(getConfig()[bundle][local.options.conf.env].content.forms.rules[form.id]) || null;
|
|
3297
|
+
} else {
|
|
3298
|
+
rules = JSON.clone(local.options.conf.content.forms).rules[form.id] || null;
|
|
3299
|
+
}
|
|
3300
|
+
|
|
3301
|
+
if (!rules) {
|
|
3302
|
+
rules = {};
|
|
3303
|
+
console.warn('[CONTROLLER]['+ local.options.conf.bundle +'][Backend validation] did not find matching rules for form.id `'+ form.id +'` for `'+ bundle+' bundle`. Do not Panic if you did not defined any.')
|
|
3304
|
+
}
|
|
3305
|
+
} catch (ruleErr) {
|
|
3306
|
+
self.throwError(ruleErr);
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
return rules;
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
this.push = function(payload) {
|
|
3315
|
+
|
|
3316
|
+
var req = local.req, res = local.res;
|
|
3317
|
+
var method = req.method.toLowerCase();
|
|
3318
|
+
// if no session defined, will push to all active clients
|
|
3319
|
+
var sessionId = ( typeof(req[method].sessionID) != 'undefined' ) ? req[method].sessionID : null;
|
|
3320
|
+
|
|
3321
|
+
// resume current session
|
|
3322
|
+
|
|
3323
|
+
if (!payload) {
|
|
3324
|
+
payload = null;
|
|
3325
|
+
if ( typeof(req[method]) != 'undefined' && typeof(req[method].payload) != 'undefined' ) {
|
|
3326
|
+
if ( typeof(payload) == 'string' ) {
|
|
3327
|
+
payload = decodeURIComponent(req[method].payload)
|
|
3328
|
+
} else {
|
|
3329
|
+
payload = JSON.stringify(req[method].payload)
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
} else if ( typeof(payload) == 'object' ) {
|
|
3333
|
+
payload = JSON.stringify(payload)
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
try {
|
|
3337
|
+
var clients = null;
|
|
3338
|
+
if (sessionId) {
|
|
3339
|
+
clients = self.serverInstance.eio.getClientsBySessionId(sessionId);
|
|
3340
|
+
if (clients)
|
|
3341
|
+
clients.send(payload);
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
// send to all clients if no specific sessionId defined
|
|
3345
|
+
if (!sessionId) {
|
|
3346
|
+
clients = self.serverInstance.eio.clients;
|
|
3347
|
+
for (var id in clients) {
|
|
3348
|
+
clients[id].send(payload)
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
|
|
3352
|
+
res.end();
|
|
3353
|
+
} catch(err) {
|
|
3354
|
+
self.throwError(err);
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
var getSession = function() {
|
|
3360
|
+
var session = null;
|
|
3361
|
+
if ( typeof(local.req.session) != 'undefined') {
|
|
3362
|
+
session = local.req.session;
|
|
3363
|
+
}
|
|
3364
|
+
// passport override
|
|
3365
|
+
if (!session && typeof(local.req.session) != 'undefined' && typeof(local.req.session.user) != 'undefined') {
|
|
3366
|
+
session = local.req.session.user;
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
return session;
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
this.isHaltedRequest = function(session) {
|
|
3373
|
+
// trying to retrieve session since it is optional
|
|
3374
|
+
if ( typeof(session) == 'undefined' ) {
|
|
3375
|
+
session = getSession();
|
|
3376
|
+
// if ( typeof(local.req.session) != 'undefined' && typeof(local.req.session.haltedRequest) != 'undefined' ) {
|
|
3377
|
+
// session = local.req.session;
|
|
3378
|
+
// }
|
|
3379
|
+
// // passport
|
|
3380
|
+
// if (!session && typeof(local.req.session) != 'undefined' && typeof(local.req.session.user) != 'undefined' && typeof(local.req.session.user.haltedRequest) != 'undefined' ) {
|
|
3381
|
+
// session = local.req.session.user;
|
|
3382
|
+
// }
|
|
3383
|
+
if (
|
|
3384
|
+
!session
|
|
3385
|
+
||
|
|
3386
|
+
typeof(session) != 'undefined'
|
|
3387
|
+
&& typeof(session.haltedRequest) == 'undefined'
|
|
3388
|
+
) {
|
|
3389
|
+
return false;
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
return (typeof(session.haltedRequest) != 'undefined' ) ? true : false;
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
|
|
3397
|
+
local.haltedRequestUrlResumed = false;
|
|
3398
|
+
|
|
3399
|
+
this.pauseRequest = function(data, requestStorage) {
|
|
3400
|
+
|
|
3401
|
+
|
|
3402
|
+
// saving halted request
|
|
3403
|
+
var req = local.req
|
|
3404
|
+
, res = local.res
|
|
3405
|
+
, next = local.next
|
|
3406
|
+
, haltedRequest = {
|
|
3407
|
+
url : req.url,
|
|
3408
|
+
routing : req.routing,
|
|
3409
|
+
method : req.method.toLowerCase(),
|
|
3410
|
+
data : JSON.clone(data)
|
|
3411
|
+
}
|
|
3412
|
+
;
|
|
3413
|
+
|
|
3414
|
+
if (
|
|
3415
|
+
typeof(requestStorage) == 'undefined'
|
|
3416
|
+
&& typeof(req.session) != 'undefined'
|
|
3417
|
+
) {
|
|
3418
|
+
requestStorage = req.session;
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
if (
|
|
3422
|
+
typeof(requestStorage) == 'undefined'
|
|
3423
|
+
) {
|
|
3424
|
+
var error = new ApiError('`requestStorage` is required', 424);
|
|
3425
|
+
self.throwError(error);
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
var requestParams = {}, i = 0;
|
|
3430
|
+
for (var p in req.params) {
|
|
3431
|
+
if (i > 0) {
|
|
3432
|
+
requestParams[p] = req.params[p];
|
|
3433
|
+
}
|
|
3434
|
+
++i;
|
|
3435
|
+
}
|
|
3436
|
+
if (requestParams.count() > 0) {
|
|
3437
|
+
haltedRequest.params = requestParams;
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
requestStorage.haltedRequest = haltedRequest;
|
|
3441
|
+
|
|
3442
|
+
return requestStorage;
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
|
|
3446
|
+
/**
|
|
3447
|
+
* resumeRequest
|
|
3448
|
+
* Used to resume an halted request
|
|
3449
|
+
* Requirements :
|
|
3450
|
+
* - a middleware attached `haltedRequest` to userSession
|
|
3451
|
+
* OR
|
|
3452
|
+
* - a persistant object where `haltedRequest` is attached
|
|
3453
|
+
*
|
|
3454
|
+
* @param {object} req
|
|
3455
|
+
* @param {object} res
|
|
3456
|
+
* @param {callback|null} next
|
|
3457
|
+
* @param {object} [requestStorage] - Will try to use sessionStorage if not passed
|
|
3458
|
+
*/
|
|
3459
|
+
this.resumeRequest = function(requestStorage) {
|
|
3460
|
+
|
|
3461
|
+
if (local.haltedRequestUrlResumed)
|
|
3462
|
+
return;
|
|
3463
|
+
|
|
3464
|
+
var haltedRequest = null
|
|
3465
|
+
, req = local.req
|
|
3466
|
+
, res = local.res
|
|
3467
|
+
, next = local.next
|
|
3468
|
+
;
|
|
3469
|
+
|
|
3470
|
+
if (
|
|
3471
|
+
typeof(requestStorage) == 'undefined'
|
|
3472
|
+
&& typeof(req.session) != 'undefined'
|
|
3473
|
+
) {
|
|
3474
|
+
requestStorage = req.session;
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
if (
|
|
3478
|
+
typeof(requestStorage) == 'undefined'
|
|
3479
|
+
||
|
|
3480
|
+
typeof(requestStorage) != 'undefined'
|
|
3481
|
+
&& typeof(requestStorage.haltedRequest) == 'undefined'
|
|
3482
|
+
) {
|
|
3483
|
+
var error = new ApiError('`requestStorage.haltedRequest` is required', 424);
|
|
3484
|
+
self.throwError(error);
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3487
|
+
haltedRequest = requestStorage.haltedRequest;
|
|
3488
|
+
var data = haltedRequest.data || {};
|
|
3489
|
+
// request methods cleanup
|
|
3490
|
+
// checkout /framework/{verrsion}/core/template/conf/(settings.json).server.supportedRequestMethods
|
|
3491
|
+
var serverSupportedMethods = local.options.conf.server.supportedRequestMethods;
|
|
3492
|
+
for (let method in serverSupportedMethods) {
|
|
3493
|
+
if (req.method.toLowerCase() == method) {
|
|
3494
|
+
data = merge(data, req[method])
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
delete req[method];
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
|
|
3501
|
+
var dataAsParams = {};
|
|
3502
|
+
if (data.count() > 0) {
|
|
3503
|
+
dataAsParams = JSON.clone(haltedRequest.data);
|
|
3504
|
+
}
|
|
3505
|
+
var url = lib.routing.getRoute(haltedRequest.routing.rule, haltedRequest.params||dataAsParams).url;
|
|
3506
|
+
var requiredController = self; // by default;
|
|
3507
|
+
if ( req.routing.namespace != haltedRequest.routing.namespace ) {
|
|
3508
|
+
try {
|
|
3509
|
+
requiredController = self.requireController(haltedRequest.routing.namespace, self._options );
|
|
3510
|
+
} catch (err) {
|
|
3511
|
+
self.throwError(err);
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
req.routing = haltedRequest.routing;
|
|
3515
|
+
req.method = haltedRequest.method;
|
|
3516
|
+
req[haltedRequest.method] = data;
|
|
3517
|
+
|
|
3518
|
+
local.haltedRequestUrlResumed = true;
|
|
3519
|
+
if ( /GET/i.test(req.method) ) {
|
|
3520
|
+
if ( typeof(requestStorage.haltedRequest) != 'undefined' ) {
|
|
3521
|
+
delete requestStorage.haltedRequest;
|
|
3522
|
+
}
|
|
3523
|
+
delete requestStorage.haltedRequest;
|
|
3524
|
+
delete requestStorage.inheritedData;
|
|
3525
|
+
requestStorage.haltedRequestUrlResumed = url;
|
|
3526
|
+
|
|
3527
|
+
requiredController.redirect(url, true);
|
|
3528
|
+
} else {
|
|
3529
|
+
local.onHaltedRequestResumed = function(err) {
|
|
3530
|
+
if (!err) {
|
|
3531
|
+
delete requestStorage.haltedRequest;
|
|
3532
|
+
delete requestStorage.inheritedData;
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
if ( typeof(next) == 'function' ) {
|
|
3536
|
+
console.warn('About to override `next` param');
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
try {
|
|
3540
|
+
requiredController[req.routing.param.control](req, res, next);
|
|
3541
|
+
// consuming it
|
|
3542
|
+
local.onHaltedRequestResumed(false);
|
|
3543
|
+
} catch(err) {
|
|
3544
|
+
console.error('[ BUNDLE ][ '+ local.options.conf.bundle +' ][ Controller ] Could not resume haltedRequest\n' + err.stack );
|
|
3545
|
+
self.throwError(err);
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
|
|
3553
|
+
this.renderCustomError = function (req, res, next) {
|
|
3554
|
+
|
|
3555
|
+
// preventing multiple call of self.renderWithoutLayout() when controller is rendering from another required controller
|
|
3556
|
+
if (local.options.renderingStack.length > 1) {
|
|
3557
|
+
return false;
|
|
3558
|
+
}
|
|
3559
|
+
local.options.isRenderingCustomError = true;
|
|
3560
|
+
|
|
3561
|
+
//local.options.isWithoutLayout = true;
|
|
3562
|
+
|
|
3563
|
+
var data = null;
|
|
3564
|
+
if ( typeof(req.routing.param.error) != 'undefined' ) {
|
|
3565
|
+
data = JSON.clone(req.routing.param.error) || {};
|
|
3566
|
+
delete req.routing.param.error
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
var session = getSession();
|
|
3570
|
+
if (session) {
|
|
3571
|
+
data.session = JSON.clone(session)
|
|
3572
|
+
}
|
|
3573
|
+
var displayToolbar = req.routing.param.displayToolbar || false;
|
|
3574
|
+
if (req.routing.param.displayToolbar) {
|
|
3575
|
+
delete req.routing.param.displayToolbar
|
|
3576
|
+
}
|
|
3577
|
+
var isLocalOptionResetNeeded = req.routing.param.isLocalOptionResetNeeded || false;
|
|
3578
|
+
var errOptions = null;
|
|
3579
|
+
if (isLocalOptionResetNeeded) {
|
|
3580
|
+
delete req.routing.param.isLocalOptionResetNeeded;
|
|
3581
|
+
var bundleConf = JSON.clone(local.options.conf);
|
|
3582
|
+
var bundle = req.routing.bundle;
|
|
3583
|
+
var param = req.routing.param;
|
|
3584
|
+
var localOptions = {
|
|
3585
|
+
// view namespace first
|
|
3586
|
+
//namespace : null,
|
|
3587
|
+
control : param.control,
|
|
3588
|
+
//controller : controllerFile,
|
|
3589
|
+
//controller: '<span class="gina-bundle-name">' + bundle +'</span>/controllers/controller.js',
|
|
3590
|
+
file: param.file,
|
|
3591
|
+
//layout: param.file,
|
|
3592
|
+
//bundle : bundle,//module
|
|
3593
|
+
bundlePath : bundleConf.bundlesPath + '/' + bundle,
|
|
3594
|
+
renderingStack : bundleConf.renderingStack,
|
|
3595
|
+
//rootPath : self.executionPath,
|
|
3596
|
+
// We don't want to keep original conf untouched
|
|
3597
|
+
//conf : JSON.clone(conf),
|
|
3598
|
+
//instance: self.serverInstance,
|
|
3599
|
+
//template: (routeHasViews) ? bundleConf.content.templates[templateName] : undefined,
|
|
3600
|
+
//isUsingTemplate: local.isUsingTemplate,
|
|
3601
|
+
//cacheless: cacheless,
|
|
3602
|
+
path: null //, // user custom path : namespace should be ignored | left blank
|
|
3603
|
+
//assets: {}
|
|
3604
|
+
};
|
|
3605
|
+
errOptions = merge(localOptions, local.options);
|
|
3606
|
+
|
|
3607
|
+
|
|
3608
|
+
}
|
|
3609
|
+
delete local.options.namespace;
|
|
3610
|
+
self.render(data, displayToolbar, errOptions);
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
|
|
3614
|
+
/**
|
|
3615
|
+
* Throw error
|
|
3616
|
+
*
|
|
3617
|
+
* @param {object} [ res ]
|
|
3618
|
+
* @param {number} code
|
|
3619
|
+
* @param {string} msg
|
|
3620
|
+
*
|
|
3621
|
+
* @returns {void}
|
|
3622
|
+
* */
|
|
3623
|
+
this.throwError = function(res, code, msg) {
|
|
3624
|
+
self.isProcessingError = true;
|
|
3625
|
+
var errorObject = null; // to be returned
|
|
3626
|
+
|
|
3627
|
+
// preventing multiple call of self.throwError() when controller is rendering from another required controller
|
|
3628
|
+
if (local.options.renderingStack.length > 1) {
|
|
3629
|
+
return false
|
|
3630
|
+
}
|
|
3631
|
+
var bundleConf = local.options.conf;
|
|
3632
|
+
var bundle = bundleConf.bundle;
|
|
3633
|
+
// handle error fallback
|
|
3634
|
+
// err.fallback must be a valide route object or a url string
|
|
3635
|
+
var fallback = null;
|
|
3636
|
+
var standardErrorMessage = null;
|
|
3637
|
+
if (
|
|
3638
|
+
arguments[0] instanceof Error
|
|
3639
|
+
|| arguments.length == 1 && typeof(res) == 'object'
|
|
3640
|
+
|| arguments[arguments.length-1] instanceof Error
|
|
3641
|
+
|| typeof(arguments[arguments.length-1]) == 'string' && !(arguments[0] instanceof Error)
|
|
3642
|
+
) {
|
|
3643
|
+
|
|
3644
|
+
code = ( res && typeof(res.status) != 'undefined' ) ? res.status : 500;
|
|
3645
|
+
|
|
3646
|
+
if ( typeof(statusCodes[code]) != 'undefined' ) {
|
|
3647
|
+
standardErrorMessage = statusCodes[code];
|
|
3648
|
+
} else {
|
|
3649
|
+
console.warn('[ ApiValidator ] statusCode `'+ code +'` not matching any definition in `'+_( getPath('gina').core + '/status.codes')+'`\nPlease contact the Gina dev team to add one if required');
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3652
|
+
errorObject = {
|
|
3653
|
+
status : code,
|
|
3654
|
+
error : res.error || res.message || standardErrorMessage
|
|
3655
|
+
};
|
|
3656
|
+
|
|
3657
|
+
if ( res instanceof Error || typeof(res.stack) != 'undefined' ) {
|
|
3658
|
+
//errorObject.status = code;
|
|
3659
|
+
//errorObject.error = standardErrorMessage || res.error || res.message;
|
|
3660
|
+
errorObject.stack = res.stack;
|
|
3661
|
+
if (res.message && typeof(res.message) == 'string') {
|
|
3662
|
+
errorObject.message = res.message;
|
|
3663
|
+
} else if (res.message) {
|
|
3664
|
+
console.warn('[ Controller ] Ignoring message because of the format.\n'+res.message)
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3667
|
+
} else if ( typeof(arguments[arguments.length-1]) == 'string' ) {
|
|
3668
|
+
// formated error
|
|
3669
|
+
errorObject.message = arguments[arguments.length-1]
|
|
3670
|
+
} else if (
|
|
3671
|
+
arguments[arguments.length-1] instanceof Error
|
|
3672
|
+
|| typeof(res) == 'object' && typeof(res.stack) != 'undefined'
|
|
3673
|
+
) {
|
|
3674
|
+
errorObject = merge(arguments[arguments.length-1], errorObject)
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
if ( typeof(res.fallback) != 'undefined' ) {
|
|
3678
|
+
fallback = res.fallback
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3681
|
+
res = local.res;
|
|
3682
|
+
|
|
3683
|
+
} else if (arguments.length < 3) {
|
|
3684
|
+
msg = code || null;
|
|
3685
|
+
code = res || 500;
|
|
3686
|
+
res = local.res;
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3689
|
+
var responseHeaders = res.getHeaders() || local.res.getHeaders();
|
|
3690
|
+
var req = local.req;
|
|
3691
|
+
var next = local.next;
|
|
3692
|
+
if (!res.headersSent) {
|
|
3693
|
+
// DELETE request methods don't normaly use a view,
|
|
3694
|
+
// but if we are calling it from a view, we should render the error back to the view
|
|
3695
|
+
if ( self.isXMLRequest() || !hasViews() && !/delete/i.test(req.method) || !local.options.isUsingTemplate && !hasViews() || hasViews() && !local.options.isUsingTemplate ) {
|
|
3696
|
+
// fallback interception
|
|
3697
|
+
if ( fallback ) {
|
|
3698
|
+
if ( typeof(fallback) == 'string' ){ // string url: user provided
|
|
3699
|
+
return self.redirect( fallback, true )
|
|
3700
|
+
} else {
|
|
3701
|
+
// else, using url from route object
|
|
3702
|
+
// Reminder
|
|
3703
|
+
// Here, we use route.toUrl() intead of
|
|
3704
|
+
// route.url to support x-bundle com
|
|
3705
|
+
return self.redirect( fallback.toUrl() );
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3709
|
+
// allowing this.throwError(err)
|
|
3710
|
+
if ( typeof(code) == 'object' && !msg && typeof(code.status) != 'undefined' && typeof(code.error) != 'undefined' ) {
|
|
3711
|
+
msg = code.error || code.message;
|
|
3712
|
+
code = code.status || 500;
|
|
3713
|
+
}
|
|
3714
|
+
if ( typeof(statusCodes[code]) != 'undefined' ) {
|
|
3715
|
+
standardErrorMessage = statusCodes[code];
|
|
3716
|
+
} else {
|
|
3717
|
+
console.warn('[ ApiValidator ] statusCode `'+ code +'` not matching any definition in `'+_( getPath('gina').core + '/status.codes')+'`\nPlease contact the Gina dev team to add one if required');
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
// if ( !local.res.getHeaders()['content-type'] /**!req.headers['content-type'] */ ) {
|
|
3721
|
+
// // Internet Explorer override
|
|
3722
|
+
// if ( typeof(req.headers['user-agent']) != 'undefined' && /msie/i.test(req.headers['user-agent']) ) {
|
|
3723
|
+
// res.writeHead(code, "content-type", "text/plain")
|
|
3724
|
+
// } else {
|
|
3725
|
+
// res.writeHead(code, { 'content-type': bundleConf.server.coreConfiguration.mime['json']} );
|
|
3726
|
+
// }
|
|
3727
|
+
// }
|
|
3728
|
+
|
|
3729
|
+
// TODO - test with internet explorer then remove this if working
|
|
3730
|
+
if ( typeof(req.headers['user-agent']) != 'undefined' ) {
|
|
3731
|
+
if ( /msie/i.test(req.headers['user-agent']) ) {
|
|
3732
|
+
res.writeHead(code, "content-type", "text/plain");
|
|
3733
|
+
} else {
|
|
3734
|
+
var contentType = ( responseHeaders && responseHeaders['content-type'])
|
|
3735
|
+
? responseHeaders['content-type']
|
|
3736
|
+
: bundleConf.server.coreConfiguration.mime['json']+ '; charset='+ bundleConf.encoding
|
|
3737
|
+
;
|
|
3738
|
+
res.writeHead(code, { 'content-type': contentType } );
|
|
3739
|
+
}
|
|
3740
|
+
} else if ( typeof(responseHeaders['content-type']) != 'undefined' ) {
|
|
3741
|
+
res.writeHead(code, { 'content-type': responseHeaders['content-type']} )
|
|
3742
|
+
} else {
|
|
3743
|
+
res.writeHead(code, "content-type", bundleConf.server.coreConfiguration.mime['json']+ '; charset='+ bundleConf.encoding);
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
|
|
3747
|
+
|
|
3748
|
+
if (!errorObject) {
|
|
3749
|
+
errorObject = {
|
|
3750
|
+
status: code,
|
|
3751
|
+
//errors: msg.error || msg.errors || msg,
|
|
3752
|
+
error: standardErrorMessage || msg.error || msg,
|
|
3753
|
+
message: msg.message || msg,
|
|
3754
|
+
stack: msg.stack
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
|
|
3758
|
+
var errOutput = null, output = errorObject.toString();
|
|
3759
|
+
if ( output == '[object Object]' ) {
|
|
3760
|
+
errOutput = JSON.stringify(errorObject);
|
|
3761
|
+
} else {
|
|
3762
|
+
errOutput = JSON.stringify(
|
|
3763
|
+
{
|
|
3764
|
+
status : errorObject.status,
|
|
3765
|
+
error : output
|
|
3766
|
+
}
|
|
3767
|
+
);
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
console.error('[ BUNDLE ][ '+ bundleConf.bundle +' ][ Controller ] '+ req.method +' ['+res.statusCode +'] '+ req.url +'\n'+ errOutput);
|
|
3771
|
+
return res.end(errOutput);
|
|
3772
|
+
} else {
|
|
3773
|
+
|
|
3774
|
+
|
|
3775
|
+
console.error(req.method +' ['+ errorObject.status +'] '+ req.url);
|
|
3776
|
+
|
|
3777
|
+
|
|
3778
|
+
// intercept none HTML mime types
|
|
3779
|
+
var url = unescape(local.req.url) /// avoid %20
|
|
3780
|
+
, ext = null
|
|
3781
|
+
, isHtmlContent = false
|
|
3782
|
+
, hasCustomErrorFile = false
|
|
3783
|
+
, eCode = code.toString().substr(0,1) + 'xx'
|
|
3784
|
+
;
|
|
3785
|
+
var extArr = url.substr(url.lastIndexOf('.')).match(/(\.[A-Za-z0-9]+)/);
|
|
3786
|
+
if (extArr) {
|
|
3787
|
+
ext = extArr[0].substr(1);
|
|
3788
|
+
}
|
|
3789
|
+
if ( !ext || /^(html|htm)$/i.test(ext) ) {
|
|
3790
|
+
isHtmlContent = true;
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
if (
|
|
3794
|
+
isHtmlContent
|
|
3795
|
+
&& typeof(bundleConf.content.templates._common.errorFiles) != 'undefined'
|
|
3796
|
+
&& typeof(bundleConf.content.templates._common.errorFiles[code]) != 'undefined'
|
|
3797
|
+
||
|
|
3798
|
+
isHtmlContent
|
|
3799
|
+
&& typeof(bundleConf.content.templates._common.errorFiles) != 'undefined'
|
|
3800
|
+
&& typeof(bundleConf.content.templates._common.errorFiles[eCode]) != 'undefined'
|
|
3801
|
+
) {
|
|
3802
|
+
hasCustomErrorFile = true;
|
|
3803
|
+
var eFilename = null
|
|
3804
|
+
, eData = null
|
|
3805
|
+
;
|
|
3806
|
+
eData = {
|
|
3807
|
+
isRenderingCustomError : true,
|
|
3808
|
+
bundle : bundle,
|
|
3809
|
+
status : code || null,
|
|
3810
|
+
//message : errorObject.message || msg || null,
|
|
3811
|
+
pathname : url
|
|
3812
|
+
};
|
|
3813
|
+
|
|
3814
|
+
if ( errorObject ) {
|
|
3815
|
+
eData = merge(errorObject, eData);
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
if ( typeof(msg) == 'object' ) {
|
|
3819
|
+
if ( typeof(msg.stack) != 'undefined' ) {
|
|
3820
|
+
eData.stack = msg.stack
|
|
3821
|
+
}
|
|
3822
|
+
if ( !eData.message && typeof(msg.message) != 'undefined' ) {
|
|
3823
|
+
eData.message = msg.message
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
if (
|
|
3827
|
+
code
|
|
3828
|
+
// See: framework/${version}/core/status.code
|
|
3829
|
+
&& typeof(bundleConf.server.coreConfiguration.statusCodes[code]) != 'undefined'
|
|
3830
|
+
) {
|
|
3831
|
+
eData.title = bundleConf.server.coreConfiguration.statusCodes[code];
|
|
3832
|
+
}
|
|
3833
|
+
// TODO - Remove this if not used
|
|
3834
|
+
// if ( typeof(local.req.routing) != 'undefined' ) {
|
|
3835
|
+
// eData.routing = local.req.routing;
|
|
3836
|
+
// }
|
|
3837
|
+
|
|
3838
|
+
if (typeof(bundleConf.content.templates._common.errorFiles[code]) != 'undefined') {
|
|
3839
|
+
eFilename = bundleConf.content.templates._common.errorFiles[code];
|
|
3840
|
+
} else {
|
|
3841
|
+
eFilename = bundleConf.content.templates._common.errorFiles[eCode];
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
if (!local.options.isRenderingCustomError) {
|
|
3845
|
+
var eRule = 'custom-error-page@'+ bundle;
|
|
3846
|
+
var routeObj = bundleConf.content.routing[eRule];
|
|
3847
|
+
routeObj.rule = eRule;
|
|
3848
|
+
//routeObj.url = unescape(local.req.url);/// avoid %20
|
|
3849
|
+
routeObj.param.title = ( typeof(eData.title) != 'undefined' ) ? eData.title : 'Error ' + eData.status;
|
|
3850
|
+
routeObj.param.file = eFilename;
|
|
3851
|
+
routeObj.param.error = eData;
|
|
3852
|
+
routeObj.param.displayToolbar = self.isCacheless();
|
|
3853
|
+
routeObj.param.isLocalOptionResetNeeded = true;
|
|
3854
|
+
|
|
3855
|
+
|
|
3856
|
+
local.req.routing = routeObj;
|
|
3857
|
+
local.req.params.errorObject = errorObject;
|
|
3858
|
+
self.renderCustomError(local.req, res, local.next);
|
|
3859
|
+
return;
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3862
|
+
}
|
|
3863
|
+
|
|
3864
|
+
// if (!errorObject) {
|
|
3865
|
+
// errorObject = {
|
|
3866
|
+
// status: code,
|
|
3867
|
+
// //errors: msg.error || msg.errors || msg,
|
|
3868
|
+
// error: standardErrorMessage || msg.error || msg,
|
|
3869
|
+
// message: msg.message || msg,
|
|
3870
|
+
// stack: msg.stack
|
|
3871
|
+
// }
|
|
3872
|
+
// }
|
|
3873
|
+
var msgString = '<h1 class="status">Error '+ code +'.</h1>';
|
|
3874
|
+
|
|
3875
|
+
console.error('[ BUNDLE ][ '+ local.options.conf.bundle +' ][ Controller ] `this.'+ req.routing.param.control +'(...)` ['+res.statusCode +'] '+ req.url);
|
|
3876
|
+
if ( typeof(msg) == 'object' ) {
|
|
3877
|
+
|
|
3878
|
+
if (msg.title) {
|
|
3879
|
+
msgString += '<pre class="'+ eCode +' title">'+ msg.title +'</pre>';
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3882
|
+
if (msg.error) {
|
|
3883
|
+
msgString += '<pre class="'+ eCode +' message">'+ msg.error +'</pre>';
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
if (msg.message) {
|
|
3887
|
+
msgString += '<pre class="'+ eCode +' message">'+ msg.message +'</pre>';
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
if (msg.stack) {
|
|
3891
|
+
|
|
3892
|
+
if (msg.error) {
|
|
3893
|
+
msg.stack = msg.stack.replace(msg.error, '')
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3896
|
+
if (msg.message) {
|
|
3897
|
+
msg.stack = msg.stack.replace(msg.message, '')
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
msg.stack = msg.stack.replace('Error:', '').replace(' ', '');
|
|
3901
|
+
msgString += '<pre class="'+ eCode +' stack">'+ msg.stack +'</pre>';
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
} else {
|
|
3905
|
+
// Generic error
|
|
3906
|
+
var title = null, message = null, stack = null;;
|
|
3907
|
+
if ( typeof(errorObject) != 'undefined' && errorObject && typeof(errorObject.error) != 'undefined' ) {
|
|
3908
|
+
title = errorObject.error
|
|
3909
|
+
}
|
|
3910
|
+
if (typeof(errorObject) != 'undefined' && errorObject && typeof(errorObject.message) != 'undefined' ) {
|
|
3911
|
+
message = errorObject.message
|
|
3912
|
+
}
|
|
3913
|
+
if (typeof(errorObject) != 'undefined' && errorObject && typeof(errorObject.stack) != 'undefined' ) {
|
|
3914
|
+
stack = errorObject.stack
|
|
3915
|
+
}
|
|
3916
|
+
|
|
3917
|
+
if (title) {
|
|
3918
|
+
msgString += '<pre class="'+ eCode +' title">'+ title +'</pre>';
|
|
3919
|
+
}
|
|
3920
|
+
if (message) {
|
|
3921
|
+
msgString += '<pre class="'+ eCode +' message">'+ message +'</pre>';
|
|
3922
|
+
}
|
|
3923
|
+
if (stack) {
|
|
3924
|
+
msgString += '<pre class="'+ eCode +' stack">'+ stack +'</pre>';
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
res.writeHead(code, { 'content-type': bundleConf.server.coreConfiguration.mime[ext]+'; charset='+ bundleConf.encoding } );
|
|
3928
|
+
// if ( isHtmlContent && hasCustomErrorFile ) {
|
|
3929
|
+
// res.end(msgString);
|
|
3930
|
+
// } else {
|
|
3931
|
+
//if ( isHtmlContent && !hasCustomErrorFile ) {
|
|
3932
|
+
res.end(msgString);
|
|
3933
|
+
//}
|
|
3934
|
+
|
|
3935
|
+
return;
|
|
3936
|
+
}
|
|
3937
|
+
} else {
|
|
3938
|
+
if (typeof(next) != 'undefined')
|
|
3939
|
+
return next();
|
|
3940
|
+
}
|
|
3941
|
+
res.end();
|
|
3942
|
+
return;
|
|
3943
|
+
}
|
|
3944
|
+
|
|
3945
|
+
// converting references to objects
|
|
3946
|
+
var refToObj = function (arr){
|
|
3947
|
+
var tmp = null,
|
|
3948
|
+
curObj = {},
|
|
3949
|
+
obj = {},
|
|
3950
|
+
count = 0,
|
|
3951
|
+
data = {},
|
|
3952
|
+
last = null;
|
|
3953
|
+
for (var r in arr) {
|
|
3954
|
+
tmp = r.split(".");
|
|
3955
|
+
//Creating structure - Adding sub levels
|
|
3956
|
+
for (var o in tmp) {
|
|
3957
|
+
count++;
|
|
3958
|
+
if (last && typeof(obj[last]) == "undefined") {
|
|
3959
|
+
curObj[last] = {};
|
|
3960
|
+
if (count >= tmp.length) {
|
|
3961
|
+
// assigning.
|
|
3962
|
+
// !!! if null or undefined, it will be ignored while extending.
|
|
3963
|
+
curObj[last][tmp[o]] = (arr[r]) ? arr[r] : "undefined";
|
|
3964
|
+
last = null;
|
|
3965
|
+
count = 0;
|
|
3966
|
+
break
|
|
3967
|
+
} else {
|
|
3968
|
+
curObj[last][tmp[o]] = {}
|
|
3969
|
+
}
|
|
3970
|
+
} else if (tmp.length === 1) { //Just one root var
|
|
3971
|
+
curObj[tmp[o]] = (arr[r]) ? arr[r] : "undefined";
|
|
3972
|
+
obj = curObj;
|
|
3973
|
+
break
|
|
3974
|
+
}
|
|
3975
|
+
obj = curObj;
|
|
3976
|
+
last = tmp[o]
|
|
3977
|
+
}
|
|
3978
|
+
//data = merge(data, obj, true);
|
|
3979
|
+
data = merge(obj, data);
|
|
3980
|
+
obj = {};
|
|
3981
|
+
curObj = {}
|
|
3982
|
+
}
|
|
3983
|
+
return data
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
init()
|
|
3987
|
+
};
|
|
3988
|
+
|
|
3989
|
+
SuperController = inherits(SuperController, EventEmitter);
|
|
3990
|
+
module.exports = SuperController
|