├── .chglog ├── CHANGELOG.tpl.md ├── RELEASE.tpl.md ├── config.yml └── release-config.yml ├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── codeql-analysis.yml │ ├── github-ci.yml │ └── reuse-compliance.yml ├── .gitignore ├── .npmrc ├── .reuse └── dep5 ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── LICENSES └── Apache-2.0.txt ├── README.md ├── SECURITY.md ├── index.js ├── lib ├── discovery.js ├── less.js ├── properties.js ├── proxy-rewrite-cookies.js └── proxy.js ├── package-lock.json ├── package.json └── test ├── discovery_test.js ├── fixtures ├── discovery │ ├── app-resources1 │ │ └── index.html │ ├── app-resources2 │ │ └── foo │ │ │ └── bar.htm │ ├── resources1 │ │ └── my │ │ │ └── ui │ │ │ └── lib │ │ │ └── .library │ ├── resources2 │ │ └── my │ │ │ └── legacy │ │ │ └── ui │ │ │ └── lib │ │ │ └── my.legacy.ui.lib.library │ ├── resources3 │ │ └── my │ │ │ └── ui │ │ │ └── l │ │ │ └── .library │ ├── test-resources1 │ │ └── my │ │ │ └── ui │ │ │ └── lib │ │ │ └── qunit │ │ │ └── MyControl.qunit.html │ ├── test-resources2 │ │ └── my │ │ │ └── legacy │ │ │ └── ui │ │ │ └── lib │ │ │ └── MyControl.htm │ └── test-resources3 │ │ └── my │ │ └── ui │ │ └── l │ │ └── qunit │ │ └── MyControl3.qunit.html ├── less │ └── test │ │ └── themes │ │ └── mytheme │ │ └── library.source.less └── properties │ └── test.properties ├── less_test.js ├── mergeUrls_test.js ├── properties_test.js ├── proxy-rewrite-cookies_test.js ├── proxy_ignore_remote_location_test.js ├── proxy_test.js └── proxy_use_remote_location_test.js /.chglog/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 4 | 5 | {{ if .Versions -}} 6 | A list of unreleased changes can be found [here]({{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD). 7 | {{ end -}} 8 | 9 | {{ range .Versions }} 10 | 11 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} 12 | {{ range .CommitGroups -}} 13 | ### {{ .Title }} 14 | {{ range .Commits -}} 15 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [`{{ .Hash.Short }}`]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Long }}) 16 | {{ end }} 17 | {{ end -}} 18 | 19 | {{- if .RevertCommits -}} 20 | ### Reverts 21 | {{ range .RevertCommits -}} 22 | - {{ .Revert.Header }} 23 | {{ end }} 24 | {{ end -}} 25 | 26 | {{- if .NoteGroups -}} 27 | {{ range .NoteGroups -}} 28 | ### {{ .Title }} 29 | {{ range .Notes }} 30 | {{ .Body }} 31 | {{ end }} 32 | {{ end -}} 33 | {{ end -}} 34 | {{ end -}} 35 | 36 | {{- if .Versions }} 37 | {{ range .Versions -}} 38 | {{ if .Tag.Previous -}} 39 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} 40 | {{ end -}} 41 | {{ end -}} 42 | {{ end -}} 43 | 44 | ## 0.7.7 - 2019-07-01 45 | 46 | ### Fixes 47 | - proxy middleware 48 | - Removing 'secure' flag of cookies [#50](https://github.com/SAP/connect-openui5/pull/50) 49 | 50 | ### All changes 51 | [`0.7.6...0.7.7`](https://github.com/SAP/connect-openui5/compare/0.7.6...0.7.7) 52 | 53 | 54 | ## 0.7.6 - 2019-03-13 55 | 56 | ### Fixes 57 | - proxy middleware 58 | - Also strip 'secure' cookie flag at the end of the header [#41](https://github.com/SAP/connect-openui5/pull/41) 59 | 60 | ### All changes 61 | [`0.7.5...0.7.6`](https://github.com/SAP/connect-openui5/compare/0.7.5...0.7.6) 62 | 63 | 64 | ## 0.7.5 - 2018-10-09 65 | 66 | ### Other changes 67 | - Update less-openui5@0.6.0 [#27](https://github.com/SAP/connect-openui5/pull/27) 68 | 69 | ### All changes 70 | [`0.7.4...0.7.5`](https://github.com/SAP/connect-openui5/compare/0.7.4...0.7.5) 71 | 72 | 73 | ## 0.7.4 - 2018-05-18 74 | 75 | ### Other changes 76 | - Update less-openui5 to v0.5.3 [#25](https://github.com/SAP/connect-openui5/pull/25) 77 | 78 | ### All changes 79 | [`0.7.3...0.7.4`](https://github.com/SAP/connect-openui5/compare/0.7.3...0.7.4) 80 | 81 | 82 | ## 0.7.3 - 2018-03-12 83 | 84 | ### Other changes 85 | - Update dependencies ([`b8d59ea`](https://github.com/SAP/connect-openui5/commit/b8d59ea8cd1e2db46b5c5f0117f02ed40aa1a097)) 86 | - Update copyright years ([`9091d54`](https://github.com/SAP/connect-openui5/commit/9091d5459126a6080a03b5db360c31d9d30c2665)) 87 | 88 | ### All changes 89 | [`0.7.2...0.7.3`](https://github.com/SAP/connect-openui5/compare/0.7.2...0.7.3) 90 | 91 | 92 | ## 0.7.2 - 2017-07-18 93 | 94 | ### Fixes 95 | - proxy middleware 96 | - remove "secure" flag from cookies [#18](https://github.com/SAP/connect-openui5/pull/18) 97 | 98 | ### All changes 99 | [`0.7.1...0.7.2`](https://github.com/SAP/connect-openui5/compare/0.7.1...0.7.2) 100 | 101 | 102 | ## 0.7.1 - 2017-06-22 103 | 104 | ### Fixes 105 | - proxy middleware 106 | - fix no_proxy patterns with * wildcard [#16](https://github.com/SAP/connect-openui5/pull/16) 107 | 108 | ### Other changes 109 | - Travis CI: Test Node.js 4, 6 and 8 with npm v5 [#17](https://github.com/SAP/connect-openui5/pull/17) 110 | 111 | ### All changes 112 | [`0.7.0...0.7.1`](https://github.com/SAP/connect-openui5/compare/0.7.0...0.7.1) 113 | 114 | 115 | ## 0.7.0 - 2017-03-23 116 | 117 | ### Breaking changes 118 | - Drop support for Node.js v0.10 [#13](https://github.com/SAP/connect-openui5/pull/13) 119 | 120 | ### Features 121 | - less middleware 122 | - Support theme scopes (Belize Themes) [#15](https://github.com/SAP/connect-openui5/pull/15) (via [SAP/less-openui5#10](https://github.com/SAP/less-openui5/pull/10)) 123 | 124 | ### All changes 125 | [`0.6.0...0.7.0`](https://github.com/SAP/connect-openui5/compare/0.6.0...0.7.0) 126 | 127 | 128 | ## 0.6.0 - 2016-04-25 129 | 130 | ### Breaking changes 131 | - less middleware 132 | - Set default of parser option `relativeUrls` to `true` [`4d5fca2 ` via less-openui5@0.2.0](https://github.com/SAP/connect-openui5/commit/4d5fca25954049eec4af53c8bd12c54d6ad020aa) (see [`00d892b `](https://github.com/SAP/less-openui5/commit/00d892b95c8c0401b8a61f1b1709dfc4a68cfa26)) 133 | 134 | ### Features 135 | - less middleware 136 | - enable inline theming parameters [`4d5fca2`](https://github.com/SAP/connect-openui5/commit/4d5fca25954049eec4af53c8bd12c54d6ad020aa) 137 | 138 | ### All changes 139 | [`0.5.0...0.6.0`](https://github.com/SAP/connect-openui5/compare/0.5.0...0.6.0) 140 | 141 | 142 | ## 0.5.0 - 2016-01-20 143 | 144 | ### Features 145 | - proxy middleware 146 | - Add support for modifying the remote location via environment variable [`46c1e56`](https://github.com/SAP/connect-openui5/commit/46c1e56db46357fee59ee072e0c82516d5c17e9e) 147 | 148 | ### All changes 149 | [`0.4.1...0.5.0`](https://github.com/SAP/connect-openui5/compare/0.4.1...0.5.0) 150 | 151 | 152 | ## 0.4.1 - 2015-09-04 153 | 154 | ### Fixes 155 | - less middleware 156 | - Extend default options rather than assign with provided options [`5ae50cd`](https://github.com/SAP/connect-openui5/commit/5ae50cd753ef5e2a3ba2807a70877ef79b6ce433) 157 | 158 | ### All changes 159 | [`0.4.0...0.4.1`](https://github.com/SAP/connect-openui5/compare/0.4.0...0.4.1) 160 | 161 | 162 | ## 0.4.0 - 2015-01-12 163 | 164 | ### Features 165 | - proxy middleware 166 | - allow passing options for [http-proxy](https://github.com/nodejitsu/node-http-proxy#options) [`6ab9920`](https://github.com/SAP/connect-openui5/commit/6ab99201d5d2439ba55017ec8211b4dd8e5ed2a9) 167 | 168 | ### All changes 169 | [`0.3.0...0.4.0`](https://github.com/SAP/connect-openui5/compare/0.3.0...0.4.0) 170 | 171 | 172 | ## 0.3.0 - 2014-11-17 173 | 174 | ### Breaking changes 175 | - context middleware 176 | - removed (not needed anymore) [`7977fde`](https://github.com/SAP/connect-openui5/commit/7977fdeaf53a6caf9f4ef4f410bd01e13927be3c) 177 | - less middleware 178 | - changed `options` argument to [less-openui5](https://github.com/SAP/less-openui5) options [`bf6d596`](https://github.com/SAP/connect-openui5/commit/bf6d596d67c5915408dc6287d15baa6a5e311c3e) 179 | 180 | ### Fixes 181 | - proxy middleware 182 | - now respects the local proxy configuration (environment variables `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) when making requests [`483e137`](https://github.com/SAP/connect-openui5/commit/483e1377caa0e90e3f4be9cc8ca91b01b4581103) 183 | - less middleware 184 | - next should not be called after ending the response [`df71ca8`](https://github.com/SAP/connect-openui5/commit/df71ca834247689fd13f8388cc5d16ff17edff47) 185 | 186 | ### All changes 187 | [`0.2.1...0.3.0`](https://github.com/SAP/connect-openui5/compare/0.2.1...0.3.0) 188 | -------------------------------------------------------------------------------- /.chglog/RELEASE.tpl.md: -------------------------------------------------------------------------------- 1 | {{ range .Versions }} 2 | {{ range .CommitGroups -}} 3 | ### {{ .Title }} 4 | {{ range .Commits -}} 5 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [`{{ .Hash.Short }}`]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Long }}) 6 | {{ end }} 7 | {{ end -}} 8 | 9 | {{- if .RevertCommits -}} 10 | ### Reverts 11 | {{ range .RevertCommits -}} 12 | - {{ .Revert.Header }} 13 | {{ end }} 14 | {{ end -}} 15 | 16 | {{- if .NoteGroups -}} 17 | {{ range .NoteGroups -}} 18 | ### {{ .Title }} 19 | {{ range .Notes }} 20 | {{ .Body }} 21 | {{ end }} 22 | {{ end -}} 23 | {{ end -}} 24 | 25 | {{ if .Tag.Previous }} 26 | ### All changes 27 | [`{{ .Tag.Previous.Name }}...{{ .Tag.Name }}`] 28 | {{ end }} 29 | 30 | {{ if .Tag.Previous -}} 31 | [`{{ .Tag.Previous.Name }}...{{ .Tag.Name }}`]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} 32 | {{ end -}} 33 | {{ end -}} 34 | -------------------------------------------------------------------------------- /.chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/SAP/connect-openui5 6 | options: 7 | commits: 8 | filters: 9 | Type: 10 | - FEATURE 11 | - FIX 12 | - PERF 13 | - DEPENDENCY 14 | - BREAKING 15 | commit_groups: 16 | title_maps: 17 | FEATURE: Features 18 | FIX: Bug Fixes 19 | PERF: Performance Improvements 20 | DEPENDENCY: Dependency Updates 21 | BREAKING: Breaking Changes 22 | header: 23 | pattern: "^\\[(\\w*)\\]\\s(?:([^\\:]*)\\:\\s)?(.*)$" 24 | pattern_maps: 25 | - Type 26 | - Scope 27 | - Subject 28 | issues: 29 | prefix: 30 | - "#" 31 | notes: 32 | keywords: 33 | - BREAKING CHANGE 34 | -------------------------------------------------------------------------------- /.chglog/release-config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: RELEASE.tpl.md 3 | info: 4 | repository_url: https://github.com/SAP/connect-openui5 5 | options: 6 | commits: 7 | filters: 8 | Type: 9 | - FEATURE 10 | - FIX 11 | - PERF 12 | - DEPENDENCY 13 | - BREAKING 14 | commit_groups: 15 | title_maps: 16 | FEATURE: Features 17 | FIX: Bug Fixes 18 | PERF: Performance Improvements 19 | DEPENDENCY: Dependency Updates 20 | BREAKING: Breaking Changes 21 | header: 22 | pattern: "^\\[(\\w*)\\]\\s(?:([^\\:]*)\\:\\s)?(.*)$" 23 | pattern_maps: 24 | - Type 25 | - Scope 26 | - Subject 27 | issues: 28 | prefix: 29 | - "#" 30 | notes: 31 | keywords: 32 | - BREAKING CHANGE 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # see http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = tab 8 | 9 | [*.{css,html,js,less,txt,json,yml,md}] 10 | trim_trailing_whitespace = true 11 | end_of_line = lf 12 | indent_size = 4 13 | insert_final_newline = true 14 | 15 | [*.{yml,yaml}] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "node": true, 4 | "es6": true 5 | }, 6 | "parserOptions": { 7 | "ecmaVersion": 8 8 | }, 9 | "extends": ["eslint:recommended", "google"], 10 | "rules": { 11 | "indent": [ 12 | "error", 13 | "tab" 14 | ], 15 | "linebreak-style": [ 16 | "error", 17 | "unix" 18 | ], 19 | "quotes": [ 20 | "error", 21 | "double", 22 | {"allowTemplateLiterals": true} 23 | ], 24 | "semi": [ 25 | "error", 26 | "always" 27 | ], 28 | "no-negated-condition": "off", 29 | "require-jsdoc": "off", 30 | "no-mixed-requires": "off", 31 | "max-len": [ 32 | "error", 33 | { 34 | "code": 120, 35 | "ignoreUrls": true, 36 | "ignoreRegExpLiterals": true 37 | } 38 | ], 39 | "no-implicit-coercion": [ 40 | 2, 41 | {"allow": ["!!"]} 42 | ], 43 | "comma-dangle": "off", 44 | "no-tabs": "off" 45 | }, 46 | "root": true 47 | }; 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: npm 8 | directory: "/" 9 | schedule: 10 | interval: weekly 11 | day: sunday 12 | time: "10:00" 13 | timezone: Etc/UCT 14 | reviewers: 15 | - matz3 16 | - svbender 17 | versioning-strategy: increase 18 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | # Execute at least once per week to get new findings without active development taking place 10 | schedule: 11 | - cron: '42 15 * * 6' 12 | 13 | jobs: 14 | codeql-analyze: 15 | name: "CodeQL Analyze" 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v3.5.2 21 | 22 | # Initializes the CodeQL tools for scanning. 23 | - name: Initialize CodeQL 24 | uses: github/codeql-action/init@v2 25 | with: 26 | languages: 'javascript' 27 | # If you wish to specify custom queries, you can do so here or in a config file. 28 | # By default, queries listed here will override any specified in a config file. 29 | # Prefix the list here with "+" to use these queries and those in the config file. 30 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 31 | 32 | # ℹ️ Command-line programs to run using the OS shell. 33 | # 📚 https://git.io/JvXDl 34 | 35 | - name: Perform CodeQL Analysis 36 | uses: github/codeql-action/analyze@v2 37 | -------------------------------------------------------------------------------- /.github/workflows/github-ci.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | test: 11 | name: General checks, tests and coverage reporting 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - uses: actions/checkout@v3.5.2 16 | 17 | - name: Use Node.js LTS 14.x 18 | uses: actions/setup-node@v3.6.0 19 | with: 20 | node-version: 14.x 21 | 22 | - name: Install dependencies 23 | run: npm ci 24 | 25 | - name: Perform checks and tests 26 | run: npm test 27 | 28 | - name: Send report to Coveralls 29 | uses: coverallsapp/github-action@v2.1.2 30 | with: 31 | github-token: ${{ secrets.GITHUB_TOKEN }} 32 | 33 | test-matrix: 34 | name: Unit tests on Node.js ${{ matrix.node-version }} and ${{ matrix.os }} 35 | strategy: 36 | fail-fast: false 37 | matrix: 38 | node-version: [16] 39 | os: [ubuntu-latest, windows-latest, macOS-latest] 40 | include: 41 | - node-version: 10 42 | os: ubuntu-latest 43 | - node-version: 12 44 | os: ubuntu-latest 45 | - node-version: 14 46 | os: ubuntu-latest 47 | runs-on: ${{ matrix.os }} 48 | steps: 49 | 50 | - uses: actions/checkout@v3.5.2 51 | 52 | - name: Use Node.js ${{ matrix.node-version }} 53 | uses: actions/setup-node@v3.6.0 54 | with: 55 | node-version: ${{ matrix.node-version }} 56 | 57 | - run: npm ci 58 | name: Install dependencies 59 | 60 | - run: npm ls --prod 61 | name: Check for missing / extraneous Dependencies 62 | 63 | - run: npm run unit 64 | name: Run unit tests 65 | -------------------------------------------------------------------------------- /.github/workflows/reuse-compliance.yml: -------------------------------------------------------------------------------- 1 | name: REUSE 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | compliance-check: 11 | name: Compliance Check 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3.5.2 15 | - name: Execute REUSE Compliance Check 16 | uses: fsfe/reuse-action@v1.1 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # CI (Azure Pipelines) xUnit test results 21 | test-results.xml 22 | 23 | # IDEs 24 | .vscode/ 25 | *.~vsdx 26 | .idea/ 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # Compiled binary addons (http://nodejs.org/api/addons.html) 32 | build/Release 33 | 34 | # Dependency directories 35 | node_modules 36 | jspm_packages 37 | 38 | # Optional npm cache directory 39 | .npm 40 | 41 | # Optional eslint cache 42 | .eslintcache 43 | 44 | # Optional REPL history 45 | .node_repl_history 46 | 47 | # Output of 'npm pack' 48 | *.tgz 49 | 50 | # Yarn Integrity file 51 | .yarn-integrity 52 | 53 | # Misc 54 | yarn.lock 55 | .DS_Store 56 | 57 | # Don't include private SSH key for deployment via Travis CI 58 | deploy_key 59 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Enforce public npm registry 2 | registry = https://registry.npmjs.org/ 3 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: connect-openui5 3 | Upstream-Contact: SAP OpenUI5 4 | Source: https://github.com/SAP/connect-openui5 5 | Disclaimer: The code in this project may include calls to APIs (“API Calls”) of 6 | SAP or third-party products or services developed outside of this project 7 | (“External Products”). 8 | “APIs” means application programming interfaces, as well as their respective 9 | specifications and implementing code that allows software to communicate with 10 | other software. 11 | API Calls to External Products are not licensed under the open source license 12 | that governs this project. The use of such API Calls and related External 13 | Products are subject to applicable additional agreements with the relevant 14 | provider of the External Products. In no event shall the open source license 15 | that governs this project grant any rights in or to any External Products,or 16 | alter, expand or supersede any terms of the applicable additional agreements. 17 | If you have a valid license agreement with SAP for the use of a particular SAP 18 | External Product, then you may make use of any API Calls included in this 19 | project’s code for that SAP External Product, subject to the terms of such 20 | license agreement. If you do not have a valid license agreement for the use of 21 | a particular SAP External Product, then you may only make use of any API Calls 22 | in this project for that SAP External Product for your internal, non-productive 23 | and non-commercial test and evaluation of such API Calls. Nothing herein grants 24 | you any rights to use or access any SAP External Product, or provide any third 25 | parties the right to use of access any SAP External Product, through API Calls. 26 | 27 | Files: * 28 | Copyright: 2014-2021 SAP SE or an SAP affiliate company and connect-openui5 contributors 29 | License: Apache-2.0 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 4 | 5 | A list of unreleased changes can be found [here](https://github.com/SAP/connect-openui5/compare/v0.10.3...HEAD). 6 | 7 | 8 | ## [v0.10.3] - 2022-11-30 9 | ### Dependency Updates 10 | - Bump less-openui5 from 0.11.2 to 0.11.3 [`0619599`](https://github.com/SAP/connect-openui5/commit/061959972e1410628fc081d3c7af75b1f3fe715d) 11 | 12 | 13 | 14 | ## [v0.10.2] - 2021-03-11 15 | ### Dependency Updates 16 | - Bump less-openui5 from 0.10.0 to 0.11.0 ([#110](https://github.com/SAP/connect-openui5/issues/110)) [`4403a88`](https://github.com/SAP/connect-openui5/commit/4403a8841f1971775bbd9d8dabd1a984c604d431) 17 | 18 | 19 | 20 | ## [v0.10.1] - 2021-01-29 21 | 22 | 23 | ## [v0.10.0] - 2020-11-06 24 | ### Breaking Changes 25 | - Require Node.js >= 10 [`8c9f87e`](https://github.com/SAP/connect-openui5/commit/8c9f87e1012bb0c6fbf2dc8e323c7ec11bfda877) 26 | 27 | ### Dependency Updates 28 | - Bump less-openui5 from 0.8.7 to 0.9.0 [`a8cdc7b`](https://github.com/SAP/connect-openui5/commit/a8cdc7bf1c82ba75217db1be50ff502ac3d380df) 29 | 30 | ### BREAKING CHANGE 31 | 32 | Support for older Node.js releases has been dropped. 33 | Only Node.js v10 or higher is supported. 34 | 35 | 36 | 37 | ## [v0.9.1] - 2020-09-10 38 | ### Bug Fixes 39 | - **proxy middleware:** Remove secure, domain, path, samesite from cookies ([#91](https://github.com/SAP/connect-openui5/issues/91)) [`e9784be`](https://github.com/SAP/connect-openui5/commit/e9784be7c40670ccbb153b7e51adccb8603446d8) 40 | 41 | 42 | 43 | ## [v0.9.0] - 2019-11-19 44 | ### Breaking Changes 45 | - **less middleware:** Remove support for 'sourceMap' / 'cleancss' options [`39fa504`](https://github.com/SAP/connect-openui5/commit/39fa504b2cbc6e8273d0712b76b64466b6f8d9ce) 46 | 47 | 48 | 49 | ## [0.8.0] - 2019-10-14 50 | ### Breaking Changes 51 | - Drop support for Node.js < 8.5 [`3aefa16`](https://github.com/SAP/connect-openui5/commit/3aefa16e1e3ecb88214ab8b79d1e2840b26f6dba) 52 | 53 | 54 | [v0.10.3]: https://github.com/SAP/connect-openui5/compare/v0.10.2...v0.10.3 55 | [v0.10.2]: https://github.com/SAP/connect-openui5/compare/v0.10.1...v0.10.2 56 | [v0.10.1]: https://github.com/SAP/connect-openui5/compare/v0.10.0...v0.10.1 57 | [v0.10.0]: https://github.com/SAP/connect-openui5/compare/v0.9.1...v0.10.0 58 | [v0.9.1]: https://github.com/SAP/connect-openui5/compare/v0.9.0...v0.9.1 59 | [v0.9.0]: https://github.com/SAP/connect-openui5/compare/0.8.0...v0.9.0 60 | [0.8.0]: https://github.com/SAP/connect-openui5/compare/0.7.7...0.8.0 61 | ## 0.7.7 - 2019-07-01 62 | 63 | ### Fixes 64 | - proxy middleware 65 | - Removing 'secure' flag of cookies [#50](https://github.com/SAP/connect-openui5/pull/50) 66 | 67 | ### All changes 68 | [`0.7.6...0.7.7`](https://github.com/SAP/connect-openui5/compare/0.7.6...0.7.7) 69 | 70 | 71 | ## 0.7.6 - 2019-03-13 72 | 73 | ### Fixes 74 | - proxy middleware 75 | - Also strip 'secure' cookie flag at the end of the header [#41](https://github.com/SAP/connect-openui5/pull/41) 76 | 77 | ### All changes 78 | [`0.7.5...0.7.6`](https://github.com/SAP/connect-openui5/compare/0.7.5...0.7.6) 79 | 80 | 81 | ## 0.7.5 - 2018-10-09 82 | 83 | ### Other changes 84 | - Update less-openui5@0.6.0 [#27](https://github.com/SAP/connect-openui5/pull/27) 85 | 86 | ### All changes 87 | [`0.7.4...0.7.5`](https://github.com/SAP/connect-openui5/compare/0.7.4...0.7.5) 88 | 89 | 90 | ## 0.7.4 - 2018-05-18 91 | 92 | ### Other changes 93 | - Update less-openui5 to v0.5.3 [#25](https://github.com/SAP/connect-openui5/pull/25) 94 | 95 | ### All changes 96 | [`0.7.3...0.7.4`](https://github.com/SAP/connect-openui5/compare/0.7.3...0.7.4) 97 | 98 | 99 | ## 0.7.3 - 2018-03-12 100 | 101 | ### Other changes 102 | - Update dependencies ([`b8d59ea`](https://github.com/SAP/connect-openui5/commit/b8d59ea8cd1e2db46b5c5f0117f02ed40aa1a097)) 103 | - Update copyright years ([`9091d54`](https://github.com/SAP/connect-openui5/commit/9091d5459126a6080a03b5db360c31d9d30c2665)) 104 | 105 | ### All changes 106 | [`0.7.2...0.7.3`](https://github.com/SAP/connect-openui5/compare/0.7.2...0.7.3) 107 | 108 | 109 | ## 0.7.2 - 2017-07-18 110 | 111 | ### Fixes 112 | - proxy middleware 113 | - remove "secure" flag from cookies [#18](https://github.com/SAP/connect-openui5/pull/18) 114 | 115 | ### All changes 116 | [`0.7.1...0.7.2`](https://github.com/SAP/connect-openui5/compare/0.7.1...0.7.2) 117 | 118 | 119 | ## 0.7.1 - 2017-06-22 120 | 121 | ### Fixes 122 | - proxy middleware 123 | - fix no_proxy patterns with * wildcard [#16](https://github.com/SAP/connect-openui5/pull/16) 124 | 125 | ### Other changes 126 | - Travis CI: Test Node.js 4, 6 and 8 with npm v5 [#17](https://github.com/SAP/connect-openui5/pull/17) 127 | 128 | ### All changes 129 | [`0.7.0...0.7.1`](https://github.com/SAP/connect-openui5/compare/0.7.0...0.7.1) 130 | 131 | 132 | ## 0.7.0 - 2017-03-23 133 | 134 | ### Breaking changes 135 | - Drop support for Node.js v0.10 [#13](https://github.com/SAP/connect-openui5/pull/13) 136 | 137 | ### Features 138 | - less middleware 139 | - Support theme scopes (Belize Themes) [#15](https://github.com/SAP/connect-openui5/pull/15) (via [SAP/less-openui5#10](https://github.com/SAP/less-openui5/pull/10)) 140 | 141 | ### All changes 142 | [`0.6.0...0.7.0`](https://github.com/SAP/connect-openui5/compare/0.6.0...0.7.0) 143 | 144 | 145 | ## 0.6.0 - 2016-04-25 146 | 147 | ### Breaking changes 148 | - less middleware 149 | - Set default of parser option `relativeUrls` to `true` [`4d5fca2 ` via less-openui5@0.2.0](https://github.com/SAP/connect-openui5/commit/4d5fca25954049eec4af53c8bd12c54d6ad020aa) (see [`00d892b `](https://github.com/SAP/less-openui5/commit/00d892b95c8c0401b8a61f1b1709dfc4a68cfa26)) 150 | 151 | ### Features 152 | - less middleware 153 | - enable inline theming parameters [`4d5fca2`](https://github.com/SAP/connect-openui5/commit/4d5fca25954049eec4af53c8bd12c54d6ad020aa) 154 | 155 | ### All changes 156 | [`0.5.0...0.6.0`](https://github.com/SAP/connect-openui5/compare/0.5.0...0.6.0) 157 | 158 | 159 | ## 0.5.0 - 2016-01-20 160 | 161 | ### Features 162 | - proxy middleware 163 | - Add support for modifying the remote location via environment variable [`46c1e56`](https://github.com/SAP/connect-openui5/commit/46c1e56db46357fee59ee072e0c82516d5c17e9e) 164 | 165 | ### All changes 166 | [`0.4.1...0.5.0`](https://github.com/SAP/connect-openui5/compare/0.4.1...0.5.0) 167 | 168 | 169 | ## 0.4.1 - 2015-09-04 170 | 171 | ### Fixes 172 | - less middleware 173 | - Extend default options rather than assign with provided options [`5ae50cd`](https://github.com/SAP/connect-openui5/commit/5ae50cd753ef5e2a3ba2807a70877ef79b6ce433) 174 | 175 | ### All changes 176 | [`0.4.0...0.4.1`](https://github.com/SAP/connect-openui5/compare/0.4.0...0.4.1) 177 | 178 | 179 | ## 0.4.0 - 2015-01-12 180 | 181 | ### Features 182 | - proxy middleware 183 | - allow passing options for [http-proxy](https://github.com/nodejitsu/node-http-proxy#options) [`6ab9920`](https://github.com/SAP/connect-openui5/commit/6ab99201d5d2439ba55017ec8211b4dd8e5ed2a9) 184 | 185 | ### All changes 186 | [`0.3.0...0.4.0`](https://github.com/SAP/connect-openui5/compare/0.3.0...0.4.0) 187 | 188 | 189 | ## 0.3.0 - 2014-11-17 190 | 191 | ### Breaking changes 192 | - context middleware 193 | - removed (not needed anymore) [`7977fde`](https://github.com/SAP/connect-openui5/commit/7977fdeaf53a6caf9f4ef4f410bd01e13927be3c) 194 | - less middleware 195 | - changed `options` argument to [less-openui5](https://github.com/SAP/less-openui5) options [`bf6d596`](https://github.com/SAP/connect-openui5/commit/bf6d596d67c5915408dc6287d15baa6a5e311c3e) 196 | 197 | ### Fixes 198 | - proxy middleware 199 | - now respects the local proxy configuration (environment variables `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) when making requests [`483e137`](https://github.com/SAP/connect-openui5/commit/483e1377caa0e90e3f4be9cc8ca91b01b4581103) 200 | - less middleware 201 | - next should not be called after ending the response [`df71ca8`](https://github.com/SAP/connect-openui5/commit/df71ca834247689fd13f8388cc5d16ff17edff47) 202 | 203 | ### All changes 204 | [`0.2.1...0.3.0`](https://github.com/SAP/connect-openui5/compare/0.2.1...0.3.0) 205 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to connect-openui5 2 | 3 | In general the contributing guidelines of OpenUI5 also apply to this project. They can be found here: 4 | https://github.com/SAP/openui5/blob/master/CONTRIBUTING.md 5 | 6 | Some parts might not be relevant for this project (e.g. the browser-specific requirements like jQuery, CSS and accessibility in the "Contribution Content Guidelines") and the contribution process is easier (pull requests will be merged directly on GitHub). 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 SAP SE or an SAP affiliate company. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, 6 | AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | 11 | 12 | "License" shall mean the terms and conditions for use, reproduction, and distribution 13 | as defined by Sections 1 through 9 of this document. 14 | 15 | 16 | 17 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 18 | owner that is granting the License. 19 | 20 | 21 | 22 | "Legal Entity" shall mean the union of the acting entity and all other entities 23 | that control, are controlled by, or are under common control with that entity. 24 | For the purposes of this definition, "control" means (i) the power, direct 25 | or indirect, to cause the direction or management of such entity, whether 26 | by contract or otherwise, or (ii) ownership of fifty percent (50%) or more 27 | of the outstanding shares, or (iii) beneficial ownership of such entity. 28 | 29 | 30 | 31 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions 32 | granted by this License. 33 | 34 | 35 | 36 | "Source" form shall mean the preferred form for making modifications, including 37 | but not limited to software source code, documentation source, and configuration 38 | files. 39 | 40 | 41 | 42 | "Object" form shall mean any form resulting from mechanical transformation 43 | or translation of a Source form, including but not limited to compiled object 44 | code, generated documentation, and conversions to other media types. 45 | 46 | 47 | 48 | "Work" shall mean the work of authorship, whether in Source or Object form, 49 | made available under the License, as indicated by a copyright notice that 50 | is included in or attached to the work (an example is provided in the Appendix 51 | below). 52 | 53 | 54 | 55 | "Derivative Works" shall mean any work, whether in Source or Object form, 56 | that is based on (or derived from) the Work and for which the editorial revisions, 57 | annotations, elaborations, or other modifications represent, as a whole, an 58 | original work of authorship. For the purposes of this License, Derivative 59 | Works shall not include works that remain separable from, or merely link (or 60 | bind by name) to the interfaces of, the Work and Derivative Works thereof. 61 | 62 | 63 | 64 | "Contribution" shall mean any work of authorship, including the original version 65 | of the Work and any modifications or additions to that Work or Derivative 66 | Works thereof, that is intentionally submitted to Licensor for inclusion in 67 | the Work by the copyright owner or by an individual or Legal Entity authorized 68 | to submit on behalf of the copyright owner. For the purposes of this definition, 69 | "submitted" means any form of electronic, verbal, or written communication 70 | sent to the Licensor or its representatives, including but not limited to 71 | communication on electronic mailing lists, source code control systems, and 72 | issue tracking systems that are managed by, or on behalf of, the Licensor 73 | for the purpose of discussing and improving the Work, but excluding communication 74 | that is conspicuously marked or otherwise designated in writing by the copyright 75 | owner as "Not a Contribution." 76 | 77 | 78 | 79 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 80 | of whom a Contribution has been received by Licensor and subsequently incorporated 81 | within the Work. 82 | 83 | 2. Grant of Copyright License. Subject to the terms and conditions of this 84 | License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 85 | no-charge, royalty-free, irrevocable copyright license to reproduce, prepare 86 | Derivative Works of, publicly display, publicly perform, sublicense, and distribute 87 | the Work and such Derivative Works in Source or Object form. 88 | 89 | 3. Grant of Patent License. Subject to the terms and conditions of this License, 90 | each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 91 | no-charge, royalty-free, irrevocable (except as stated in this section) patent 92 | license to make, have made, use, offer to sell, sell, import, and otherwise 93 | transfer the Work, where such license applies only to those patent claims 94 | licensable by such Contributor that are necessarily infringed by their Contribution(s) 95 | alone or by combination of their Contribution(s) with the Work to which such 96 | Contribution(s) was submitted. If You institute patent litigation against 97 | any entity (including a cross-claim or counterclaim in a lawsuit) alleging 98 | that the Work or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses granted to You 100 | under this License for that Work shall terminate as of the date such litigation 101 | is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the Work or 104 | Derivative Works thereof in any medium, with or without modifications, and 105 | in Source or Object form, provided that You meet the following conditions: 106 | 107 | (a) You must give any other recipients of the Work or Derivative Works a copy 108 | of this License; and 109 | 110 | (b) You must cause any modified files to carry prominent notices stating that 111 | You changed the files; and 112 | 113 | (c) You must retain, in the Source form of any Derivative Works that You distribute, 114 | all copyright, patent, trademark, and attribution notices from the Source 115 | form of the Work, excluding those notices that do not pertain to any part 116 | of the Derivative Works; and 117 | 118 | (d) If the Work includes a "NOTICE" text file as part of its distribution, 119 | then any Derivative Works that You distribute must include a readable copy 120 | of the attribution notices contained within such NOTICE file, excluding those 121 | notices that do not pertain to any part of the Derivative Works, in at least 122 | one of the following places: within a NOTICE text file distributed as part 123 | of the Derivative Works; within the Source form or documentation, if provided 124 | along with the Derivative Works; or, within a display generated by the Derivative 125 | Works, if and wherever such third-party notices normally appear. The contents 126 | of the NOTICE file are for informational purposes only and do not modify the 127 | License. You may add Your own attribution notices within Derivative Works 128 | that You distribute, alongside or as an addendum to the NOTICE text from the 129 | Work, provided that such additional attribution notices cannot be construed 130 | as modifying the License. 131 | 132 | You may add Your own copyright statement to Your modifications and may provide 133 | additional or different license terms and conditions for use, reproduction, 134 | or distribution of Your modifications, or for any such Derivative Works as 135 | a whole, provided Your use, reproduction, and distribution of the Work otherwise 136 | complies with the conditions stated in this License. 137 | 138 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 139 | Contribution intentionally submitted for inclusion in the Work by You to the 140 | Licensor shall be under the terms and conditions of this License, without 141 | any additional terms or conditions. Notwithstanding the above, nothing herein 142 | shall supersede or modify the terms of any separate license agreement you 143 | may have executed with Licensor regarding such Contributions. 144 | 145 | 6. Trademarks. This License does not grant permission to use the trade names, 146 | trademarks, service marks, or product names of the Licensor, except as required 147 | for reasonable and customary use in describing the origin of the Work and 148 | reproducing the content of the NOTICE file. 149 | 150 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to 151 | in writing, Licensor provides the Work (and each Contributor provides its 152 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 153 | KIND, either express or implied, including, without limitation, any warranties 154 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR 155 | A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness 156 | of using or redistributing the Work and assume any risks associated with Your 157 | exercise of permissions under this License. 158 | 159 | 8. Limitation of Liability. In no event and under no legal theory, whether 160 | in tort (including negligence), contract, or otherwise, unless required by 161 | applicable law (such as deliberate and grossly negligent acts) or agreed to 162 | in writing, shall any Contributor be liable to You for damages, including 163 | any direct, indirect, special, incidental, or consequential damages of any 164 | character arising as a result of this License or out of the use or inability 165 | to use the Work (including but not limited to damages for loss of goodwill, 166 | work stoppage, computer failure or malfunction, or any and all other commercial 167 | damages or losses), even if such Contributor has been advised of the possibility 168 | of such damages. 169 | 170 | 9. Accepting Warranty or Additional Liability. While redistributing the Work 171 | or Derivative Works thereof, You may choose to offer, and charge a fee for, 172 | acceptance of support, warranty, indemnity, or other liability obligations 173 | and/or rights consistent with this License. However, in accepting such obligations, 174 | You may act only on Your own behalf and on Your sole responsibility, not on 175 | behalf of any other Contributor, and only if You agree to indemnify, defend, 176 | and hold each Contributor harmless for any liability incurred by, or claims 177 | asserted against, such Contributor by reason of your accepting any such warranty 178 | or additional liability. END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following boilerplate 183 | notice, with the fields enclosed by brackets "[]" replaced with your own identifying 184 | information. (Don't include the brackets!) The text should be enclosed in 185 | the appropriate comment syntax for the file format. We also recommend that 186 | a file or class name and description of purpose be included on the same "printed 187 | page" as the copyright notice for easier identification within third-party 188 | archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | 194 | you may not use this file except in compliance with the License. 195 | 196 | You may obtain a copy of the License at 197 | 198 | http://www.apache.org/licenses/LICENSE-2.0 199 | 200 | Unless required by applicable law or agreed to in writing, software 201 | 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | 204 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 205 | 206 | See the License for the specific language governing permissions and 207 | 208 | limitations under the License. 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![OpenUI5](http://openui5.org/images/OpenUI5_new_big_side.png) 2 | 3 | [![REUSE status](https://api.reuse.software/badge/github.com/SAP/connect-openui5)](https://api.reuse.software/info/github.com/SAP/connect-openui5) 4 | [![Build Status](http://img.shields.io/travis/SAP/connect-openui5.svg?style=flat)](https://travis-ci.org/SAP/connect-openui5) 5 | [![NPM Version](http://img.shields.io/npm/v/connect-openui5.svg?style=flat)](https://www.npmjs.org/package/connect-openui5) 6 | 7 | # DEPRECATED 8 | 9 | **⚠️ This project has been deprecated in favor of [UI5 Tooling](https://sap.github.io/ui5-tooling/) and proxy solutions that are available in the form of [custom middleware extensions from the UI5 community](https://bestofui5.org/#/packages?tokens=proxy:tag).** 10 | 11 | # connect-openui5 12 | 13 | > [Connect](https://github.com/senchalabs/connect) middleware for OpenUI5. 14 | 15 | Looking for a grunt task to run a web server with this middleware? Check out [grunt-openui5](https://github.com/SAP/grunt-openui5)! 16 | 17 | ## Install 18 | 19 | ``` 20 | npm install connect-openui5 21 | ``` 22 | 23 | ## Usage 24 | 25 | ```js 26 | var connect = require('connect'); 27 | var http = require('http'); 28 | var app = connect(); 29 | 30 | var middleware = require('connect-openui5'); 31 | 32 | // Compiles LESS themes on the fly 33 | app.use(middleware.less({ 34 | rootPaths: [ 'path/to/theme/resources' ] 35 | })); 36 | 37 | // Makes sure that properties files will be served with "Content-Type: text/plain; charset=ISO-8859-1" 38 | app.use(middleware.properties()); 39 | 40 | // Provides a generic proxy to consume resources from other origins without causing CORS issues 41 | // URL-Format: /{http|https}/{host}/{path} 42 | app.use('/proxy', middleware.proxy()); 43 | 44 | // Provide discovery service (used in OpenUI5 testsuite) 45 | app.use('/discovery', middleware.discovery({ 46 | appresources: [ 'path/to/app-resources' ], 47 | resources: [ 'path/to/resources' ], 48 | testresources: [ 'path/to/test-resources' ] 49 | })); 50 | 51 | // create node.js http server and listen on port 52 | http.createServer(app).listen(3000); 53 | 54 | ``` 55 | 56 | ## less 57 | 58 | Compiles LESS themes on the fly. The results will be cached and only re-compiled if a file has changed. 59 | 60 | The following files will be handled 61 | - library.css 62 | - library-RTL.css 63 | - library-parameters.json 64 | 65 | The `library.source.less` file in the same directory will be used for compilation. 66 | 67 | ### API 68 | 69 | #### less(options) 70 | 71 | ##### options 72 | 73 | Type: `object` 74 | 75 | Options for [less-openui5](https://github.com/SAP/less-openui5#options). 76 | 77 | ## properties 78 | 79 | This middleware function ensures that properties files will be served with "Content-Type: text/plain; charset=ISO-8859-1". 80 | 81 | ## proxy 82 | 83 | Provides a generic proxy to consume resources from other origins without causing CORS issues. 84 | 85 | URL-Format `/{http|https}/{host}/{path}` 86 | 87 | ### remote location 88 | 89 | The environment variable REMOTE_LOCATION allows setting a remote location. 90 | 91 | Usage: 92 | Use a URL without the pattern `/{http|https}/{host}` and the proxy will use the environment variable REMOTE_LOCATION 93 | to determine host and additional path information. Also query parameters can be added. 94 | 95 | Sample: 96 | 97 | URL-Format: `/foo/bar?test=1234` 98 | 99 | REMOTE_LOCATION: `https://remotehost:1234/rfoo/rbar?rtest=1234` 100 | 101 | Composed URL send to remote host: `/rfoo/rbar/foo/bar?rtest=1234&test=1234`. 102 | 103 | The similar URL without using REMOTE_LOCATION would be `/https/remotehost:1234/rfoo/rbar/foo/bar?rtest=1234&test=1234` 104 | 105 | ### API 106 | 107 | #### proxy(options) 108 | 109 | ##### options 110 | 111 | Type: `object` 112 | Default: `{}` 113 | 114 | Options for [http-proxy](https://github.com/nodejitsu/node-http-proxy#options). 115 | 116 | ## discovery 117 | 118 | Provides a resource discovery service (consumed in the [OpenUI5 testsuite](https://github.com/SAP/openui5/tree/master/src/sap.ui.core/test/testsuite)). 119 | 120 | ### API 121 | 122 | #### discovery(options) 123 | 124 | ##### options 125 | 126 | ###### appresources 127 | 128 | Type: `array` of `string` 129 | 130 | Application resource folder(s), see `/app_pages`. 131 | 132 | ###### resources 133 | 134 | Type: `array` of `string` 135 | 136 | OpenUI5 library resource folder(s), see `/all_libs`. 137 | 138 | ###### testresources 139 | 140 | Type: `array` of `string` 141 | 142 | OpenUI5 library test-resource folder(s), see `/all_tests`. 143 | 144 | ### Endpoints 145 | 146 | #### /app_pages 147 | 148 | Returns all `*.html`/`*.htm` pages located in the `appresources` folder(s). 149 | 150 | ```json 151 | { 152 | "app_pages": [ 153 | { 154 | "entry": "myApp.html" 155 | } 156 | ] 157 | } 158 | ``` 159 | 160 | #### /all_libs 161 | 162 | Returns all libraries located in the `resources` folder(s). They will be identified by a `.library`. 163 | 164 | ```json 165 | { 166 | "all_libs": [ 167 | { 168 | "entry": "my/ui/lib" 169 | } 170 | ] 171 | } 172 | ``` 173 | 174 | #### /all_tests 175 | 176 | Returns all `*.html`/`*.htm` pages located in the `testresources` folder(s). 177 | 178 | ```json 179 | { 180 | "all_tests": [ 181 | { 182 | "lib": "my.ui.lib", 183 | "name": "qunit/MyControl.qunit.html", 184 | "url": "test-resources/my/ui/lib/qunit/MyControl.qunit.html" 185 | } 186 | ] 187 | } 188 | ``` 189 | 190 | ## Contributing 191 | 192 | See [CONTRIBUTING.md](CONTRIBUTING.md). 193 | 194 | ## Release History 195 | 196 | See [CHANGELOG.md](CHANGELOG.md). 197 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Issues 2 | 3 | We take security issues in our projects seriously. We appreciate your efforts to responsibly disclose your findings. 4 | 5 | Please do not report security issues directly on GitHub but using one of the channels listed below. This allows us to provide a fix before an issue can be exploited. 6 | 7 | - **Researchers/Non-SAP Customers:** Please consult SAPs [disclosure guidelines](https://wiki.scn.sap.com/wiki/display/PSR/Disclosure+Guidelines+for+SAP+Security+Advisories) and send the related information in a PGP encrypted e-mail to secure@sap.com. Find the public PGP key [here](https://www.sap.com/dmc/policies/pgp/keyblock.txt). 8 | - **SAP Customers:** If the security issue is not covered by a published security note, please report it by creating a customer message at https://launchpad.support.sap.com. 9 | 10 | Please also refer to the general [SAP security information page](https://www.sap.com/about/trust-center/security/incident-management.html). 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | 5 | discovery: require("./lib/discovery"), 6 | less: require("./lib/less"), 7 | properties: require("./lib/properties"), 8 | proxy: require("./lib/proxy") 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /lib/discovery.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const async = require("async"); 4 | const glob = require("glob"); 5 | 6 | const librariesPattern = /([A-Z0-9._%+-/]+)\/[A-Z0-9._]*\.library$/i; 7 | const testPagesPattern = /(([A-Z0-9._%+-]+\/)+([A-Z_0-9-\\.]+)\.(html|htm))$/i; 8 | const urlPattern = /\/(app_pages|all_libs|all_tests)(?:[?#].*)?$/; 9 | 10 | function eachGlobbedFile(folders, globPatterns, eachCallback, finishedCallback) { 11 | if (typeof globPatterns === "string") { 12 | globPatterns = [globPatterns]; 13 | } 14 | async.eachSeries(folders, function(folder, folderDone) { 15 | async.eachSeries(globPatterns, function(globPattern, globDone) { 16 | glob(globPattern, {cwd: folder}, function(err, files) { 17 | if (err) { 18 | globDone(err); 19 | } 20 | files.forEach(eachCallback); 21 | globDone(); 22 | }); 23 | }, folderDone); 24 | }, finishedCallback); 25 | } 26 | 27 | module.exports = function(options) { 28 | return function discoveryMiddleware(req, res, next) { 29 | const parts = urlPattern.exec(req.url); 30 | const type = parts && parts[1]; 31 | if (!type) { 32 | next(); 33 | return; 34 | } 35 | 36 | const response = []; 37 | 38 | function sendResponse() { 39 | const responseData = {}; 40 | responseData[type] = response; 41 | res.writeHead(200, { 42 | "Content-Type": "application/json" 43 | }); 44 | res.end(JSON.stringify(responseData)); 45 | } 46 | 47 | if (type === "app_pages") { 48 | eachGlobbedFile(options.appresources, "**/*.{html,htm}", function(file) { 49 | response.push({ 50 | entry: file 51 | }); 52 | }, sendResponse); 53 | } else if (type === "all_libs") { 54 | eachGlobbedFile(options.resources, ["**/.library", "**/*.library"], function(file) { 55 | const match = librariesPattern.exec(file); 56 | if (match) { 57 | response.push({ 58 | entry: match[1] 59 | }); 60 | } 61 | }, sendResponse); 62 | } else if (type === "all_tests") { 63 | const mLibs = {}; 64 | 65 | async.series([ 66 | function(done) { 67 | eachGlobbedFile(options.resources, ["**/.library", "**/*.library"], function(file) { 68 | const match = librariesPattern.exec(file); 69 | if (match) { 70 | const lib = match[1]; 71 | mLibs[lib] = lib.replace(/\//g, "."); 72 | } 73 | }, done); 74 | }, 75 | function(done) { 76 | eachGlobbedFile(options.testresources, "**/*.{html,htm}", function(file) { 77 | if (testPagesPattern.test(file)) { 78 | Object.keys(mLibs).forEach(function(lib) { 79 | if (file.indexOf(lib + "/") === 0) { 80 | response.push({ 81 | lib: mLibs[lib], 82 | name: file.substr(lib.length + 1), 83 | url: "../" + file 84 | }); 85 | } 86 | }); 87 | } 88 | }, done); 89 | } 90 | ], sendResponse); 91 | } 92 | }; 93 | }; 94 | -------------------------------------------------------------------------------- /lib/less.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const url = require("url"); 4 | const path = require("path"); 5 | const extend = require("extend"); 6 | const less = require("less-openui5"); 7 | 8 | 9 | const themeFilesPattern = /^\/(.*)\/themes\/(.*)\/library(\.css|-RTL\.css|-parameters\.json)$/; 10 | 11 | module.exports = function(options) { 12 | const builder = new less.Builder(); 13 | 14 | return function lessMiddleware(req, res, next) { 15 | // handle only GET / HEAD requests 16 | if (!/^(GET|HEAD)$/i.test(req.method)) { 17 | next(); 18 | return; 19 | } 20 | 21 | const pathname = url.parse(req.url).pathname; 22 | 23 | /* 24 | groups (array index): 25 | 1 => library name 26 | 2 => theme name 27 | 3 => theme suffix 28 | */ 29 | const pathInfo = themeFilesPattern.exec(pathname); 30 | if (!pathInfo) { 31 | next(); 32 | return; 33 | } 34 | 35 | const dirname = path.dirname(pathname); 36 | const lessInputPath = dirname + "/library.source.less"; 37 | 38 | // Only compile rtl version if requested 39 | const rtl = pathInfo[3] === "-RTL.css"; 40 | 41 | const lessOptions = extend(true, { 42 | lessInputPath: lessInputPath, 43 | library: { 44 | name: pathInfo[1].replace(/\//g, ".") 45 | }, 46 | rtl: rtl 47 | }, options); 48 | 49 | builder.build(lessOptions).then(function(result) { 50 | // serve result 51 | switch (pathInfo[3]) { 52 | case ".css": 53 | res.setHeader("Content-Type", "text/css"); 54 | res.write(result.css); 55 | break; 56 | case "-RTL.css": 57 | res.setHeader("Content-Type", "text/css"); 58 | res.write(result.cssRtl); 59 | break; 60 | case "-parameters.json": 61 | res.setHeader("Content-Type", "application/json"); 62 | res.write(JSON.stringify(result.variables, null, "\t")); 63 | break; 64 | // no default 65 | } 66 | res.end(); 67 | }, function(err) { 68 | if (err) { 69 | next(err); 70 | return; 71 | } 72 | }); 73 | }; 74 | }; 75 | -------------------------------------------------------------------------------- /lib/properties.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const url = require("url"); 4 | 5 | module.exports = function() { 6 | const rProperties = /\.properties$/; 7 | return function propertiesMiddleware(req, res, next) { 8 | // ensure that *.properties files will be served as text/plain; charset=ISO-8859-1 9 | const sUrl = url.parse(req.url).pathname; 10 | if (rProperties.test(sUrl)) { 11 | res.setHeader("Content-Type", "text/plain; charset=ISO-8859-1"); 12 | } 13 | next(); 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /lib/proxy-rewrite-cookies.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const serialize = require("cookie").serialize; 4 | const parse = require("set-cookie-parser").parse; 5 | function noop($) { 6 | return $; 7 | } 8 | 9 | module.exports = function(cookies) { 10 | // Can't use cookie.parse as it only parses 'Cookie' headers, not 'Set-Cookie' 11 | // See https://github.com/jshttp/cookie/issues/58 12 | return parse(cookies, { 13 | // Do not decode as we don't want to change the value 14 | decodeValues: false, 15 | map: false // ensure to return array 16 | }).map(function(cookie) { 17 | return serialize(cookie.name, cookie.value, { 18 | // Do not pass "secure", "domain", "path", "sameSite" to remove them from the cookie 19 | expires: cookie.expires, 20 | maxAge: cookie.maxAge, 21 | httpOnly: cookie.httpOnly, 22 | 23 | // As we didn't decode, we should also not encode the value 24 | // Encoding can't be disabled so just providing a "noop" function 25 | // that returns the given value 26 | encode: noop 27 | }); 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /lib/proxy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const url = require("url"); 4 | const httpProxy = require("http-proxy"); 5 | const rewriteCookies = require("./proxy-rewrite-cookies"); 6 | 7 | const env = { 8 | noProxy: process.env.NO_PROXY || process.env.no_proxy, 9 | httpProxy: process.env.HTTP_PROXY || process.env.http_proxy, 10 | httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy, 11 | remoteLocation: process.env.REMOTE_LOCATION || process.env.remote_location 12 | }; 13 | 14 | // inspired by https://github.com/request/request/blob/33cd9e297a00c5540e55778a24a706effc35434c/request.js#L169 15 | function getProxyUri(uri) { 16 | if (uri.protocol === "https:" && env.httpsProxy || uri.protocol === "http:" && env.httpProxy) { 17 | if (env.noProxy) { 18 | const canonicalHost = uri.host.replace(/^\.*/, "."); 19 | const port = uri.port || (uri.protocol === "https:" ? "443" : "80"); 20 | 21 | const patterns = env.noProxy.split(","); 22 | for (let i = patterns.length - 1; i >= 0; i--) { 23 | let pattern = patterns[i].trim().toLowerCase(); 24 | 25 | // don't use a proxy at all 26 | if (pattern === "*") { 27 | return null; 28 | } 29 | 30 | // Remove leading * and make sure to have exact one leading dot (.) 31 | pattern = pattern.replace(/^[*]+/, "").replace(/^\.*/, "."); 32 | 33 | // add port if no specified 34 | if (pattern.indexOf(":") === -1) { 35 | pattern += ":" + port; 36 | } 37 | 38 | // if host ends with pattern, no proxy should be used 39 | if (canonicalHost.indexOf(pattern) === canonicalHost.length - pattern.length) { 40 | return null; 41 | } 42 | } 43 | } 44 | 45 | if (uri.protocol === "https:" && env.httpsProxy) { 46 | return env.httpsProxy; 47 | } else if (uri.protocol === "http:" && env.httpProxy) { 48 | return env.httpProxy; 49 | } 50 | } 51 | 52 | return null; 53 | } 54 | 55 | 56 | function createUri(uriParam, pRemoteUri) { 57 | // parse the request url 58 | const urlPattern = /^\/(http|https)\/(.*)/; 59 | const parts = urlPattern.exec(uriParam); 60 | if (parts) { 61 | // parse target url 62 | return url.parse(parts[1] + "://" + parts[2]); 63 | } 64 | 65 | // if no absolute url is provided, check for REMOTE_LOCATION (which itself must be an absolute url) 66 | if (!pRemoteUri) { 67 | return undefined; 68 | } 69 | 70 | const remoteUri = url.parse(pRemoteUri); 71 | const uri = url.parse(uriParam); // actual url 72 | 73 | // mix both uri objects 74 | if (uri.pathname) { 75 | if ( "/" == remoteUri.pathname.substring(remoteUri.pathname.length-1)) { 76 | // remoteUri.pathname ends with / 77 | remoteUri.pathname = remoteUri.pathname + uri.pathname.substring(1); 78 | } else { 79 | remoteUri.pathname = remoteUri.pathname + uri.pathname; 80 | } 81 | } 82 | 83 | if (uri.query) { 84 | if (remoteUri.query) { 85 | remoteUri.query = remoteUri.query + (remoteUri.query.length > 0 ? "&" : "") + uri.query; 86 | } else { 87 | remoteUri.query = uri.query; 88 | } 89 | } 90 | 91 | return remoteUri; 92 | } 93 | 94 | function buildRequestUrl(uri) { 95 | let ret = uri.pathname; 96 | if (uri.query ) { 97 | ret += "?" + uri.query; 98 | } 99 | return ret; 100 | } 101 | 102 | module.exports = function(options) { 103 | const proxy = httpProxy.createProxyServer(options || {}); 104 | 105 | return function(req, res, next) { 106 | const uri = createUri(req.url, env.remoteLocation); 107 | if (!uri || !uri.host) { 108 | next(); 109 | return; 110 | } 111 | 112 | // change original request url to target url 113 | req.url = buildRequestUrl(uri); 114 | 115 | // change original host to target host 116 | req.headers.host = uri.host; 117 | 118 | // overwrite response headers 119 | res.orgWriteHead = res.writeHead; 120 | res.writeHead = function(...args) { 121 | const cookies = rewriteCookies(res.getHeader("set-cookie")); 122 | res.setHeader("set-cookie", cookies); 123 | // call original writeHead function 124 | res.orgWriteHead(...args); 125 | }; 126 | 127 | // get proxy for uri (if defined in env vars) 128 | const targetUri = getProxyUri(uri) || uri.protocol + "//" + uri.host; 129 | 130 | // proxy the request 131 | proxy.proxyRequest(req, res, { 132 | target: targetUri 133 | }, function(err) { 134 | if (err) { 135 | next(err); 136 | } 137 | }); 138 | }; 139 | }; 140 | 141 | // For testing 142 | module.exports._createUri = createUri; 143 | module.exports._buildRequestUrl = buildRequestUrl; 144 | module.exports._env = env; 145 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connect-openui5", 3 | "version": "0.10.3", 4 | "description": "Connect middleware for OpenUI5", 5 | "author": { 6 | "name": "SAP SE", 7 | "email": "openui5@sap.com", 8 | "url": "https://www.sap.com" 9 | }, 10 | "license": "Apache-2.0", 11 | "keywords": [ 12 | "openui5", 13 | "sapui5", 14 | "ui5", 15 | "connect", 16 | "server", 17 | "middleware" 18 | ], 19 | "main": "index.js", 20 | "engines": { 21 | "node": ">= 10", 22 | "npm": ">= 5" 23 | }, 24 | "scripts": { 25 | "lint": "eslint ./", 26 | "unit": "mocha test/*.js", 27 | "coverage": "nyc npm run unit", 28 | "test": "npm run lint && npm run coverage && npm run depcheck", 29 | "preversion": "npm test", 30 | "version": "git-chglog --next-tag v$npm_package_version -o CHANGELOG.md 0.8.0.. && git add CHANGELOG.md", 31 | "postversion": "git push --follow-tags", 32 | "release-note": "git-chglog -c .chglog/release-config.yml v$npm_package_version", 33 | "depcheck": "depcheck" 34 | }, 35 | "files": [ 36 | "index.js", 37 | "lib", 38 | "LICENSE.txt", 39 | "LICENSES/**", 40 | ".reuse/**" 41 | ], 42 | "nyc": { 43 | "reporter": [ 44 | "lcov", 45 | "text", 46 | "text-summary" 47 | ], 48 | "exclude": [ 49 | "coverage/**", 50 | "test/**", 51 | ".eslintrc.js" 52 | ], 53 | "check-coverage": true, 54 | "statements": 75, 55 | "branches": 55, 56 | "functions": 90, 57 | "lines": 80, 58 | "watermarks": { 59 | "statements": [ 60 | 70, 61 | 90 62 | ], 63 | "branches": [ 64 | 70, 65 | 90 66 | ], 67 | "functions": [ 68 | 70, 69 | 90 70 | ], 71 | "lines": [ 72 | 70, 73 | 90 74 | ] 75 | }, 76 | "cache": true, 77 | "all": true 78 | }, 79 | "repository": { 80 | "type": "git", 81 | "url": "git@github.com:SAP/connect-openui5.git" 82 | }, 83 | "dependencies": { 84 | "async": "^3.2.4", 85 | "cookie": "^0.4.2", 86 | "extend": "^3.0.2", 87 | "glob": "^7.2.3", 88 | "http-proxy": "^1.18.1", 89 | "less-openui5": "^0.11.6", 90 | "set-cookie-parser": "^2.6.0" 91 | }, 92 | "devDependencies": { 93 | "connect": "^3.7.0", 94 | "depcheck": "^1.4.3", 95 | "eslint": "^7.32.0", 96 | "eslint-config-google": "^0.14.0", 97 | "mocha": "^8.4.0", 98 | "nyc": "^15.1.0", 99 | "serve-static": "^1.15.0" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /test/discovery_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const http = require("http"); 5 | const assert = require("assert"); 6 | const connect = require("connect"); 7 | const discovery = require("../").discovery; 8 | 9 | describe("discovery middleware", function() { 10 | it("should provide \"app_pages\" json response", function(done) { 11 | const app = connect(); 12 | 13 | app.use("/discovery", discovery({ 14 | appresources: [ 15 | "test/fixtures/discovery/app-resources1", 16 | "test/fixtures/discovery/app-resources2" 17 | ] 18 | })); 19 | 20 | const server = http.createServer(app).listen(8080); 21 | 22 | http.get("http://localhost:8080/discovery/app_pages", function(res) { 23 | let responseData = ""; 24 | res.on("data", function(data) { 25 | responseData += data; 26 | }); 27 | res.on("end", function() { 28 | assert.equal(responseData, JSON.stringify({ 29 | "app_pages": [ 30 | { 31 | entry: "index.html" 32 | }, 33 | { 34 | entry: "foo/bar.htm" 35 | } 36 | ] 37 | })); 38 | 39 | server.close(); 40 | done(); 41 | }); 42 | }); 43 | }); 44 | 45 | it("should provide \"all_libs\" json response", function(done) { 46 | const app = connect(); 47 | 48 | app.use("/discovery", discovery({ 49 | resources: [ 50 | "test/fixtures/discovery/resources1", 51 | "test/fixtures/discovery/resources2", 52 | "test/fixtures/discovery/resources3" 53 | ] 54 | })); 55 | 56 | const server = http.createServer(app).listen(8080); 57 | 58 | http.get("http://localhost:8080/discovery/all_libs", function(res) { 59 | let responseData = ""; 60 | res.on("data", function(data) { 61 | responseData += data; 62 | }); 63 | res.on("end", function() { 64 | assert.equal(responseData, JSON.stringify({ 65 | "all_libs": [ 66 | { 67 | entry: "my/ui/lib" 68 | }, 69 | { 70 | entry: "my/legacy/ui/lib" 71 | }, 72 | { 73 | entry: "my/ui/l" 74 | } 75 | ] 76 | })); 77 | 78 | server.close(); 79 | done(); 80 | }); 81 | }); 82 | }); 83 | 84 | it("should provide \"all_tests\" json response", function(done) { 85 | const app = connect(); 86 | 87 | app.use("/discovery", discovery({ 88 | resources: [ 89 | "test/fixtures/discovery/resources1", 90 | "test/fixtures/discovery/resources2", 91 | "test/fixtures/discovery/resources3" 92 | ], 93 | testresources: [ 94 | "test/fixtures/discovery/test-resources1", 95 | "test/fixtures/discovery/test-resources2", 96 | "test/fixtures/discovery/test-resources3" 97 | ] 98 | })); 99 | 100 | const server = http.createServer(app).listen(8080); 101 | 102 | http.get("http://localhost:8080/discovery/all_tests", function(res) { 103 | let responseData = ""; 104 | res.on("data", function(data) { 105 | responseData += data; 106 | }); 107 | res.on("end", function() { 108 | assert.equal(responseData, JSON.stringify({ 109 | "all_tests": [ 110 | { 111 | lib: "my.ui.lib", 112 | name: "qunit/MyControl.qunit.html", 113 | url: "../my/ui/lib/qunit/MyControl.qunit.html" 114 | }, 115 | { 116 | lib: "my.legacy.ui.lib", 117 | name: "MyControl.htm", 118 | url: "../my/legacy/ui/lib/MyControl.htm" 119 | }, 120 | { 121 | lib: "my.ui.l", 122 | name: "qunit/MyControl3.qunit.html", 123 | url: "../my/ui/l/qunit/MyControl3.qunit.html" 124 | } 125 | ] 126 | })); 127 | 128 | server.close(); 129 | done(); 130 | }); 131 | }); 132 | }); 133 | }); 134 | -------------------------------------------------------------------------------- /test/fixtures/discovery/app-resources1/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/app-resources1/index.html -------------------------------------------------------------------------------- /test/fixtures/discovery/app-resources2/foo/bar.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/app-resources2/foo/bar.htm -------------------------------------------------------------------------------- /test/fixtures/discovery/resources1/my/ui/lib/.library: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/resources1/my/ui/lib/.library -------------------------------------------------------------------------------- /test/fixtures/discovery/resources2/my/legacy/ui/lib/my.legacy.ui.lib.library: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/resources2/my/legacy/ui/lib/my.legacy.ui.lib.library -------------------------------------------------------------------------------- /test/fixtures/discovery/resources3/my/ui/l/.library: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/resources3/my/ui/l/.library -------------------------------------------------------------------------------- /test/fixtures/discovery/test-resources1/my/ui/lib/qunit/MyControl.qunit.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/test-resources1/my/ui/lib/qunit/MyControl.qunit.html -------------------------------------------------------------------------------- /test/fixtures/discovery/test-resources2/my/legacy/ui/lib/MyControl.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/test-resources2/my/legacy/ui/lib/MyControl.htm -------------------------------------------------------------------------------- /test/fixtures/discovery/test-resources3/my/ui/l/qunit/MyControl3.qunit.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/connect-openui5/d9a4d0625342068cf2313effb6a69a2e34aa8330/test/fixtures/discovery/test-resources3/my/ui/l/qunit/MyControl3.qunit.html -------------------------------------------------------------------------------- /test/fixtures/less/test/themes/mytheme/library.source.less: -------------------------------------------------------------------------------- 1 | @myVar: #000000; 2 | 3 | .myRule { 4 | color: @myVar; 5 | float: left; 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/properties/test.properties: -------------------------------------------------------------------------------- 1 | FOO=B\u00C4R 2 | -------------------------------------------------------------------------------- /test/less_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const http = require("http"); 5 | const assert = require("assert"); 6 | const connect = require("connect"); 7 | const less = require("../").less; 8 | 9 | describe("less middleware", function() { 10 | it("should return \"library.css\" with correct content", function(done) { 11 | const app = connect(); 12 | 13 | app.use(less({ 14 | rootPaths: ["test/fixtures/less"] 15 | })); 16 | 17 | const server = http.createServer(app).listen(8080); 18 | 19 | http.get("http://localhost:8080/test/themes/mytheme/library.css", function(res) { 20 | assert.equal(res.headers["content-type"], "text/css"); 21 | 22 | let responseData = ""; 23 | 24 | res.on("data", function(data) { 25 | responseData += data; 26 | }); 27 | 28 | res.on("end", function() { 29 | assert.equal( 30 | responseData, ".myRule {\n color: #000000;\n float: left;\n}\n\n" + 31 | "/* Inline theming parameters */\n" + 32 | "#sap-ui-theme-test{" + 33 | "background-image:url('data:text/plain;utf-8,%7B%22myVar%22%3A%22%23000000%22%7D')}\n" 34 | ); 35 | server.close(); 36 | done(); 37 | }); 38 | }); 39 | }); 40 | 41 | it("should return \"library-RTL.css\" with correct content", function(done) { 42 | const app = connect(); 43 | 44 | app.use(less({ 45 | rootPaths: ["test/fixtures/less"] 46 | })); 47 | 48 | const server = http.createServer(app).listen(8080); 49 | 50 | http.get("http://localhost:8080/test/themes/mytheme/library-RTL.css", function(res) { 51 | assert.equal(res.headers["content-type"], "text/css"); 52 | 53 | let responseData = ""; 54 | 55 | res.on("data", function(data) { 56 | responseData += data; 57 | }); 58 | 59 | res.on("end", function() { 60 | assert.equal( 61 | responseData, ".myRule {\n color: #000000;\n float: right;\n}\n\n" + 62 | "/* Inline theming parameters */\n" + 63 | "#sap-ui-theme-test{" + 64 | "background-image:url('data:text/plain;utf-8,%7B%22myVar%22%3A%22%23000000%22%7D')}\n" 65 | ); 66 | server.close(); 67 | done(); 68 | }); 69 | }); 70 | }); 71 | 72 | it("should return \"library-parameters.json\" with correct content", function(done) { 73 | const app = connect(); 74 | 75 | app.use(less({ 76 | rootPaths: ["test/fixtures/less"] 77 | })); 78 | 79 | const server = http.createServer(app).listen(8080); 80 | 81 | http.get("http://localhost:8080/test/themes/mytheme/library-parameters.json", function(res) { 82 | assert.equal(res.headers["content-type"], "application/json"); 83 | 84 | let responseData = ""; 85 | 86 | res.on("data", function(data) { 87 | responseData += data; 88 | }); 89 | 90 | res.on("end", function() { 91 | assert.equal(responseData, JSON.stringify({ 92 | myVar: "#000000" 93 | }, null, "\t")); 94 | server.close(); 95 | done(); 96 | }); 97 | }); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /test/mergeUrls_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const proxy = require("../").proxy; 5 | const assert = require("assert"); 6 | 7 | function test(sRemoteLocation, pUrl, expected) { 8 | const uri = proxy._createUri(pUrl, sRemoteLocation); 9 | const url = proxy._buildRequestUrl(uri); 10 | assert.equal(url, expected); 11 | } 12 | 13 | describe("test create URL", function() { 14 | it("no path && no path", function() { 15 | test("http://localhost:1234", "", "/"); 16 | }); 17 | 18 | it("no path / && no path", function() { 19 | test("http://localhost:1234", "/", "/"); 20 | }); 21 | 22 | 23 | it("path && no path", function() { 24 | test("http://localhost:1234", "/foo/bar", "/foo/bar"); 25 | }); 26 | 27 | it("path && path", function() { 28 | test("http://localhost:1234/rfoo/rbar", "/foo/bar", "/rfoo/rbar/foo/bar"); 29 | }); 30 | 31 | 32 | it("path && query", function() { 33 | test("http://localhost:1234?rtest=1234", "/foo/bar", "/foo/bar?rtest=1234"); 34 | }); 35 | 36 | it("path && / query", function() { 37 | test("http://localhost:1234/?rtest=1234", "/foo/bar", "/foo/bar?rtest=1234"); 38 | }); 39 | 40 | it("path && path query", function() { 41 | test("http://localhost:1234/rfoo/rbar?rtest=1234", "/foo/bar", "/rfoo/rbar/foo/bar?rtest=1234"); 42 | }); 43 | 44 | it("path && path / query", function() { 45 | test("http://localhost:1234/rfoo/rbar/?rtest=1234", "/foo/bar", "/rfoo/rbar/foo/bar?rtest=1234"); 46 | }); 47 | 48 | 49 | it("query && path", function() { 50 | test("http://localhost:1234/rfoo/rbar", "?test=1234", "/rfoo/rbar?test=1234"); 51 | }); 52 | 53 | it("query path && query", function() { 54 | test("http://localhost:1234?rtest=1234", "/foo/bar?test=1234", "/foo/bar?rtest=1234&test=1234"); 55 | }); 56 | 57 | it("query path && / query", function() { 58 | test("http://localhost:1234/?rtest=1234", "/foo/bar?test=1234", "/foo/bar?rtest=1234&test=1234"); 59 | }); 60 | 61 | 62 | it("query path && path query", function() { 63 | test("http://localhost:1234/rfoo/rbar?rtest=1234", "/foo/bar?test=1234", "/rfoo/rbar/foo/bar?rtest=1234&test=1234"); 64 | }); 65 | 66 | it("query path && path / query", function() { 67 | test("http://localhost:1234/rfoo/rbar/?rtest=1234", "/foo/bar?test=1234", "/rfoo/rbar/foo/bar?rtest=1234&test=1234"); 68 | }); 69 | 70 | it("query path && path / query", function() { 71 | test("http://localhost:1234/rfoo/rbar/?rtest1=1234&rtest2=4567", "/foo/bar?test1=1234&test2=4567", "/rfoo/rbar/foo/bar?rtest1=1234&rtest2=4567&test1=1234&test2=4567"); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /test/properties_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const http = require("http"); 5 | const assert = require("assert"); 6 | const connect = require("connect"); 7 | const serveStatic = require("serve-static"); 8 | const properties = require("../").properties; 9 | 10 | describe("properties middleware", function() { 11 | it("should return \"test.properties\" with correct Content-Type header", function(done) { 12 | const app = connect(); 13 | 14 | app.use(properties()); 15 | app.use("/", serveStatic("test/fixtures/properties")); 16 | 17 | const server = http.createServer(app).listen(8080); 18 | 19 | http.get("http://localhost:8080/test.properties", function(res) { 20 | assert.equal(res.headers["content-type"], "text/plain; charset=ISO-8859-1"); 21 | 22 | let responseData = ""; 23 | 24 | res.on("data", function(data) { 25 | responseData += data; 26 | }); 27 | 28 | res.on("end", function() { 29 | assert.equal(responseData.replace(/(\n)$/, ""), "FOO=B\\u00C4R"); 30 | server.close(); 31 | done(); 32 | }); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/proxy-rewrite-cookies_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const assert = require("assert"); 5 | const rewriteCookies = require("../lib/proxy-rewrite-cookies"); 6 | 7 | describe("proxy-rewrite-cookies", function() { 8 | it("should return empty array when no value is provided", function() { 9 | assert.deepEqual(rewriteCookies(), []); 10 | }); 11 | it("should return empty array when empty string is provided", function() { 12 | assert.deepEqual(rewriteCookies(""), []); 13 | }); 14 | it("should return empty array when empty array is provided", function() { 15 | assert.deepEqual(rewriteCookies([]), []); 16 | }); 17 | it("should return cookie with only key / value", function() { 18 | assert.deepEqual(rewriteCookies("foo=bar"), ["foo=bar"]); 19 | }); 20 | it("should return multiple cookies with only key / value", function() { 21 | assert.deepEqual(rewriteCookies(["foo=1", "bar=2"]), ["foo=1", "bar=2"]); 22 | }); 23 | it("should remove secure attribute", function() { 24 | assert.deepEqual(rewriteCookies(["foo=bar; Secure;"]), ["foo=bar"]); 25 | }); 26 | it("should remove domain attribute", function() { 27 | assert.deepEqual(rewriteCookies(["foo=bar; Domain=example.com;"]), ["foo=bar"]); 28 | }); 29 | it("should remove path attribute", function() { 30 | assert.deepEqual(rewriteCookies(["foo=bar; Path=/foo;"]), ["foo=bar"]); 31 | }); 32 | it("should remove samesite attribute", function() { 33 | assert.deepEqual(rewriteCookies(["foo=bar; SameSite=Lax;"]), ["foo=bar"]); 34 | }); 35 | it("should NOT remove Expires attribute", function() { 36 | assert.deepEqual(rewriteCookies( 37 | ["foo=bar; Expires=Fri, 09-Oct-2020 10:00:00 GMT;"]), 38 | ["foo=bar; Expires=Fri, 09 Oct 2020 10:00:00 GMT"]); 39 | }); 40 | it("should NOT remove Max-Age attribute", function() { 41 | assert.deepEqual(rewriteCookies( 42 | ["foo=bar; Max-Age=123;"]), 43 | ["foo=bar; Max-Age=123"]); 44 | }); 45 | it("should NOT remove HttpOnly attribute", function() { 46 | assert.deepEqual(rewriteCookies( 47 | ["foo=bar; HttpOnly;"]), 48 | ["foo=bar; HttpOnly"]); 49 | }); 50 | it("should handle all attributes at once", function() { 51 | assert.deepEqual(rewriteCookies( 52 | ["foo=bar; Secure; Domain=example.com; Expires=Fri, 09-Oct-2020 10:00:00 GMT; " + 53 | "Path=/foo; Max-Age=123; SameSite=Lax; HttpOnly;"]), 54 | ["foo=bar; Max-Age=123; Expires=Fri, 09 Oct 2020 10:00:00 GMT; HttpOnly"]); 55 | }); 56 | it("should not change the value (no decoding / encoding)", function() { 57 | assert.deepEqual(rewriteCookies( 58 | ["foo=bar=1"]), 59 | ["foo=bar=1"]); 60 | assert.deepEqual(rewriteCookies( 61 | ["equation=E%3Dmc%5E2"]), 62 | ["equation=E%3Dmc%5E2"]); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/proxy_ignore_remote_location_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const http = require("http"); 5 | const assert = require("assert"); 6 | const connect = require("connect"); 7 | 8 | // avoid spawning a new process 9 | delete require.cache[require.resolve("../lib/proxy")]; 10 | process.env.REMOTE_LOCATION = "http://localhost:8085"; 11 | const proxy = require("../lib/proxy"); 12 | delete require.cache[require.resolve("../lib/proxy")]; 13 | 14 | describe("IGNORE remote location", function() { 15 | it("should proxy from one server to the server and IGNORE remote location", function(fnDone) { 16 | // check environment 17 | assert.equal(proxy._env.remoteLocation, "http://localhost:8085"); 18 | 19 | const sExpectedResponse = "All ok!"; 20 | const sExpectedPath = "/foo/bar?pA=1&pB=2"; 21 | const iExpectedStatusCode = 200; 22 | const oAppToBeProxied = connect(); 23 | let sActualResponse = ""; 24 | let sActualPath; 25 | let iActualStatusCode; 26 | 27 | oAppToBeProxied.use(function(oRequest, oResponse) { 28 | // no x-forwarded headers expected (wasn't configured in proxy) 29 | assert.equal(oRequest.headers["x-forwarded-for"], undefined); 30 | assert.equal(oRequest.headers["x-forwarded-port"], undefined); 31 | assert.equal(oRequest.headers["x-forwarded-proto"], undefined); 32 | sActualPath = oRequest.url; 33 | oResponse.end(sExpectedResponse); 34 | }); 35 | 36 | const oServerToBeProxied = http.createServer(oAppToBeProxied); 37 | oServerToBeProxied.listen(8080); 38 | 39 | const oProxyApp = connect(); 40 | oProxyApp.use(proxy()); 41 | const oProxyServer = http.createServer(oProxyApp); 42 | oProxyServer.listen(9000); 43 | oServerToBeProxied.on("close", function() { 44 | oProxyServer.close(); 45 | }); 46 | 47 | // should still proxy to port 8080 and not to port 8085 48 | http.get("http://localhost:9000/http/localhost:8080" + sExpectedPath, function(oResponse) { 49 | oResponse.on("data", function(oData) { 50 | sActualResponse += oData; 51 | }); 52 | iActualStatusCode = oResponse.statusCode; 53 | oResponse.on("end", function() { 54 | assert.equal(sActualPath, sExpectedPath); 55 | assert.equal(sActualResponse, sExpectedResponse); 56 | assert.equal(iActualStatusCode, iExpectedStatusCode); 57 | oProxyServer.on("close", fnDone); 58 | oServerToBeProxied.close(); 59 | }); 60 | }); 61 | }); 62 | }); 63 | 64 | -------------------------------------------------------------------------------- /test/proxy_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const http = require("http"); 5 | const assert = require("assert"); 6 | const connect = require("connect"); 7 | const proxy = require("../").proxy; 8 | 9 | describe("proxy middleware should proxy generic requests", function() { 10 | it("should proxy from one server to the other", function(done) { 11 | const sExpectedResponse = "All ok!"; 12 | const sExpectedPath = "/foo/bar"; 13 | const iExpectedStatusCode = 200; 14 | const oAppToBeProxied = connect(); 15 | let sActualResponse = ""; 16 | let sActualPath; 17 | let iActualStatusCode; 18 | 19 | oAppToBeProxied.use(function(oRequest, oResponse) { 20 | // no x-forwareded headers expected (wasn't configured in proxy) 21 | assert.equal(oRequest.headers["x-forwarded-for"], undefined); 22 | assert.equal(oRequest.headers["x-forwarded-port"], undefined); 23 | assert.equal(oRequest.headers["x-forwarded-proto"], undefined); 24 | sActualPath = oRequest.url; 25 | oResponse.setHeader("Set-Cookie", [ 26 | "a=b; Secure; HttpOnly; Max-Age=5; SameSite=Strict", 27 | "c=d; Domain=example.com; HttpOnly; Expires=expires=Fri, 09-Oct-2020 10:00:00 GMT; Path=/foo" 28 | ]); 29 | oResponse.end(sExpectedResponse); 30 | }); 31 | 32 | const oServerToBeProxied = http.createServer(oAppToBeProxied); 33 | oServerToBeProxied.listen(8080); 34 | 35 | const oProxyApp = connect(); 36 | oProxyApp.use(proxy()); 37 | const oProxyServer = http.createServer(oProxyApp); 38 | oProxyServer.listen(9000); 39 | 40 | http.get("http://localhost:9000/http/localhost:8080" + sExpectedPath, function(oResponse) { 41 | oResponse.on("data", function(oData) { 42 | sActualResponse += oData; 43 | }); 44 | iActualStatusCode = oResponse.statusCode; 45 | oResponse.on("end", function() { 46 | assert.equal(sActualPath, sExpectedPath); 47 | assert.equal(sActualResponse, sExpectedResponse); 48 | assert.equal(iActualStatusCode, iExpectedStatusCode); 49 | 50 | const cookies = oResponse.headers["set-cookie"]; 51 | ["secure", "domain", "path", "samesite"].forEach(function(attribute) { 52 | const hasAttribute = cookies.some(function(cookie) { 53 | return cookie.toLowerCase().includes(attribute); 54 | }); 55 | assert.ok(!hasAttribute, attribute + " attribute should be removed from the cookies"); 56 | }); 57 | 58 | oServerToBeProxied.close(); 59 | oProxyServer.close(); 60 | done(); 61 | }); 62 | }); 63 | }); 64 | it("should proxy by respecting custom options", function(done) { 65 | const sExpectedResponse = "All ok!"; 66 | const sExpectedPath = "/foo/bar"; 67 | const iExpectedStatusCode = 200; 68 | const oAppToBeProxied = connect(); 69 | let sActualResponse = ""; 70 | let sActualPath; 71 | let iActualStatusCode; 72 | 73 | oAppToBeProxied.use(function(oRequest, oResponse) { 74 | // x-forwareded headers are expected (see xfwd option in proxy config) 75 | assert( 76 | oRequest.headers["x-forwarded-for"] === "127.0.0.1" || 77 | oRequest.headers["x-forwarded-for"] === "::ffff:127.0.0.1" 78 | ); 79 | assert.equal(oRequest.headers["x-forwarded-port"], "8080"); 80 | assert.equal(oRequest.headers["x-forwarded-proto"], "http"); 81 | sActualPath = oRequest.url; 82 | oResponse.end(sExpectedResponse); 83 | }); 84 | 85 | const oServerToBeProxied = http.createServer(oAppToBeProxied); 86 | oServerToBeProxied.listen(8080); 87 | 88 | const oProxyApp = connect(); 89 | oProxyApp.use(proxy({ 90 | xfwd: true 91 | })); 92 | const oProxyServer = http.createServer(oProxyApp); 93 | oProxyServer.listen(9000); 94 | 95 | http.get("http://localhost:9000/http/localhost:8080" + sExpectedPath, function(oResponse) { 96 | oResponse.on("data", function(oData) { 97 | sActualResponse += oData; 98 | }); 99 | iActualStatusCode = oResponse.statusCode; 100 | oResponse.on("end", function() { 101 | assert.equal(sActualPath, sExpectedPath); 102 | assert.equal(sActualResponse, sExpectedResponse); 103 | assert.equal(iActualStatusCode, iExpectedStatusCode); 104 | 105 | oServerToBeProxied.close(); 106 | oProxyServer.close(); 107 | done(); 108 | }); 109 | }); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/proxy_use_remote_location_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | "use strict"; 3 | 4 | const http = require("http"); 5 | const assert = require("assert"); 6 | const connect = require("connect"); 7 | 8 | // avoid spawning a new process 9 | delete require.cache[require.resolve("../lib/proxy")]; 10 | process.env.REMOTE_LOCATION = "http://localhost:8080"; 11 | const proxy = require("../lib/proxy"); 12 | delete require.cache[require.resolve("../lib/proxy")]; 13 | 14 | describe("USE remote location", function() { 15 | it("should proxy from one server to the server and USE remote location", function(fnDone) { 16 | // check environment 17 | assert.equal(proxy._env.remoteLocation, "http://localhost:8080"); 18 | 19 | const sExpectedResponse = "All ok!"; 20 | const sExpectedPath = "/foo/bar?pA=1&pB=2"; 21 | const iExpectedStatusCode = 200; 22 | const oAppToBeProxied = connect(); 23 | let sActualResponse = ""; 24 | let sActualPath; 25 | let iActualStatusCode; 26 | 27 | oAppToBeProxied.use(function(oRequest, oResponse) { 28 | // no x-forwarded headers expected (wasn't configured in proxy) 29 | assert.equal(oRequest.headers["x-forwarded-for"], undefined); 30 | assert.equal(oRequest.headers["x-forwarded-port"], undefined); 31 | assert.equal(oRequest.headers["x-forwarded-proto"], undefined); 32 | sActualPath = oRequest.url; 33 | oResponse.end(sExpectedResponse); 34 | }); 35 | 36 | const oServerToBeProxied = http.createServer(oAppToBeProxied); 37 | oServerToBeProxied.listen(8080); 38 | 39 | const oProxyApp = connect(); 40 | oProxyApp.use(proxy()); 41 | const oProxyServer = http.createServer(oProxyApp); 42 | oProxyServer.listen(9000); 43 | oServerToBeProxied.on("close", function() { 44 | oProxyServer.close(); 45 | }); 46 | 47 | // should proxy to port 8080 48 | http.get("http://localhost:9000" + sExpectedPath, function(oResponse) { 49 | oResponse.on("data", function(oData) { 50 | sActualResponse += oData; 51 | }); 52 | iActualStatusCode = oResponse.statusCode; 53 | oResponse.on("end", function() { 54 | assert.equal(sActualPath, sExpectedPath); 55 | assert.equal(sActualResponse, sExpectedResponse); 56 | assert.equal(iActualStatusCode, iExpectedStatusCode); 57 | oProxyServer.on("close", fnDone); 58 | oServerToBeProxied.close(); 59 | }); 60 | }); 61 | }); 62 | }); 63 | 64 | --------------------------------------------------------------------------------