diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..12cf1111232 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# https://editorconfig.org +root = true + +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[{*.js,*.json,*.yml}] +indent_size = 2 +indent_style = space diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000000..62562b74a3b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +coverage +node_modules diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 00000000000..f9359bf2892 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,14 @@ +root: true +env: + es2022: true + node: true +rules: + eol-last: error + eqeqeq: [error, allow-null] + indent: [error, 2, { MemberExpression: "off", SwitchCase: 1 }] + no-trailing-spaces: error + no-unused-vars: [error, { vars: all, args: none, ignoreRestSiblings: true }] + no-restricted-globals: + - error + - name: Buffer + message: Use `import { Buffer } from "node:buffer"` instead of the global Buffer. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..a6096a49b45 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + time: "23:00" + timezone: Europe/London + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..dab7815960c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,117 @@ +name: ci + +on: + push: + branches: + - master + - develop + - '4.x' + - '5.x' + - '5.0' + paths-ignore: + - '*.md' + pull_request: + workflow_dispatch: + +permissions: + contents: read + +# Cancel in progress workflows +# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run +concurrency: + group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: 'lts/*' + + - name: Install dependencies + run: npm install --ignore-scripts --include=dev + + - name: Run lint + run: npm run lint + + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + node-version: [18, 19, 20, 21, 22, 23, 24, 25] + # Node.js release schedule: https://nodejs.org/en/about/releases/ + + name: Node.js ${{ matrix.node-version }} - ${{matrix.os}} + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: ${{ matrix.node-version }} + + - name: Configure npm loglevel + run: | + npm config set loglevel error + shell: bash + + - name: Install dependencies + run: npm install + + - name: Output Node and NPM versions + run: | + echo "Node.js version: $(node -v)" + echo "NPM version: $(npm -v)" + + - name: Run tests + shell: bash + run: npm run test-ci + + - name: Upload code coverage + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }} + path: ./coverage/lcov.info + retention-days: 1 + + coverage: + needs: test + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Install lcov + shell: bash + run: sudo apt-get -y install lcov + + - name: Collect coverage reports + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + path: ./coverage + pattern: coverage-node-* + + - name: Merge coverage reports + shell: bash + run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info + + - name: Upload coverage report + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2.3.6 + with: + file: ./lcov.info diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000000..1ac121c027f --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,74 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["master"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["master"] + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [javascript, actions] + + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 + with: + languages: ${{ matrix.language }} + config: | + paths-ignore: + - test + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + # - name: Autobuild + # uses: github/codeql-action/autobuild@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 diff --git a/.github/workflows/legacy.yml b/.github/workflows/legacy.yml new file mode 100644 index 00000000000..1df70694732 --- /dev/null +++ b/.github/workflows/legacy.yml @@ -0,0 +1,101 @@ +name: legacy + +on: + push: + branches: + - master + - develop + - '4.x' + - '5.x' + - '5.0' + paths-ignore: + - '*.md' + pull_request: + paths-ignore: + - '*.md' + workflow_dispatch: + +permissions: + contents: read + +# Cancel in progress workflows +# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run +concurrency: + group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + node-version: [16, 17] + # Node.js release schedule: https://nodejs.org/en/about/releases/ + + name: Node.js ${{ matrix.node-version }} - ${{matrix.os}} + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: ${{ matrix.node-version }} + + - name: Configure npm loglevel + run: | + npm config set loglevel error + shell: bash + + - name: Install dependencies + run: npm install + + - name: Output Node and NPM versions + run: | + echo "Node.js version: $(node -v)" + echo "NPM version: $(npm -v)" + + - name: Run tests + shell: bash + run: npm run test-ci + + - name: Upload code coverage + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }} + path: ./coverage/lcov.info + retention-days: 1 + + coverage: + needs: test + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Install lcov + shell: bash + run: sudo apt-get -y install lcov + + - name: Collect coverage reports + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + path: ./coverage + pattern: coverage-node-* + + - name: Merge coverage reports + shell: bash + run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info + + - name: Upload coverage report + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2.3.6 + with: + file: ./lcov.info diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000000..9cbd54487d8 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,72 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '16 21 * * 1' + push: + branches: [ "master" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 + with: + sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 9723e60591d..768368cd652 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,20 @@ -# OS X -.DS_Store* -Icon? -._* - -# Windows -Thumbs.db -ehthumbs.db -Desktop.ini - -# Linux -.directory -*~ - - # npm node_modules +package-lock.json +npm-shrinkwrap.json *.log *.gz +# Yarn +yarn-error.log +yarn.lock # Coveralls +.nyc_output coverage # Benchmarking benchmarks/graphs + +# ignore additional files using core.excludesFile +# https://git-scm.com/docs/gitignore diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..43c97e719a5 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index df087b4a0f7..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: node_js -node_js: - - "0.10" - - "0.12" - - "1.0" - - "1.8" - - "2.0" - - "2.3" -sudo: false -before_install: "npm rm --save-dev connect-redis" -script: "npm run-script test-ci" -after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" diff --git a/Contributing.md b/Contributing.md deleted file mode 100644 index 6dab84f125d..00000000000 --- a/Contributing.md +++ /dev/null @@ -1,25 +0,0 @@ - -## Website Issues - -Issues for the expressjs.com website go here https://github.com/strongloop/expressjs.com - -## PRs and Code contributions - -* Tests must pass. -* Follow existing coding style. -* If you fix a bug, add a test. - - -## Issues which are questions - -We will typically close any vague issues or questions that are specific to some app you are writing. Please double check the docs and other references before being trigger happy with posting a question issue. - -Things that will help get your question issue looked at: - -* Full and runnable JS code. -* Clear description of the problem or unexpected behavior. -* Clear description of the expected result. -* Steps you have taken to debug it yourself. - -If you post a question and do not outline the above items or make it easy for us to understand and reproduce your issue, it will be closed. - diff --git a/History.md b/History.md index 3362daefb49..5b6cba51ed8 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,854 @@ +5.1.0 / 2025-03-31 +======================== + +* Add support for `Uint8Array` in `res.send()` +* Add support for ETag option in `res.sendFile()` +* Add support for multiple links with the same rel in `res.links()` +* Add funding field to package.json +* perf: use loop for acceptParams +* refactor: prefix built-in node module imports +* deps: remove `setprototypeof` +* deps: remove `safe-buffer` +* deps: remove `utils-merge` +* deps: remove `methods` +* deps: remove `depd` +* deps: `debug@^4.4.0` +* deps: `body-parser@^2.2.0` +* deps: `router@^2.2.0` +* deps: `content-type@^1.0.5` +* deps: `finalhandler@^2.1.0` +* deps: `qs@^6.14.0` +* deps: `server-static@2.2.0` +* deps: `type-is@2.0.1` + +5.0.1 / 2024-10-08 +========== + +* Update `cookie` semver lock to address [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764) + +5.0.0 / 2024-09-10 +========================= +* remove: + - `path-is-absolute` dependency - use `path.isAbsolute` instead +* breaking: + * `res.status()` accepts only integers, and input must be greater than 99 and less than 1000 + * will throw a `RangeError: Invalid status code: ${code}. Status code must be greater than 99 and less than 1000.` for inputs outside this range + * will throw a `TypeError: Invalid status code: ${code}. Status code must be an integer.` for non integer inputs + * deps: send@1.0.0 + * `res.redirect('back')` and `res.location('back')` is no longer a supported magic string, explicitly use `req.get('Referrer') || '/'`. +* change: + - `res.clearCookie` will ignore user provided `maxAge` and `expires` options +* deps: cookie-signature@^1.2.1 +* deps: debug@4.3.6 +* deps: merge-descriptors@^2.0.0 +* deps: serve-static@^2.1.0 +* deps: qs@6.13.0 +* deps: accepts@^2.0.0 +* deps: mime-types@^3.0.0 + - `application/javascript` => `text/javascript` +* deps: type-is@^2.0.0 +* deps: content-disposition@^1.0.0 +* deps: finalhandler@^2.0.0 +* deps: fresh@^2.0.0 +* deps: body-parser@^2.0.1 +* deps: send@^1.1.0 + +5.0.0-beta.3 / 2024-03-25 +========================= + +This incorporates all changes after 4.19.1 up to 4.19.2. + +5.0.0-beta.2 / 2024-03-20 +========================= + +This incorporates all changes after 4.17.2 up to 4.19.1. + +5.0.0-beta.1 / 2022-02-14 +========================= + +This is the first Express 5.0 beta release, based off 4.17.2 and includes +changes from 5.0.0-alpha.8. + + * change: + - Default "query parser" setting to `'simple'` + - Requires Node.js 4+ + - Use `mime-types` for file to content type mapping + * deps: array-flatten@3.0.0 + * deps: body-parser@2.0.0-beta.1 + - `req.body` is no longer always initialized to `{}` + - `urlencoded` parser now defaults `extended` to `false` + - Use `on-finished` to determine when body read + * deps: router@2.0.0-beta.1 + - Add new `?`, `*`, and `+` parameter modifiers + - Internalize private `router.process_params` method + - Matching group expressions are only RegExp syntax + - Named matching groups no longer available by position in `req.params` + - Regular expressions can only be used in a matching group + - Remove `debug` dependency + - Special `*` path segment behavior removed + - deps: array-flatten@3.0.0 + - deps: parseurl@~1.3.3 + - deps: path-to-regexp@3.2.0 + - deps: setprototypeof@1.2.0 + * deps: send@1.0.0-beta.1 + - Change `dotfiles` option default to `'ignore'` + - Remove `hidden` option; use `dotfiles` option instead + - Use `mime-types` for file to content type mapping + - deps: debug@3.1.0 + * deps: serve-static@2.0.0-beta.1 + - Change `dotfiles` option default to `'ignore'` + - Remove `hidden` option; use `dotfiles` option instead + - Use `mime-types` for file to content type mapping + - Remove `express.static.mime` export; use `mime-types` package instead + - deps: send@1.0.0-beta.1 + +5.0.0-alpha.8 / 2020-03-25 +========================== + +This is the eighth Express 5.0 alpha release, based off 4.17.1 and includes +changes from 5.0.0-alpha.7. + +5.0.0-alpha.7 / 2018-10-26 +========================== + +This is the seventh Express 5.0 alpha release, based off 4.16.4 and includes +changes from 5.0.0-alpha.6. + +The major change with this alpha is the basic support for returned, rejected +Promises in the router. + + * remove: + - `path-to-regexp` dependency + * deps: debug@3.1.0 + - Add `DEBUG_HIDE_DATE` environment variable + - Change timer to per-namespace instead of global + - Change non-TTY date format + - Remove `DEBUG_FD` environment variable support + - Support 256 namespace colors + * deps: router@2.0.0-alpha.1 + - Add basic support for returned, rejected Promises + - Fix JSDoc for `Router` constructor + - deps: debug@3.1.0 + - deps: parseurl@~1.3.2 + - deps: setprototypeof@1.1.0 + - deps: utils-merge@1.0.1 + +5.0.0-alpha.6 / 2017-09-24 +========================== + +This is the sixth Express 5.0 alpha release, based off 4.15.5 and includes +changes from 5.0.0-alpha.5. + + * remove: + - `res.redirect(url, status)` signature - use `res.redirect(status, url)` + - `res.send(status, body)` signature - use `res.status(status).send(body)` + * deps: router@~1.3.1 + - deps: debug@2.6.8 + +5.0.0-alpha.5 / 2017-03-06 +========================== + +This is the fifth Express 5.0 alpha release, based off 4.15.2 and includes +changes from 5.0.0-alpha.4. + +5.0.0-alpha.4 / 2017-03-01 +========================== + +This is the fourth Express 5.0 alpha release, based off 4.15.0 and includes +changes from 5.0.0-alpha.3. + + * remove: + - Remove Express 3.x middleware error stubs + * deps: router@~1.3.0 + - Add `next("router")` to exit from router + - Fix case where `router.use` skipped requests routes did not + - Skip routing when `req.url` is not set + - Use `%o` in path debug to tell types apart + - deps: debug@2.6.1 + - deps: setprototypeof@1.0.3 + - perf: add fast match path for `*` route + +5.0.0-alpha.3 / 2017-01-28 +========================== + +This is the third Express 5.0 alpha release, based off 4.14.1 and includes +changes from 5.0.0-alpha.2. + + * remove: + - `res.json(status, obj)` signature - use `res.status(status).json(obj)` + - `res.jsonp(status, obj)` signature - use `res.status(status).jsonp(obj)` + - `res.vary()` (no arguments) -- provide a field name as an argument + * deps: array-flatten@2.1.1 + * deps: path-is-absolute@1.0.1 + * deps: router@~1.1.5 + - deps: array-flatten@2.0.1 + - deps: methods@~1.1.2 + - deps: parseurl@~1.3.1 + - deps: setprototypeof@1.0.2 + +5.0.0-alpha.2 / 2015-07-06 +========================== + +This is the second Express 5.0 alpha release, based off 4.13.1 and includes +changes from 5.0.0-alpha.1. + + * remove: + - `app.param(fn)` + - `req.param()` -- use `req.params`, `req.body`, or `req.query` instead + * change: + - `res.render` callback is always async, even for sync view engines + - The leading `:` character in `name` for `app.param(name, fn)` is no longer removed + - Use `router` module for routing + - Use `path-is-absolute` module for absolute path detection + +5.0.0-alpha.1 / 2014-11-06 +========================== + +This is the first Express 5.0 alpha release, based off 4.10.1. + + * remove: + - `app.del` - use `app.delete` + - `req.acceptsCharset` - use `req.acceptsCharsets` + - `req.acceptsEncoding` - use `req.acceptsEncodings` + - `req.acceptsLanguage` - use `req.acceptsLanguages` + - `res.json(obj, status)` signature - use `res.json(status, obj)` + - `res.jsonp(obj, status)` signature - use `res.jsonp(status, obj)` + - `res.send(body, status)` signature - use `res.send(status, body)` + - `res.send(status)` signature - use `res.sendStatus(status)` + - `res.sendfile` - use `res.sendFile` instead + - `express.query` middleware + * change: + - `req.host` now returns host (`hostname:port`) - use `req.hostname` for only hostname + - `req.query` is now a getter instead of a plain property + * add: + - `app.router` is a reference to the base router + +4.20.0 / 2024-09-10 +========== + * deps: serve-static@0.16.0 + * Remove link renderization in html while redirecting + * deps: send@0.19.0 + * Remove link renderization in html while redirecting + * deps: body-parser@0.6.0 + * add `depth` option to customize the depth level in the parser + * IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`) + * Remove link renderization in html while using `res.redirect` + * deps: path-to-regexp@0.1.10 + - Adds support for named matching groups in the routes using a regex + - Adds backtracking protection to parameters without regexes defined + * deps: encodeurl@~2.0.0 + - Removes encoding of `\`, `|`, and `^` to align better with URL spec + * Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie` + - Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie + +4.19.2 / 2024-03-25 +========== + + * Improved fix for open redirect allow list bypass + +4.19.1 / 2024-03-20 +========== + + * Allow passing non-strings to res.location with new encoding handling checks + +4.19.0 / 2024-03-20 +========== + + * Prevent open redirect allow list bypass due to encodeurl + * deps: cookie@0.6.0 + +4.18.3 / 2024-02-29 +========== + + * Fix routing requests without method + * deps: body-parser@1.20.2 + - Fix strict json error message on Node.js 19+ + - deps: content-type@~1.0.5 + - deps: raw-body@2.5.2 + * deps: cookie@0.6.0 + - Add `partitioned` option + +4.18.2 / 2022-10-08 +=================== + + * Fix regression routing a large stack in a single route + * deps: body-parser@1.20.1 + - deps: qs@6.11.0 + - perf: remove unnecessary object clone + * deps: qs@6.11.0 + +4.18.1 / 2022-04-29 +=================== + + * Fix hanging on large stack of sync routes + +4.18.0 / 2022-04-25 +=================== + + * Add "root" option to `res.download` + * Allow `options` without `filename` in `res.download` + * Deprecate string and non-integer arguments to `res.status` + * Fix behavior of `null`/`undefined` as `maxAge` in `res.cookie` + * Fix handling very large stacks of sync middleware + * Ignore `Object.prototype` values in settings through `app.set`/`app.get` + * Invoke `default` with same arguments as types in `res.format` + * Support proper 205 responses using `res.send` + * Use `http-errors` for `res.format` error + * deps: body-parser@1.20.0 + - Fix error message for json parse whitespace in `strict` + - Fix internal error when inflated body exceeds limit + - Prevent loss of async hooks context + - Prevent hanging when request already read + - deps: depd@2.0.0 + - deps: http-errors@2.0.0 + - deps: on-finished@2.4.1 + - deps: qs@6.10.3 + - deps: raw-body@2.5.1 + * deps: cookie@0.5.0 + - Add `priority` option + - Fix `expires` option to reject invalid dates + * deps: depd@2.0.0 + - Replace internal `eval` usage with `Function` constructor + - Use instance methods on `process` to check for listeners + * deps: finalhandler@1.2.0 + - Remove set content headers that break response + - deps: on-finished@2.4.1 + - deps: statuses@2.0.1 + * deps: on-finished@2.4.1 + - Prevent loss of async hooks context + * deps: qs@6.10.3 + * deps: send@0.18.0 + - Fix emitted 416 error missing headers property + - Limit the headers removed for 304 response + - deps: depd@2.0.0 + - deps: destroy@1.2.0 + - deps: http-errors@2.0.0 + - deps: on-finished@2.4.1 + - deps: statuses@2.0.1 + * deps: serve-static@1.15.0 + - deps: send@0.18.0 + * deps: statuses@2.0.1 + - Remove code 306 + - Rename `425 Unordered Collection` to standard `425 Too Early` + +4.17.3 / 2022-02-16 +=================== + + * deps: accepts@~1.3.8 + - deps: mime-types@~2.1.34 + - deps: negotiator@0.6.3 + * deps: body-parser@1.19.2 + - deps: bytes@3.1.2 + - deps: qs@6.9.7 + - deps: raw-body@2.4.3 + * deps: cookie@0.4.2 + * deps: qs@6.9.7 + * Fix handling of `__proto__` keys + * pref: remove unnecessary regexp for trust proxy + +4.17.2 / 2021-12-16 +=================== + + * Fix handling of `undefined` in `res.jsonp` + * Fix handling of `undefined` when `"json escape"` is enabled + * Fix incorrect middleware execution with unanchored `RegExp`s + * Fix `res.jsonp(obj, status)` deprecation message + * Fix typo in `res.is` JSDoc + * deps: body-parser@1.19.1 + - deps: bytes@3.1.1 + - deps: http-errors@1.8.1 + - deps: qs@6.9.6 + - deps: raw-body@2.4.2 + - deps: safe-buffer@5.2.1 + - deps: type-is@~1.6.18 + * deps: content-disposition@0.5.4 + - deps: safe-buffer@5.2.1 + * deps: cookie@0.4.1 + - Fix `maxAge` option to reject invalid values + * deps: proxy-addr@~2.0.7 + - Use `req.socket` over deprecated `req.connection` + - deps: forwarded@0.2.0 + - deps: ipaddr.js@1.9.1 + * deps: qs@6.9.6 + * deps: safe-buffer@5.2.1 + * deps: send@0.17.2 + - deps: http-errors@1.8.1 + - deps: ms@2.1.3 + - pref: ignore empty http tokens + * deps: serve-static@1.14.2 + - deps: send@0.17.2 + * deps: setprototypeof@1.2.0 + +4.17.1 / 2019-05-25 +=================== + + * Revert "Improve error message for `null`/`undefined` to `res.status`" + +4.17.0 / 2019-05-16 +=================== + + * Add `express.raw` to parse bodies into `Buffer` + * Add `express.text` to parse bodies into string + * Improve error message for non-strings to `res.sendFile` + * Improve error message for `null`/`undefined` to `res.status` + * Support multiple hosts in `X-Forwarded-Host` + * deps: accepts@~1.3.7 + * deps: body-parser@1.19.0 + - Add encoding MIK + - Add petabyte (`pb`) support + - Fix parsing array brackets after index + - deps: bytes@3.1.0 + - deps: http-errors@1.7.2 + - deps: iconv-lite@0.4.24 + - deps: qs@6.7.0 + - deps: raw-body@2.4.0 + - deps: type-is@~1.6.17 + * deps: content-disposition@0.5.3 + * deps: cookie@0.4.0 + - Add `SameSite=None` support + * deps: finalhandler@~1.1.2 + - Set stricter `Content-Security-Policy` header + - deps: parseurl@~1.3.3 + - deps: statuses@~1.5.0 + * deps: parseurl@~1.3.3 + * deps: proxy-addr@~2.0.5 + - deps: ipaddr.js@1.9.0 + * deps: qs@6.7.0 + - Fix parsing array brackets after index + * deps: range-parser@~1.2.1 + * deps: send@0.17.1 + - Set stricter CSP header in redirect & error responses + - deps: http-errors@~1.7.2 + - deps: mime@1.6.0 + - deps: ms@2.1.1 + - deps: range-parser@~1.2.1 + - deps: statuses@~1.5.0 + - perf: remove redundant `path.normalize` call + * deps: serve-static@1.14.1 + - Set stricter CSP header in redirect response + - deps: parseurl@~1.3.3 + - deps: send@0.17.1 + * deps: setprototypeof@1.1.1 + * deps: statuses@~1.5.0 + - Add `103 Early Hints` + * deps: type-is@~1.6.18 + - deps: mime-types@~2.1.24 + - perf: prevent internal `throw` on invalid type + +4.16.4 / 2018-10-10 +=================== + + * Fix issue where `"Request aborted"` may be logged in `res.sendfile` + * Fix JSDoc for `Router` constructor + * deps: body-parser@1.18.3 + - Fix deprecation warnings on Node.js 10+ + - Fix stack trace for strict json parse error + - deps: depd@~1.1.2 + - deps: http-errors@~1.6.3 + - deps: iconv-lite@0.4.23 + - deps: qs@6.5.2 + - deps: raw-body@2.3.3 + - deps: type-is@~1.6.16 + * deps: proxy-addr@~2.0.4 + - deps: ipaddr.js@1.8.0 + * deps: qs@6.5.2 + * deps: safe-buffer@5.1.2 + +4.16.3 / 2018-03-12 +=================== + + * deps: accepts@~1.3.5 + - deps: mime-types@~2.1.18 + * deps: depd@~1.1.2 + - perf: remove argument reassignment + * deps: encodeurl@~1.0.2 + - Fix encoding `%` as last character + * deps: finalhandler@1.1.1 + - Fix 404 output for bad / missing pathnames + - deps: encodeurl@~1.0.2 + - deps: statuses@~1.4.0 + * deps: proxy-addr@~2.0.3 + - deps: ipaddr.js@1.6.0 + * deps: send@0.16.2 + - Fix incorrect end tag in default error & redirects + - deps: depd@~1.1.2 + - deps: encodeurl@~1.0.2 + - deps: statuses@~1.4.0 + * deps: serve-static@1.13.2 + - Fix incorrect end tag in redirects + - deps: encodeurl@~1.0.2 + - deps: send@0.16.2 + * deps: statuses@~1.4.0 + * deps: type-is@~1.6.16 + - deps: mime-types@~2.1.18 + +4.16.2 / 2017-10-09 +=================== + + * Fix `TypeError` in `res.send` when given `Buffer` and `ETag` header set + * perf: skip parsing of entire `X-Forwarded-Proto` header + +4.16.1 / 2017-09-29 +=================== + + * deps: send@0.16.1 + * deps: serve-static@1.13.1 + - Fix regression when `root` is incorrectly set to a file + - deps: send@0.16.1 + +4.16.0 / 2017-09-28 +=================== + + * Add `"json escape"` setting for `res.json` and `res.jsonp` + * Add `express.json` and `express.urlencoded` to parse bodies + * Add `options` argument to `res.download` + * Improve error message when autoloading invalid view engine + * Improve error messages when non-function provided as middleware + * Skip `Buffer` encoding when not generating ETag for small response + * Use `safe-buffer` for improved Buffer API + * deps: accepts@~1.3.4 + - deps: mime-types@~2.1.16 + * deps: content-type@~1.0.4 + - perf: remove argument reassignment + - perf: skip parameter parsing when no parameters + * deps: etag@~1.8.1 + - perf: replace regular expression with substring + * deps: finalhandler@1.1.0 + - Use `res.headersSent` when available + * deps: parseurl@~1.3.2 + - perf: reduce overhead for full URLs + - perf: unroll the "fast-path" `RegExp` + * deps: proxy-addr@~2.0.2 + - Fix trimming leading / trailing OWS in `X-Forwarded-For` + - deps: forwarded@~0.1.2 + - deps: ipaddr.js@1.5.2 + - perf: reduce overhead when no `X-Forwarded-For` header + * deps: qs@6.5.1 + - Fix parsing & compacting very deep objects + * deps: send@0.16.0 + - Add 70 new types for file extensions + - Add `immutable` option + - Fix missing `` in default error & redirects + - Set charset as "UTF-8" for .js and .json + - Use instance methods on steam to check for listeners + - deps: mime@1.4.1 + - perf: improve path validation speed + * deps: serve-static@1.13.0 + - Add 70 new types for file extensions + - Add `immutable` option + - Set charset as "UTF-8" for .js and .json + - deps: send@0.16.0 + * deps: setprototypeof@1.1.0 + * deps: utils-merge@1.0.1 + * deps: vary@~1.1.2 + - perf: improve header token parsing speed + * perf: re-use options object when generating ETags + * perf: remove dead `.charset` set in `res.jsonp` + +4.15.5 / 2017-09-24 +=================== + + * deps: debug@2.6.9 + * deps: finalhandler@~1.0.6 + - deps: debug@2.6.9 + - deps: parseurl@~1.3.2 + * deps: fresh@0.5.2 + - Fix handling of modified headers with invalid dates + - perf: improve ETag match loop + - perf: improve `If-None-Match` token parsing + * deps: send@0.15.6 + - Fix handling of modified headers with invalid dates + - deps: debug@2.6.9 + - deps: etag@~1.8.1 + - deps: fresh@0.5.2 + - perf: improve `If-Match` token parsing + * deps: serve-static@1.12.6 + - deps: parseurl@~1.3.2 + - deps: send@0.15.6 + - perf: improve slash collapsing + +4.15.4 / 2017-08-06 +=================== + + * deps: debug@2.6.8 + * deps: depd@~1.1.1 + - Remove unnecessary `Buffer` loading + * deps: finalhandler@~1.0.4 + - deps: debug@2.6.8 + * deps: proxy-addr@~1.1.5 + - Fix array argument being altered + - deps: ipaddr.js@1.4.0 + * deps: qs@6.5.0 + * deps: send@0.15.4 + - deps: debug@2.6.8 + - deps: depd@~1.1.1 + - deps: http-errors@~1.6.2 + * deps: serve-static@1.12.4 + - deps: send@0.15.4 + +4.15.3 / 2017-05-16 +=================== + + * Fix error when `res.set` cannot add charset to `Content-Type` + * deps: debug@2.6.7 + - Fix `DEBUG_MAX_ARRAY_LENGTH` + - deps: ms@2.0.0 + * deps: finalhandler@~1.0.3 + - Fix missing `` in HTML document + - deps: debug@2.6.7 + * deps: proxy-addr@~1.1.4 + - deps: ipaddr.js@1.3.0 + * deps: send@0.15.3 + - deps: debug@2.6.7 + - deps: ms@2.0.0 + * deps: serve-static@1.12.3 + - deps: send@0.15.3 + * deps: type-is@~1.6.15 + - deps: mime-types@~2.1.15 + * deps: vary@~1.1.1 + - perf: hoist regular expression + +4.15.2 / 2017-03-06 +=================== + + * deps: qs@6.4.0 + - Fix regression parsing keys starting with `[` + +4.15.1 / 2017-03-05 +=================== + + * deps: send@0.15.1 + - Fix issue when `Date.parse` does not return `NaN` on invalid date + - Fix strict violation in broken environments + * deps: serve-static@1.12.1 + - Fix issue when `Date.parse` does not return `NaN` on invalid date + - deps: send@0.15.1 + +4.15.0 / 2017-03-01 +=================== + + * Add debug message when loading view engine + * Add `next("router")` to exit from router + * Fix case where `router.use` skipped requests routes did not + * Remove usage of `res._headers` private field + - Improves compatibility with Node.js 8 nightly + * Skip routing when `req.url` is not set + * Use `%o` in path debug to tell types apart + * Use `Object.create` to setup request & response prototypes + * Use `setprototypeof` module to replace `__proto__` setting + * Use `statuses` instead of `http` module for status messages + * deps: debug@2.6.1 + - Allow colors in workers + - Deprecated `DEBUG_FD` environment variable set to `3` or higher + - Fix error when running under React Native + - Use same color for same namespace + - deps: ms@0.7.2 + * deps: etag@~1.8.0 + - Use SHA1 instead of MD5 for ETag hashing + - Works with FIPS 140-2 OpenSSL configuration + * deps: finalhandler@~1.0.0 + - Fix exception when `err` cannot be converted to a string + - Fully URL-encode the pathname in the 404 + - Only include the pathname in the 404 message + - Send complete HTML document + - Set `Content-Security-Policy: default-src 'self'` header + - deps: debug@2.6.1 + * deps: fresh@0.5.0 + - Fix false detection of `no-cache` request directive + - Fix incorrect result when `If-None-Match` has both `*` and ETags + - Fix weak `ETag` matching to match spec + - perf: delay reading header values until needed + - perf: enable strict mode + - perf: hoist regular expressions + - perf: remove duplicate conditional + - perf: remove unnecessary boolean coercions + - perf: skip checking modified time if ETag check failed + - perf: skip parsing `If-None-Match` when no `ETag` header + - perf: use `Date.parse` instead of `new Date` + * deps: qs@6.3.1 + - Fix array parsing from skipping empty values + - Fix compacting nested arrays + * deps: send@0.15.0 + - Fix false detection of `no-cache` request directive + - Fix incorrect result when `If-None-Match` has both `*` and ETags + - Fix weak `ETag` matching to match spec + - Remove usage of `res._headers` private field + - Support `If-Match` and `If-Unmodified-Since` headers + - Use `res.getHeaderNames()` when available + - Use `res.headersSent` when available + - deps: debug@2.6.1 + - deps: etag@~1.8.0 + - deps: fresh@0.5.0 + - deps: http-errors@~1.6.1 + * deps: serve-static@1.12.0 + - Fix false detection of `no-cache` request directive + - Fix incorrect result when `If-None-Match` has both `*` and ETags + - Fix weak `ETag` matching to match spec + - Remove usage of `res._headers` private field + - Send complete HTML document in redirect response + - Set default CSP header in redirect response + - Support `If-Match` and `If-Unmodified-Since` headers + - Use `res.getHeaderNames()` when available + - Use `res.headersSent` when available + - deps: send@0.15.0 + * perf: add fast match path for `*` route + * perf: improve `req.ips` performance + +4.14.1 / 2017-01-28 +=================== + + * deps: content-disposition@0.5.2 + * deps: finalhandler@0.5.1 + - Fix exception when `err.headers` is not an object + - deps: statuses@~1.3.1 + - perf: hoist regular expressions + - perf: remove duplicate validation path + * deps: proxy-addr@~1.1.3 + - deps: ipaddr.js@1.2.0 + * deps: send@0.14.2 + - deps: http-errors@~1.5.1 + - deps: ms@0.7.2 + - deps: statuses@~1.3.1 + * deps: serve-static@~1.11.2 + - deps: send@0.14.2 + * deps: type-is@~1.6.14 + - deps: mime-types@~2.1.13 + +4.14.0 / 2016-06-16 +=================== + + * Add `acceptRanges` option to `res.sendFile`/`res.sendfile` + * Add `cacheControl` option to `res.sendFile`/`res.sendfile` + * Add `options` argument to `req.range` + - Includes the `combine` option + * Encode URL in `res.location`/`res.redirect` if not already encoded + * Fix some redirect handling in `res.sendFile`/`res.sendfile` + * Fix Windows absolute path check using forward slashes + * Improve error with invalid arguments to `req.get()` + * Improve performance for `res.json`/`res.jsonp` in most cases + * Improve `Range` header handling in `res.sendFile`/`res.sendfile` + * deps: accepts@~1.3.3 + - Fix including type extensions in parameters in `Accept` parsing + - Fix parsing `Accept` parameters with quoted equals + - Fix parsing `Accept` parameters with quoted semicolons + - Many performance improvements + - deps: mime-types@~2.1.11 + - deps: negotiator@0.6.1 + * deps: content-type@~1.0.2 + - perf: enable strict mode + * deps: cookie@0.3.1 + - Add `sameSite` option + - Fix cookie `Max-Age` to never be a floating point number + - Improve error message when `encode` is not a function + - Improve error message when `expires` is not a `Date` + - Throw better error for invalid argument to parse + - Throw on invalid values provided to `serialize` + - perf: enable strict mode + - perf: hoist regular expression + - perf: use for loop in parse + - perf: use string concatenation for serialization + * deps: finalhandler@0.5.0 + - Change invalid or non-numeric status code to 500 + - Overwrite status message to match set status code + - Prefer `err.statusCode` if `err.status` is invalid + - Set response headers from `err.headers` object + - Use `statuses` instead of `http` module for status messages + * deps: proxy-addr@~1.1.2 + - Fix accepting various invalid netmasks + - Fix IPv6-mapped IPv4 validation edge cases + - IPv4 netmasks must be contiguous + - IPv6 addresses cannot be used as a netmask + - deps: ipaddr.js@1.1.1 + * deps: qs@6.2.0 + - Add `decoder` option in `parse` function + * deps: range-parser@~1.2.0 + - Add `combine` option to combine overlapping ranges + - Fix incorrectly returning -1 when there is at least one valid range + - perf: remove internal function + * deps: send@0.14.1 + - Add `acceptRanges` option + - Add `cacheControl` option + - Attempt to combine multiple ranges into single range + - Correctly inherit from `Stream` class + - Fix `Content-Range` header in 416 responses when using `start`/`end` options + - Fix `Content-Range` header missing from default 416 responses + - Fix redirect error when `path` contains raw non-URL characters + - Fix redirect when `path` starts with multiple forward slashes + - Ignore non-byte `Range` headers + - deps: http-errors@~1.5.0 + - deps: range-parser@~1.2.0 + - deps: statuses@~1.3.0 + - perf: remove argument reassignment + * deps: serve-static@~1.11.1 + - Add `acceptRanges` option + - Add `cacheControl` option + - Attempt to combine multiple ranges into single range + - Fix redirect error when `req.url` contains raw non-URL characters + - Ignore non-byte `Range` headers + - Use status code 301 for redirects + - deps: send@0.14.1 + * deps: type-is@~1.6.13 + - Fix type error when given invalid type to match against + - deps: mime-types@~2.1.11 + * deps: vary@~1.1.0 + - Only accept valid field names in the `field` argument + * perf: use strict equality when possible + +4.13.4 / 2016-01-21 +=================== + + * deps: content-disposition@0.5.1 + - perf: enable strict mode + * deps: cookie@0.1.5 + - Throw on invalid values provided to `serialize` + * deps: depd@~1.1.0 + - Support web browser loading + - perf: enable strict mode + * deps: escape-html@~1.0.3 + - perf: enable strict mode + - perf: optimize string replacement + - perf: use faster string coercion + * deps: finalhandler@0.4.1 + - deps: escape-html@~1.0.3 + * deps: merge-descriptors@1.0.1 + - perf: enable strict mode + * deps: methods@~1.1.2 + - perf: enable strict mode + * deps: parseurl@~1.3.1 + - perf: enable strict mode + * deps: proxy-addr@~1.0.10 + - deps: ipaddr.js@1.0.5 + - perf: enable strict mode + * deps: range-parser@~1.0.3 + - perf: enable strict mode + * deps: send@0.13.1 + - deps: depd@~1.1.0 + - deps: destroy@~1.0.4 + - deps: escape-html@~1.0.3 + - deps: range-parser@~1.0.3 + * deps: serve-static@~1.10.2 + - deps: escape-html@~1.0.3 + - deps: parseurl@~1.3.0 + - deps: send@0.13.1 + +4.13.3 / 2015-08-02 +=================== + + * Fix infinite loop condition using `mergeParams: true` + * Fix inner numeric indices incorrectly altering parent `req.params` + +4.13.2 / 2015-07-31 +=================== + + * deps: accepts@~1.2.12 + - deps: mime-types@~2.1.4 + * deps: array-flatten@1.1.1 + - perf: enable strict mode + * deps: path-to-regexp@0.1.7 + - Fix regression with escaped round brackets and matching groups + * deps: type-is@~1.6.6 + - deps: mime-types@~2.1.4 + 4.13.1 / 2015-07-05 =================== @@ -683,13 +1534,13 @@ - deps: negotiator@0.4.6 * deps: debug@1.0.2 * deps: send@0.4.3 - - Do not throw un-catchable error on file open race condition + - Do not throw uncatchable error on file open race condition - Use `escape-html` for HTML escaping - deps: debug@1.0.2 - deps: finished@1.2.2 - deps: fresh@0.2.2 * deps: serve-static@1.2.3 - - Do not throw un-catchable error on file open race condition + - Do not throw uncatchable error on file open race condition - deps: send@0.4.3 4.4.2 / 2014-06-09 @@ -865,6 +1716,22 @@ - `app.route()` - Proxy to the app's `Router#route()` method to create a new route - Router & Route - public API +3.21.2 / 2015-07-31 +=================== + + * deps: connect@2.30.2 + - deps: body-parser@~1.13.3 + - deps: compression@~1.5.2 + - deps: errorhandler@~1.4.2 + - deps: method-override@~2.3.5 + - deps: serve-index@~1.7.2 + - deps: type-is@~1.6.6 + - deps: vhost@~3.0.1 + * deps: vary@~1.0.1 + - Fix setting empty header from empty `field` + - perf: enable strict mode + - perf: remove argument reassignments + 3.21.1 / 2015-07-05 =================== @@ -1514,7 +2381,7 @@ * deps: connect@2.21.0 - deprecate `connect(middleware)` -- use `app.use(middleware)` instead - deprecate `connect.createServer()` -- use `connect()` instead - - fix `res.setHeader()` patch to work with with get -> append -> set pattern + - fix `res.setHeader()` patch to work with get -> append -> set pattern - deps: compression@~1.0.8 - deps: errorhandler@~1.1.1 - deps: express-session@~1.5.0 @@ -1553,7 +2420,7 @@ - deps: serve-static@1.2.3 * deps: debug@1.0.2 * deps: send@0.4.3 - - Do not throw un-catchable error on file open race condition + - Do not throw uncatchable error on file open race condition - Use `escape-html` for HTML escaping - deps: debug@1.0.2 - deps: finished@1.2.2 @@ -2725,8 +3592,8 @@ Shaw] * Added node v0.1.97 compatibility * Added support for deleting cookies via Request#cookie('key', null) * Updated haml submodule - * Fixed not-found page, now using using charset utf-8 - * Fixed show-exceptions page, now using using charset utf-8 + * Fixed not-found page, now using charset utf-8 + * Fixed show-exceptions page, now using charset utf-8 * Fixed view support due to fs.readFile Buffers * Changed; mime.type() no longer accepts ".type" due to node extname() changes @@ -2738,7 +3605,7 @@ Shaw] * Updated haml submodule * Changed ETag; removed inode, modified time only * Fixed LF to CRLF for setting multiple cookies - * Fixed cookie complation; values are now urlencoded + * Fixed cookie compilation; values are now urlencoded * Fixed cookies parsing; accepts quoted values and url escaped cookies 0.11.0 / 2010-05-06 @@ -2761,7 +3628,7 @@ Shaw] ================== * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s - encoding is set to 'utf8' or 'utf-8'. + encoding is set to 'utf8' or 'utf-8'). * Added "encoding" option to Request#render(). Closes #299 * Added "dump exceptions" setting, which is enabled by default. * Added simple ejs template engine support @@ -2800,7 +3667,7 @@ Shaw] * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js * Added callback function support to Request#halt() as 3rd/4th arg * Added preprocessing of route param wildcards using param(). Closes #251 - * Added view partial support (with collections etc) + * Added view partial support (with collections etc.) * Fixed bug preventing falsey params (such as ?page=0). Closes #286 * Fixed setting of multiple cookies. Closes #199 * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml) @@ -2933,7 +3800,7 @@ Shaw] * Added "plot" format option for Profiler (for gnuplot processing) * Added request number to Profiler plugin - * Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8 + * Fixed binary encoding for multipart file uploads, was previously defaulting to UTF8 * Fixed issue with routes not firing when not files are present. Closes #184 * Fixed process.Promise -> events.Promise @@ -2979,7 +3846,7 @@ Shaw] * Updated sample chat app to show messages on load * Updated libxmljs parseString -> parseHtmlString * Fixed `make init` to work with older versions of git - * Fixed specs can now run independent specs for those who cant build deps. Closes #127 + * Fixed specs can now run independent specs for those who can't build deps. Closes #127 * Fixed issues introduced by the node url module changes. Closes 126. * Fixed two assertions failing due to Collection#keys() returning strings * Fixed faulty Collection#toArray() spec due to keys() returning strings diff --git a/Readme.md b/Readme.md index 8da83a517e1..d62b9821250 100644 --- a/Readme.md +++ b/Readme.md @@ -1,30 +1,71 @@ -[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/) +[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/) - Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). +**Fast, unopinionated, minimalist web framework for [Node.js](https://nodejs.org).** + +**This project has a [Code of Conduct].** + +## Table of contents + +- [Table of contents](#table-of-contents) +- [Installation](#installation) +- [Features](#features) +- [Docs \& Community](#docs--community) +- [Quick Start](#quick-start) +- [Philosophy](#philosophy) +- [Examples](#examples) +- [Contributing](#contributing) + - [Security Issues](#security-issues) + - [Running Tests](#running-tests) +- [Current project team members](#current-project-team-members) + - [TC (Technical Committee)](#tc-technical-committee) + - [TC emeriti members](#tc-emeriti-members) + - [Triagers](#triagers) + - [Emeritus Triagers](#emeritus-triagers) +- [License](#license) + + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-downloads-url] +[![Linux Build][github-actions-ci-image]][github-actions-ci-url] +[![Test Coverage][coveralls-image]][coveralls-url] +[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer] - [![NPM Version][npm-image]][npm-url] - [![NPM Downloads][downloads-image]][downloads-url] - [![Linux Build][travis-image]][travis-url] - [![Windows Build][appveyor-image]][appveyor-url] - [![Test Coverage][coveralls-image]][coveralls-url] ```js -var express = require('express') -var app = express() +import express from 'express' + +const app = express() -app.get('/', function (req, res) { +app.get('/', (req, res) => { res.send('Hello World') }) -app.listen(3000) +app.listen(3000, () => { + console.log('Server is running on http://localhost:3000') +}) ``` ## Installation +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). + +Before installing, [download and install Node.js](https://nodejs.org/en/download/). +Node.js 18 or higher is required. + +If this is a brand new project, make sure to create a `package.json` first with +the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file). + +Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + ```bash -$ npm install express +npm install express ``` +Follow [our installing guide](https://expressjs.com/en/starter/installing.html) +for more information. + ## Features * Robust routing @@ -37,15 +78,11 @@ $ npm install express ## Docs & Community - * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/strongloop/expressjs.com)] - * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC - * [Github Organization](https://github.com/expressjs) for Official Middleware & Modules - * Visit the [Wiki](https://github.com/strongloop/express/wiki) - * [Google Group](https://groups.google.com/group/express-js) for discussion - * [Русскоязычная документация](http://jsman.ru/express/) - * [한국어 문서](http://expressjs.kr) - [[website repo](https://github.com/Hanul/expressjs.kr)] + * [Website and Documentation](https://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)] + * [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules + * [Github Discussions](https://github.com/expressjs/discussions) for discussion on the development and usage of Express -**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/strongloop/express/wiki/New-features-in-4.x). +**PROTIP** Be sure to read the [migration guide to v5](https://expressjs.com/en/guide/migrating-5) ## Quick Start @@ -54,85 +91,185 @@ $ npm install express Install the executable. The executable's major version will match Express's: ```bash -$ npm install -g express-generator@4 +npm install -g express-generator@4 ``` Create the app: ```bash -$ express /tmp/foo && cd /tmp/foo +express /tmp/foo && cd /tmp/foo ``` Install dependencies: ```bash -$ npm install +npm install ``` Start the server: ```bash -$ npm start +npm start ``` + View the website at: http://localhost:3000 + ## Philosophy The Express philosophy is to provide small, robust tooling for HTTP servers, making - it a great solution for single page applications, web sites, hybrids, or public + it a great solution for single page applications, websites, hybrids, or public HTTP APIs. Express does not force you to use any specific ORM or template engine. With support for over - 14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js), + 14 template engines via [@ladjs/consolidate](https://github.com/ladjs/consolidate), you can quickly craft your perfect framework. ## Examples - To view the examples, clone the Express repo and install the dependencies: + To view the examples, clone the Express repository: + +```bash +git clone https://github.com/expressjs/express.git --depth 1 && cd express +``` + + Then install the dependencies: ```bash -$ git clone git://github.com/strongloop/express.git --depth 1 -$ cd express -$ npm install +npm install ``` Then run whichever example you want: ```bash -$ node examples/content-negotiation +node examples/content-negotiation ``` -## Tests +## Contributing + +The Express.js project welcomes all constructive contributions. Contributions take many forms, +from code for bug fixes and enhancements, to additions and fixes to documentation, additional +tests, triaging incoming pull requests and issues, and more! - To run the test suite, first install the dependencies, then run `npm test`: +See the [Contributing Guide] for more technical details on contributing. + +### Security Issues + +If you discover a security vulnerability in Express, please see [Security Policies and Procedures](SECURITY.md). + +### Running Tests + +To run the test suite, first install the dependencies: ```bash -$ npm install -$ npm test +npm install ``` -## People +Then run `npm test`: -The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia] +```bash +npm test +``` -The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson] +## Current project team members + +For information about the governance of the express.js project, see [GOVERNANCE.md](https://github.com/expressjs/discussions/blob/HEAD/docs/GOVERNANCE.md). + +The original author of Express is [TJ Holowaychuk](https://github.com/tj) + +[List of all contributors](https://github.com/expressjs/express/graphs/contributors) + +### TC (Technical Committee) + +* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him) +* [jonchurch](https://github.com/jonchurch) - **Jon Church** +* [wesleytodd](https://github.com/wesleytodd) - **Wes Todd** +* [LinusU](https://github.com/LinusU) - **Linus Unnebäck** +* [blakeembrey](https://github.com/blakeembrey) - **Blake Embrey** +* [sheplu](https://github.com/sheplu) - **Jean Burellier** +* [crandmck](https://github.com/crandmck) - **Rand McKinney** +* [ctcpip](https://github.com/ctcpip) - **Chris de Almeida** + +
+TC emeriti members + +#### TC emeriti members + + * [dougwilson](https://github.com/dougwilson) - **Douglas Wilson** + * [hacksparrow](https://github.com/hacksparrow) - **Hage Yaapa** + * [jonathanong](https://github.com/jonathanong) - **jongleberry** + * [niftylettuce](https://github.com/niftylettuce) - **niftylettuce** + * [troygoode](https://github.com/troygoode) - **Troy Goode** +
+ + +### Triagers + +* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair** +* [bjohansebas](https://github.com/bjohansebas) - **Sebastian Beltran** +* [carpasse](https://github.com/carpasse) - **Carlos Serrano** +* [CBID2](https://github.com/CBID2) - **Christine Belzie** +* [dpopp07](https://github.com/dpopp07) - **Dustin Popp** +* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him) +* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi** +* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him) +* [Phillip9587](https://github.com/Phillip9587) - **Phillip Barta** +* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger** +* [rxmarbles](https://github.com/rxmarbles) **Rick Markins** (He/him) + +
+Triagers emeriti members + +#### Emeritus Triagers + + * [AuggieH](https://github.com/AuggieH) - **Auggie Hudak** + * [G-Rath](https://github.com/G-Rath) - **Gareth Jones** + * [MohammadXroid](https://github.com/MohammadXroid) - **Mohammad Ayashi** + * [NawafSwe](https://github.com/NawafSwe) - **Nawaf Alsharqi** + * [NotMoni](https://github.com/NotMoni) - **Moni** + * [VigneshMurugan](https://github.com/VigneshMurugan) - **Vignesh Murugan** + * [davidmashe](https://github.com/davidmashe) - **David Ashe** + * [digitaIfabric](https://github.com/digitaIfabric) - **David** + * [e-l-i-s-e](https://github.com/e-l-i-s-e) - **Elise Bonner** + * [fed135](https://github.com/fed135) - **Frederic Charette** + * [firmanJS](https://github.com/firmanJS) - **Firman Abdul Hakim** + * [getspooky](https://github.com/getspooky) - **Yasser Ameur** + * [ghinks](https://github.com/ghinks) - **Glenn** + * [ghousemohamed](https://github.com/ghousemohamed) - **Ghouse Mohamed** + * [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil** + * [jake32321](https://github.com/jake32321) - **Jake Reed** + * [jonchurch](https://github.com/jonchurch) - **Jon Church** + * [lekanikotun](https://github.com/lekanikotun) - **Troy Goode** + * [marsonya](https://github.com/marsonya) - **Lekan Ikotun** + * [mastermatt](https://github.com/mastermatt) - **Matt R. Wilson** + * [maxakuru](https://github.com/maxakuru) - **Max Edell** + * [mlrawlings](https://github.com/mlrawlings) - **Michael Rawlings** + * [rodion-arr](https://github.com/rodion-arr) - **Rodion Abdurakhimov** + * [sheplu](https://github.com/sheplu) - **Jean Burellier** + * [tarunyadav1](https://github.com/tarunyadav1) - **Tarun yadav** + * [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe** + * [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim** + * [0ss](https://github.com/0ss) - **Salah** + * [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him) + * [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him) + * [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego** + * [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin** + +
-[List of all contributors](https://github.com/strongloop/express/graphs/contributors) ## License [MIT](LICENSE) -[npm-image]: https://img.shields.io/npm/v/express.svg +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/express/master +[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master +[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=CI +[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml +[npm-downloads-image]: https://badgen.net/npm/dm/express +[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true [npm-url]: https://npmjs.org/package/express -[downloads-image]: https://img.shields.io/npm/dm/express.svg -[downloads-url]: https://npmjs.org/package/express -[travis-image]: https://img.shields.io/travis/strongloop/express/master.svg?label=linux -[travis-url]: https://travis-ci.org/strongloop/express -[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows -[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express -[coveralls-image]: https://img.shields.io/coveralls/strongloop/express/master.svg -[coveralls-url]: https://coveralls.io/r/strongloop/express?branch=master -[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg -[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/ -[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg -[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/ +[npm-version-image]: https://badgen.net/npm/v/express +[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge +[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express +[Code of Conduct]: https://github.com/expressjs/.github/blob/HEAD/CODE_OF_CONDUCT.md +[Contributing Guide]: https://github.com/expressjs/.github/blob/HEAD/CONTRIBUTING.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..ff106d62104 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,56 @@ +# Security Policies and Procedures + +This document outlines security procedures and general policies for the Express +project. + + * [Reporting a Bug](#reporting-a-bug) + * [Disclosure Policy](#disclosure-policy) + * [Comments on this Policy](#comments-on-this-policy) + +## Reporting a Bug + +The Express team and community take all security bugs in Express seriously. +Thank you for improving the security of Express. We appreciate your efforts and +responsible disclosure and will make every effort to acknowledge your +contributions. + +Report security bugs by emailing `express-security@lists.openjsf.org`. + +To ensure the timely response to your report, please ensure that the entirety +of the report is contained within the email body and not solely behind a web +link or an attachment. + +The lead maintainer will acknowledge your email within 48 hours, and will send a +more detailed response within 48 hours indicating the next steps in handling +your report. After the initial reply to your report, the security team will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. + +Report security bugs in third-party modules to the person or team maintaining +the module. + +## Pre-release Versions + +Alpha and Beta releases are unstable and **not suitable for production use**. +Vulnerabilities found in pre-releases should be reported according to the [Reporting a Bug](#reporting-a-bug) section. +Due to the unstable nature of the branch it is not guaranteed that any fixes will be released in the next pre-release. + +## Disclosure Policy + +When the security team receives a security bug report, they will assign it to a +primary handler. This person will coordinate the fix and release process, +involving the following steps: + + * Confirm the problem and determine the affected versions. + * Audit code to find any potential similar problems. + * Prepare fixes for all releases still under maintenance. These fixes will be + released as fast as possible to npm. + +## The Express Threat Model + +We are currently working on a new version of the security model, the most updated version can be found [here](https://github.com/expressjs/security-wg/blob/main/docs/ThreatModel.md) + +## Comments on this Policy + +If you have suggestions on how this process could be improved please submit a +pull request. diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b1f13d167bd..00000000000 --- a/appveyor.yml +++ /dev/null @@ -1,18 +0,0 @@ -environment: - matrix: - - nodejs_version: "0.10" - - nodejs_version: "0.12" - - nodejs_version: "1.0" - - nodejs_version: "1.8" - - nodejs_version: "2.0" - - nodejs_version: "2.3" -install: - - ps: Install-Product node $env:nodejs_version - - npm rm --save-dev connect-redis - - npm install -build: off -test_script: - - node --version - - npm --version - - npm run test-ci -version: "{build}" diff --git a/benchmarks/Makefile b/benchmarks/Makefile index baf0d6fce92..ed1ddfc4f34 100644 --- a/benchmarks/Makefile +++ b/benchmarks/Makefile @@ -1,13 +1,17 @@ all: - @./run 1 middleware - @./run 5 middleware - @./run 10 middleware - @./run 15 middleware - @./run 20 middleware - @./run 30 middleware - @./run 50 middleware - @./run 100 middleware + @./run 1 middleware 50 + @./run 5 middleware 50 + @./run 10 middleware 50 + @./run 15 middleware 50 + @./run 20 middleware 50 + @./run 30 middleware 50 + @./run 50 middleware 50 + @./run 100 middleware 50 + @./run 10 middleware 100 + @./run 10 middleware 250 + @./run 10 middleware 500 + @./run 10 middleware 1000 @echo .PHONY: all diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 00000000000..1894c527d63 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,34 @@ +# Express Benchmarks + +## Installation + +You will need to install [wrk](https://github.com/wg/wrk/blob/master/INSTALL) in order to run the benchmarks. + +## Running + +To run the benchmarks, first install the dependencies `npm i`, then run `make` + +The output will look something like this: + +``` + 50 connections + 1 middleware + 7.15ms + 6784.01 + + [...redacted...] + + 1000 connections + 10 middleware + 139.21ms + 6155.19 + +``` + +### Tip: Include Node.js version in output + +You can use `make && node -v` to include the node.js version in the output. + +### Tip: Save the results to a file + +You can use `make > results.log` to save the results to a file `results.log`. diff --git a/benchmarks/middleware.js b/benchmarks/middleware.js index 3aa7a8b4ac7..fed97ba8ce4 100644 --- a/benchmarks/middleware.js +++ b/benchmarks/middleware.js @@ -1,5 +1,4 @@ -var http = require('http'); var express = require('..'); var app = express(); @@ -14,10 +13,8 @@ while (n--) { }); } -var body = new Buffer('Hello World'); - -app.use(function(req, res, next){ - res.send(body); +app.use(function(req, res){ + res.send('Hello World') }); app.listen(3333); diff --git a/benchmarks/run b/benchmarks/run index 93b5bc52ff2..ec8f55d5643 100755 --- a/benchmarks/run +++ b/benchmarks/run @@ -4,13 +4,15 @@ echo MW=$1 node $2 & pid=$! +echo " $3 connections" + sleep 2 wrk 'http://localhost:3333/?foo[bar]=baz' \ -d 3 \ - -c 50 \ + -c $3 \ -t 8 \ - | grep 'Requests/sec' \ - | awk '{ print " " $2 }' + | grep 'Requests/sec\|Latency' \ + | awk '{ print " " $2 }' kill $pid diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000000..bd1f1f6310f --- /dev/null +++ b/examples/README.md @@ -0,0 +1,29 @@ +# Express examples + +This page contains list of examples using Express. + +- [auth](./auth) - Authentication with login and password +- [content-negotiation](./content-negotiation) - HTTP content negotiation +- [cookie-sessions](./cookie-sessions) - Working with cookie-based sessions +- [cookies](./cookies) - Working with cookies +- [downloads](./downloads) - Transferring files to client +- [ejs](./ejs) - Working with Embedded JavaScript templating (ejs) +- [error-pages](./error-pages) - Creating error pages +- [error](./error) - Working with error middleware +- [hello-world](./hello-world) - Simple request handler +- [markdown](./markdown) - Markdown as template engine +- [multi-router](./multi-router) - Working with multiple Express routers +- [mvc](./mvc) - MVC-style controllers +- [online](./online) - Tracking online user activity with `online` and `redis` packages +- [params](./params) - Working with route parameters +- [resource](./resource) - Multiple HTTP operations on the same resource +- [route-map](./route-map) - Organizing routes using a map +- [route-middleware](./route-middleware) - Working with route middleware +- [route-separation](./route-separation) - Organizing routes per each resource +- [search](./search) - Search API +- [session](./session) - User sessions +- [static-files](./static-files) - Serving static files +- [vhost](./vhost) - Working with virtual hosts +- [view-constructor](./view-constructor) - Rendering views dynamically +- [view-locals](./view-locals) - Saving data in request object between middleware calls +- [web-service](./web-service) - Simple API service diff --git a/examples/auth/index.js b/examples/auth/index.js index d110fe28d42..40b73e6de16 100644 --- a/examples/auth/index.js +++ b/examples/auth/index.js @@ -1,10 +1,12 @@ +'use strict' + /** * Module dependencies. */ var express = require('../..'); -var hash = require('./pass').hash; -var bodyParser = require('body-parser'); +var hash = require('pbkdf2-password')() +var path = require('node:path'); var session = require('express-session'); var app = module.exports = express(); @@ -12,11 +14,11 @@ var app = module.exports = express(); // config app.set('view engine', 'ejs'); -app.set('views', __dirname + '/views'); +app.set('views', path.join(__dirname, 'views')); // middleware -app.use(bodyParser.urlencoded({ extended: false })); +app.use(express.urlencoded()) app.use(session({ resave: false, // don't save session if unmodified saveUninitialized: false, // don't create session until something stored @@ -45,7 +47,7 @@ var users = { // when you create a user, generate a salt // and hash the password ('foobar' is the pass here) -hash('foobar', function(err, salt, hash){ +hash({ password: 'foobar' }, function (err, pass, salt, hash) { if (err) throw err; // store the salt & hash in the "db" users.tj.salt = salt; @@ -59,14 +61,14 @@ function authenticate(name, pass, fn) { if (!module.parent) console.log('authenticating %s:%s', name, pass); var user = users[name]; // query the db for the given username - if (!user) return fn(new Error('cannot find user')); + if (!user) return fn(null, null) // apply the same algorithm to the POSTed password, applying // the hash against the pass / salt, if there is a match we // found the user - hash(pass, user.salt, function(err, hash){ + hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) { if (err) return fn(err); - if (hash == user.hash) return fn(null, user); - fn(new Error('invalid password')); + if (hash === user.hash) return fn(null, user) + fn(null, null) }); } @@ -99,8 +101,10 @@ app.get('/login', function(req, res){ res.render('login'); }); -app.post('/login', function(req, res){ +app.post('/login', function (req, res, next) { + if (!req.body) return res.sendStatus(400) authenticate(req.body.username, req.body.password, function(err, user){ + if (err) return next(err) if (user) { // Regenerate session when signing in // to prevent fixation @@ -112,7 +116,7 @@ app.post('/login', function(req, res){ req.session.success = 'Authenticated as ' + user.name + ' click to logout. ' + ' You may now access /restricted.'; - res.redirect('back'); + res.redirect(req.get('Referrer') || '/'); }); } else { req.session.error = 'Authentication failed, please check your ' diff --git a/examples/auth/pass.js b/examples/auth/pass.js deleted file mode 100644 index fefb25b66a5..00000000000 --- a/examples/auth/pass.js +++ /dev/null @@ -1,48 +0,0 @@ - -// check out https://github.com/tj/node-pwd - -/** - * Module dependencies. - */ - -var crypto = require('crypto'); - -/** - * Bytesize. - */ - -var len = 128; - -/** - * Iterations. ~300ms - */ - -var iterations = 12000; - -/** - * Hashes a password with optional `salt`, otherwise - * generate a salt for `pass` and invoke `fn(err, salt, hash)`. - * - * @param {String} password to hash - * @param {String} optional salt - * @param {Function} callback - * @api public - */ - -exports.hash = function (pwd, salt, fn) { - if (3 == arguments.length) { - crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){ - fn(err, hash.toString('base64')); - }); - } else { - fn = salt; - crypto.randomBytes(len, function(err, salt){ - if (err) return fn(err); - salt = salt.toString('base64'); - crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){ - if (err) return fn(err); - fn(null, salt, hash.toString('base64')); - }); - }); - } -}; diff --git a/examples/auth/views/head.ejs b/examples/auth/views/head.ejs index 0a919f49296..c623b5cc8d1 100644 --- a/examples/auth/views/head.ejs +++ b/examples/auth/views/head.ejs @@ -1,6 +1,8 @@ + + <%= title %> + + <%= title %> + diff --git a/examples/ejs/views/users.html b/examples/ejs/views/users.html index b0640750f2a..dad24625e65 100644 --- a/examples/ejs/views/users.html +++ b/examples/ejs/views/users.html @@ -1,4 +1,4 @@ -<% include header.html %> +<%- include('header.html') -%>

Users

-<% include footer.html %> +<%- include('footer.html') -%> diff --git a/examples/error-pages/index.js b/examples/error-pages/index.js index aff985bd674..0863120bc8f 100644 --- a/examples/error-pages/index.js +++ b/examples/error-pages/index.js @@ -1,14 +1,17 @@ +'use strict' + /** * Module dependencies. */ var express = require('../../'); +var path = require('node:path'); var app = module.exports = express(); var logger = require('morgan'); -var silent = 'test' == process.env.NODE_ENV; +var silent = process.env.NODE_ENV === 'test' // general config -app.set('views', __dirname + '/views'); +app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // our custom "verbose errors" setting @@ -18,7 +21,7 @@ app.enable('verbose errors'); // disable them in production // use $ NODE_ENV=production node examples/error-pages -if ('production' == app.settings.env) app.disable('verbose errors'); +if (app.settings.env === 'production') app.disable('verbose errors') silent || app.use(logger('dev')); @@ -60,20 +63,17 @@ app.get('/500', function(req, res, next){ app.use(function(req, res, next){ res.status(404); - // respond with html page - if (req.accepts('html')) { - res.render('404', { url: req.url }); - return; - } - - // respond with json - if (req.accepts('json')) { - res.send({ error: 'Not found' }); - return; - } - - // default to plain-text. send() - res.type('txt').send('Not found'); + res.format({ + html: function () { + res.render('404', { url: req.url }) + }, + json: function () { + res.json({ error: 'Not found' }) + }, + default: function () { + res.type('txt').send('Not found') + } + }) }); // error-handling middleware, take the same form diff --git a/examples/error-pages/views/404.ejs b/examples/error-pages/views/404.ejs index a72369e2d2c..d992ce02294 100644 --- a/examples/error-pages/views/404.ejs +++ b/examples/error-pages/views/404.ejs @@ -1,3 +1,3 @@ -<% include error_header %> +<%- include('error_header') -%>

Cannot find <%= url %>

-<% include footer %> +<%- include('footer') -%> diff --git a/examples/error-pages/views/500.ejs b/examples/error-pages/views/500.ejs index 8c1e0e80fb8..c9d855f8044 100644 --- a/examples/error-pages/views/500.ejs +++ b/examples/error-pages/views/500.ejs @@ -1,8 +1,8 @@ -<% include error_header %> +<%- include('error_header') -%>

Error: <%= error.message %>

<% if (settings['verbose errors']) { %>
<%= error.stack %>
<% } else { %>

An error occurred!

<% } %> -<% include footer %> +<%- include('footer') -%> diff --git a/examples/error-pages/views/error_header.ejs b/examples/error-pages/views/error_header.ejs index 6d541dd9f5c..b2451ab3241 100644 --- a/examples/error-pages/views/error_header.ejs +++ b/examples/error-pages/views/error_header.ejs @@ -1,6 +1,8 @@ + + Error diff --git a/examples/error-pages/views/index.ejs b/examples/error-pages/views/index.ejs index 04a1a7847b9..ae8c92820a7 100644 --- a/examples/error-pages/views/index.ejs +++ b/examples/error-pages/views/index.ejs @@ -1,6 +1,8 @@ + + Custom Pages Example diff --git a/examples/error/index.js b/examples/error/index.js index d7db5015a13..d733a81172d 100644 --- a/examples/error/index.js +++ b/examples/error/index.js @@ -1,3 +1,5 @@ +'use strict' + /** * Module dependencies. */ @@ -5,7 +7,7 @@ var express = require('../../'); var logger = require('morgan'); var app = module.exports = express(); -var test = app.get('env') == 'test'; +var test = app.get('env') === 'test' if (!test) app.use(logger('dev')); @@ -24,13 +26,16 @@ function error(err, req, res, next) { res.send('Internal Server Error'); } -app.get('/', function(req, res){ +app.get('/', function () { // Caught and passed down to the errorHandler middleware throw new Error('something broke!'); }); app.get('/next', function(req, res, next){ // We can also pass exceptions to next() + // The reason for process.nextTick() is to show that + // next() can be called inside an async operation, + // in real life it can be a DB read or HTTP request. process.nextTick(function(){ next(new Error('oh no!')); }); diff --git a/examples/expose-data-to-client/index.js b/examples/expose-data-to-client/index.js deleted file mode 100644 index 5dd99df682a..00000000000 --- a/examples/expose-data-to-client/index.js +++ /dev/null @@ -1,64 +0,0 @@ - -var express = require('../..'); -var logger = require('morgan'); -var app = express(); - -app.set('view engine', 'jade'); -app.set('views', __dirname + '/views'); - -function User(name) { - this.private = 'heyyyy'; - this.secret = 'something'; - this.name = name; - this.id = 123; -} - -// You'll probably want to do -// something like this so you -// dont expose "secret" data. - -User.prototype.toJSON = function(){ - return { - id: this.id, - name: this.name - }; -}; - -app.use(logger('dev')); - -// earlier on expose an object -// that we can tack properties on. -// all res.locals props are exposed -// to the templates, so "expose" will -// be present. - -app.use(function(req, res, next){ - res.locals.expose = {}; - // you could alias this as req or res.expose - // to make it shorter and less annoying - next(); -}); - -// pretend we loaded a user - -app.use(function(req, res, next){ - req.user = new User('Tobi'); - next(); -}); - -app.get('/', function(req, res){ - res.redirect('/user'); -}); - -app.get('/user', function(req, res){ - // we only want to expose the user - // to the client for this route: - res.locals.expose.user = req.user; - res.render('page'); -}); - -/* istanbul ignore next */ -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} diff --git a/examples/expose-data-to-client/views/page.jade b/examples/expose-data-to-client/views/page.jade deleted file mode 100644 index 6e58a18afbc..00000000000 --- a/examples/expose-data-to-client/views/page.jade +++ /dev/null @@ -1,14 +0,0 @@ -html - head - title Express - script. - // call this whatever you like, - // or dump them into individual - // props like "var user =" - var data = !{JSON.stringify(expose)} - body - h1 Expose client data - p The following was exposed to the client: - pre - script. - document.write(JSON.stringify(data, null, 2)) \ No newline at end of file diff --git a/examples/hello-world/index.js b/examples/hello-world/index.js index 04382ac3d0b..8c1855c2eb7 100644 --- a/examples/hello-world/index.js +++ b/examples/hello-world/index.js @@ -1,6 +1,8 @@ +'use strict' + var express = require('../../'); -var app = express(); +var app = module.exports = express() app.get('/', function(req, res){ res.send('Hello World'); diff --git a/examples/jade/index.js b/examples/jade/index.js deleted file mode 100644 index 738b382d267..00000000000 --- a/examples/jade/index.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Module dependencies. - */ - -var express = require('../../lib/express'); - -// Path to our public directory - -var pub = __dirname + '/public'; - -// setup middleware - -var app = express(); -app.use(express.static(pub)); - -// Optional since express defaults to CWD/views - -app.set('views', __dirname + '/views'); - -// Set our default template engine to "jade" -// which prevents the need for extensions -// (although you can still mix and match) -app.set('view engine', 'jade'); - -function User(name, email) { - this.name = name; - this.email = email; -} - -// Dummy users -var users = [ - new User('tj', 'tj@vision-media.ca') - , new User('ciaran', 'ciaranj@gmail.com') - , new User('aaron', 'aaron.heckmann+github@gmail.com') -]; - -app.get('/', function(req, res){ - res.render('users', { users: users }); -}); - -// change this to a better error handler in your code -// sending stacktrace to users in production is not good -app.use(function(err, req, res, next) { - res.send(err.stack); -}); - -/* istanbul ignore next */ -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} diff --git a/examples/jade/public/stylesheets/style.css b/examples/jade/public/stylesheets/style.css deleted file mode 100644 index c4593b44211..00000000000 --- a/examples/jade/public/stylesheets/style.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - padding: 50px 80px; - font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif; -} diff --git a/examples/jade/views/header.jade b/examples/jade/views/header.jade deleted file mode 100644 index 6c42929d837..00000000000 --- a/examples/jade/views/header.jade +++ /dev/null @@ -1,3 +0,0 @@ -head - title Jade Example - link(rel="stylesheet", href="http://github.com/stylesheets/style.css") \ No newline at end of file diff --git a/examples/jade/views/layout.jade b/examples/jade/views/layout.jade deleted file mode 100644 index 300cdc78473..00000000000 --- a/examples/jade/views/layout.jade +++ /dev/null @@ -1,5 +0,0 @@ -doctype html -html - include header - body - block content diff --git a/examples/jade/views/users/index.jade b/examples/jade/views/users/index.jade deleted file mode 100644 index feb7623fa3d..00000000000 --- a/examples/jade/views/users/index.jade +++ /dev/null @@ -1,8 +0,0 @@ - -extends ../layout - -block content - h1 Users - #users - for user in users - include user \ No newline at end of file diff --git a/examples/jade/views/users/user.jade b/examples/jade/views/users/user.jade deleted file mode 100644 index 9e603298cbf..00000000000 --- a/examples/jade/views/users/user.jade +++ /dev/null @@ -1,3 +0,0 @@ -.user - h2= user.name - .email= user.email \ No newline at end of file diff --git a/examples/markdown/index.js b/examples/markdown/index.js index db2f16fb482..53e40ac38e4 100644 --- a/examples/markdown/index.js +++ b/examples/markdown/index.js @@ -1,10 +1,14 @@ +'use strict' + /** * Module dependencies. */ +var escapeHtml = require('escape-html'); var express = require('../..'); -var fs = require('fs'); -var md = require('marked').parse; +var fs = require('node:fs'); +var marked = require('marked'); +var path = require('node:path'); var app = module.exports = express(); @@ -13,21 +17,16 @@ var app = module.exports = express(); app.engine('md', function(path, options, fn){ fs.readFile(path, 'utf8', function(err, str){ if (err) return fn(err); - try { - var html = md(str); - html = html.replace(/\{([^}]+)\}/g, function(_, name){ - return options[name] || ''; - }); - fn(null, html); - } catch(err) { - fn(err); - } + var html = marked.parse(str).replace(/\{([^}]+)\}/g, function(_, name){ + return escapeHtml(options[name] || ''); + }); + fn(null, html); }); }); -app.set('views', __dirname + '/views'); +app.set('views', path.join(__dirname, 'views')); -// make it the default so we dont need .md +// make it the default, so we don't need .md app.set('view engine', 'md'); app.get('/', function(req, res){ diff --git a/examples/multi-router/controllers/api_v1.js b/examples/multi-router/controllers/api_v1.js index 08b7b5e6fdd..a301e3ee72d 100644 --- a/examples/multi-router/controllers/api_v1.js +++ b/examples/multi-router/controllers/api_v1.js @@ -1,3 +1,5 @@ +'use strict' + var express = require('../../..'); var apiv1 = express.Router(); diff --git a/examples/multi-router/controllers/api_v2.js b/examples/multi-router/controllers/api_v2.js index 4dd708281c2..e997fb1f88c 100644 --- a/examples/multi-router/controllers/api_v2.js +++ b/examples/multi-router/controllers/api_v2.js @@ -1,3 +1,5 @@ +'use strict' + var express = require('../../..'); var apiv2 = express.Router(); diff --git a/examples/multi-router/index.js b/examples/multi-router/index.js index ff31e514a56..dbfd2841262 100644 --- a/examples/multi-router/index.js +++ b/examples/multi-router/index.js @@ -1,3 +1,5 @@ +'use strict' + var express = require('../..'); var app = module.exports = express(); @@ -6,7 +8,7 @@ app.use('/api/v1', require('./controllers/api_v1')); app.use('/api/v2', require('./controllers/api_v2')); app.get('/', function(req, res) { - res.send('Hello form root route.'); + res.send('Hello from root route.') }); /* istanbul ignore next */ diff --git a/examples/multipart/index.js b/examples/multipart/index.js deleted file mode 100644 index 42c2af23f74..00000000000 --- a/examples/multipart/index.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Module dependencies. - */ - -var express = require('../..'); -var multiparty = require('multiparty'); -var format = require('util').format; - -var app = module.exports = express(); - -app.get('/', function(req, res){ - res.send('
' - + '

Title:

' - + '

Image:

' - + '

' - + '
'); -}); - -app.post('/', function(req, res, next){ - // create a form to begin parsing - var form = new multiparty.Form(); - var image; - var title; - - form.on('error', next); - form.on('close', function(){ - res.send(format('\nuploaded %s (%d Kb) as %s' - , image.filename - , image.size / 1024 | 0 - , title)); - }); - - // listen on field event for title - form.on('field', function(name, val){ - if (name !== 'title') return; - title = val; - }); - - // listen on part event for image file - form.on('part', function(part){ - if (!part.filename) return; - if (part.name !== 'image') return part.resume(); - image = {}; - image.filename = part.filename; - image.size = 0; - part.on('data', function(buf){ - image.size += buf.length; - }); - }); - - - // parse the form - form.parse(req); -}); - -/* istanbul ignore next */ -if (!module.parent) { - app.listen(4000); - console.log('Express started on port 4000'); -} diff --git a/examples/mvc/controllers/main/index.js b/examples/mvc/controllers/main/index.js index 83db90f6f20..74cde191cd8 100644 --- a/examples/mvc/controllers/main/index.js +++ b/examples/mvc/controllers/main/index.js @@ -1,3 +1,5 @@ +'use strict' + exports.index = function(req, res){ res.redirect('/users'); -}; \ No newline at end of file +}; diff --git a/examples/mvc/controllers/pet/index.js b/examples/mvc/controllers/pet/index.js index 157a98e84e2..214160f9a46 100644 --- a/examples/mvc/controllers/pet/index.js +++ b/examples/mvc/controllers/pet/index.js @@ -1,3 +1,5 @@ +'use strict' + /** * Module dependencies. */ diff --git a/examples/mvc/controllers/pet/views/edit.ejs b/examples/mvc/controllers/pet/views/edit.ejs index fc697c25500..655666e0109 100644 --- a/examples/mvc/controllers/pet/views/edit.ejs +++ b/examples/mvc/controllers/pet/views/edit.ejs @@ -1,6 +1,8 @@ + + Edit <%= pet.name %> diff --git a/examples/mvc/controllers/pet/views/show.ejs b/examples/mvc/controllers/pet/views/show.ejs index 2ec7b0bf063..7e1e338e7d8 100644 --- a/examples/mvc/controllers/pet/views/show.ejs +++ b/examples/mvc/controllers/pet/views/show.ejs @@ -1,6 +1,8 @@ + + <%= pet.name %> diff --git a/examples/mvc/controllers/user-pet/index.js b/examples/mvc/controllers/user-pet/index.js index 416b00741a2..42a29adebe7 100644 --- a/examples/mvc/controllers/user-pet/index.js +++ b/examples/mvc/controllers/user-pet/index.js @@ -1,3 +1,5 @@ +'use strict' + /** * Module dependencies. */ diff --git a/examples/mvc/controllers/user/index.js b/examples/mvc/controllers/user/index.js index 9ccbcccb9ca..ec3ae4c8110 100644 --- a/examples/mvc/controllers/user/index.js +++ b/examples/mvc/controllers/user/index.js @@ -1,9 +1,13 @@ +'use strict' + /** * Module dependencies. */ var db = require('../../db'); +exports.engine = 'hbs'; + exports.before = function(req, res, next){ var id = req.params.user_id; if (!id) return next(); diff --git a/examples/mvc/controllers/user/views/edit.hbs b/examples/mvc/controllers/user/views/edit.hbs new file mode 100644 index 00000000000..2be7ddc4a94 --- /dev/null +++ b/examples/mvc/controllers/user/views/edit.hbs @@ -0,0 +1,27 @@ + + + + + + + Edit {{user.name}} + + +

{{user.name}}

+
+ + + +
+ +
+ + + +
+ + diff --git a/examples/mvc/controllers/user/views/edit.jade b/examples/mvc/controllers/user/views/edit.jade deleted file mode 100644 index a2fde5d477e..00000000000 --- a/examples/mvc/controllers/user/views/edit.jade +++ /dev/null @@ -1,11 +0,0 @@ -link(rel='stylesheet', href='http://github.com/style.css') -h1= user.name -form(action='http://github.com/user/#{user.id}?_method=put', method='post') - label= 'Name: ' - input(type='text', name='user[name]', value='#{user.name}') - input(type='submit', value='Update') - -form(action='http://github.com/user/#{user.id}/pet', method='post') - label= 'Pet: ' - input(type='text', name='pet[name]', placeholder='Name') - input(type='submit', value='Add') diff --git a/examples/mvc/controllers/user/views/list.hbs b/examples/mvc/controllers/user/views/list.hbs new file mode 100644 index 00000000000..448c66f8c78 --- /dev/null +++ b/examples/mvc/controllers/user/views/list.hbs @@ -0,0 +1,18 @@ + + + + + + + Users + + +

Users

+

Click a user below to view their pets.

+ + + diff --git a/examples/mvc/controllers/user/views/list.jade b/examples/mvc/controllers/user/views/list.jade deleted file mode 100644 index af8933cfe05..00000000000 --- a/examples/mvc/controllers/user/views/list.jade +++ /dev/null @@ -1,7 +0,0 @@ -link(rel='stylesheet', href='http://github.com/style.css') -h1 Users -p Click a user below to view their pets. -ul - each user in users - li - a(href='http://github.com/user/#{user.id}')= user.name diff --git a/examples/mvc/controllers/user/views/show.hbs b/examples/mvc/controllers/user/views/show.hbs new file mode 100644 index 00000000000..f3fccfe046b --- /dev/null +++ b/examples/mvc/controllers/user/views/show.hbs @@ -0,0 +1,31 @@ + + + + + + + {{user.name}} + + +

{{user.name}} edit

+ +{{#if hasMessages}} + +{{/if}} + +{{#if user.pets.length}} +

View {{user.name}}'s pets:

+ +{{else}} +

No pets!

+{{/if}} + + diff --git a/examples/mvc/controllers/user/views/show.jade b/examples/mvc/controllers/user/views/show.jade deleted file mode 100644 index 267d3ef7e40..00000000000 --- a/examples/mvc/controllers/user/views/show.jade +++ /dev/null @@ -1,17 +0,0 @@ -link(rel='stylesheet', href='http://github.com/style.css') -h1= user.name + ' ' - a(href='http://github.com/user/#{user.id}/edit') edit - -if (hasMessages) - ul#messages - each msg in messages - li= msg - -if (user.pets.length) - p View #{user.name}'s pets: - ul - each pet in user.pets - li - a(href='http://github.com/pet/#{pet.id}')= pet.name -else - p No pets! diff --git a/examples/mvc/db.js b/examples/mvc/db.js index 565fdfaa507..94d1480f9b7 100644 --- a/examples/mvc/db.js +++ b/examples/mvc/db.js @@ -1,3 +1,5 @@ +'use strict' + // faux database var pets = exports.pets = []; @@ -11,4 +13,4 @@ var users = exports.users = []; users.push({ name: 'TJ', pets: [pets[0], pets[1], pets[2]], id: 0 }); users.push({ name: 'Guillermo', pets: [pets[3]], id: 1 }); -users.push({ name: 'Nathan', pets: [], id: 2 }); \ No newline at end of file +users.push({ name: 'Nathan', pets: [], id: 2 }); diff --git a/examples/mvc/index.js b/examples/mvc/index.js index bf7f726e30f..1d8aa0e3c31 100644 --- a/examples/mvc/index.js +++ b/examples/mvc/index.js @@ -1,23 +1,23 @@ +'use strict' + /** * Module dependencies. */ var express = require('../..'); var logger = require('morgan'); +var path = require('node:path'); var session = require('express-session'); -var bodyParser = require('body-parser'); var methodOverride = require('method-override'); var app = module.exports = express(); -// settings - -// set our default template engine to "jade" -// which prevents the need for extensions -app.set('view engine', 'jade'); +// set our default template engine to "ejs" +// which prevents the need for using file extensions +app.set('view engine', 'ejs'); // set views for error and 404 pages -app.set('views', __dirname + '/views'); +app.set('views', path.join(__dirname, 'views')); // define a custom res.message() method // which stores messages in the session @@ -34,7 +34,7 @@ app.response.message = function(msg){ if (!module.parent) app.use(logger('dev')); // serve static files -app.use(express.static(__dirname + '/public')); +app.use(express.static(path.join(__dirname, 'public'))); // session support app.use(session({ @@ -44,7 +44,7 @@ app.use(session({ })); // parse request bodies (req.body) -app.use(bodyParser.urlencoded({ extended: true })); +app.use(express.urlencoded({ extended: true })) // allow overriding methods in query (?_method=put) app.use(methodOverride('_method')); diff --git a/examples/mvc/lib/boot.js b/examples/mvc/lib/boot.js index 78e82db1bfb..fc2ab0fad99 100644 --- a/examples/mvc/lib/boot.js +++ b/examples/mvc/lib/boot.js @@ -1,25 +1,31 @@ +'use strict' + /** * Module dependencies. */ var express = require('../../..'); -var fs = require('fs'); +var fs = require('node:fs'); +var path = require('node:path'); module.exports = function(parent, options){ + var dir = path.join(__dirname, '..', 'controllers'); var verbose = options.verbose; - fs.readdirSync(__dirname + '/../controllers').forEach(function(name){ + fs.readdirSync(dir).forEach(function(name){ + var file = path.join(dir, name) + if (!fs.statSync(file).isDirectory()) return; verbose && console.log('\n %s:', name); - var obj = require('./../controllers/' + name); + var obj = require(file); var name = obj.name || name; var prefix = obj.prefix || ''; var app = express(); var handler; var method; - var path; + var url; // allow specifying the view engine if (obj.engine) app.set('view engine', obj.engine); - app.set('views', __dirname + '/../controllers/' + name + '/views'); + app.set('views', path.join(__dirname, '..', 'controllers', name, 'views')); // generate routes based // on the exported methods @@ -30,27 +36,27 @@ module.exports = function(parent, options){ switch (key) { case 'show': method = 'get'; - path = '/' + name + '/:' + name + '_id'; + url = '/' + name + '/:' + name + '_id'; break; case 'list': method = 'get'; - path = '/' + name + 's'; + url = '/' + name + 's'; break; case 'edit': method = 'get'; - path = '/' + name + '/:' + name + '_id/edit'; + url = '/' + name + '/:' + name + '_id/edit'; break; case 'update': method = 'put'; - path = '/' + name + '/:' + name + '_id'; + url = '/' + name + '/:' + name + '_id'; break; case 'create': method = 'post'; - path = '/' + name; + url = '/' + name; break; case 'index': method = 'get'; - path = '/'; + url = '/'; break; default: /* istanbul ignore next */ @@ -59,15 +65,15 @@ module.exports = function(parent, options){ // setup handler = obj[key]; - path = prefix + path; + url = prefix + url; // before middleware support if (obj.before) { - app[method](path, obj.before, handler); - verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), path, key); + app[method](url, obj.before, handler); + verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), url, key); } else { - app[method](path, handler); - verbose && console.log(' %s %s -> %s', method.toUpperCase(), path, key); + app[method](url, handler); + verbose && console.log(' %s %s -> %s', method.toUpperCase(), url, key); } } diff --git a/examples/mvc/public/style.css b/examples/mvc/public/style.css index 69fde2e23aa..8a23f9d41c4 100644 --- a/examples/mvc/public/style.css +++ b/examples/mvc/public/style.css @@ -1,6 +1,6 @@ body { padding: 50px; - font: 16px "Helvetica Neue", Helvetica, Arial; + font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif; } a { color: #107aff; diff --git a/examples/mvc/views/404.ejs b/examples/mvc/views/404.ejs new file mode 100644 index 00000000000..21a86f8a653 --- /dev/null +++ b/examples/mvc/views/404.ejs @@ -0,0 +1,13 @@ + + + + + + Not Found + + + +

404: Not Found

+

Sorry we can't find <%= url %>

+ + diff --git a/examples/mvc/views/404.jade b/examples/mvc/views/404.jade deleted file mode 100644 index 110c471f1b9..00000000000 --- a/examples/mvc/views/404.jade +++ /dev/null @@ -1,3 +0,0 @@ -link(rel='stylesheet', href='http://github.com/style.css') -h1 404: Not Found -p Sorry we can't find #{url} diff --git a/examples/mvc/views/5xx.ejs b/examples/mvc/views/5xx.ejs new file mode 100644 index 00000000000..190f580543a --- /dev/null +++ b/examples/mvc/views/5xx.ejs @@ -0,0 +1,13 @@ + + + + + + Internal Server Error + + + +

500: Internal Server Error

+

Looks like something blew up!

+ + diff --git a/examples/mvc/views/5xx.jade b/examples/mvc/views/5xx.jade deleted file mode 100644 index 3508b7c0e2a..00000000000 --- a/examples/mvc/views/5xx.jade +++ /dev/null @@ -1,3 +0,0 @@ -link(rel='stylesheet', href='http://github.com/style.css') -h1 500: Internal Server Error -p Looks like something blew up! diff --git a/examples/online/index.js b/examples/online/index.js index 5cdaa6ca8d2..0b5fdffc86a 100644 --- a/examples/online/index.js +++ b/examples/online/index.js @@ -1,4 +1,9 @@ -// first: +'use strict' + +// install redis first: +// https://redis.io/ + +// then: // $ npm install redis online // $ redis-server diff --git a/examples/params/index.js b/examples/params/index.js index d70f0beeeb1..11eef51a592 100644 --- a/examples/params/index.js +++ b/examples/params/index.js @@ -1,28 +1,23 @@ +'use strict' + /** * Module dependencies. */ +var createError = require('http-errors') var express = require('../../'); var app = module.exports = express(); // Faux database var users = [ - { name: 'tj' } + { name: 'tj' } , { name: 'tobi' } , { name: 'loki' } , { name: 'jane' } , { name: 'bandit' } ]; -// Create HTTP error - -function createError(status, message) { - var err = new Error(message); - err.status = status; - return err; -} - // Convert :to and :from to integers app.param(['to', 'from'], function(req, res, next, num, name){ @@ -37,7 +32,8 @@ app.param(['to', 'from'], function(req, res, next, num, name){ // Load user by id app.param('user', function(req, res, next, id){ - if (req.user = users[id]) { + req.user = users[id] + if (req.user) { next(); } else { next(createError(404, 'failed to find user')); @@ -56,7 +52,7 @@ app.get('/', function(req, res){ * GET :user. */ -app.get('/user/:user', function(req, res, next){ +app.get('/user/:user', function (req, res) { res.send('user ' + req.user.name); }); @@ -64,11 +60,11 @@ app.get('/user/:user', function(req, res, next){ * GET users :from - :to. */ -app.get('/users/:from-:to', function(req, res, next){ +app.get('/users/:from-:to', function (req, res) { var from = req.params.from; var to = req.params.to; var names = users.map(function(user){ return user.name; }); - res.send('users ' + names.slice(from, to).join(', ')); + res.send('users ' + names.slice(from, to + 1).join(', ')); }); /* istanbul ignore next */ diff --git a/examples/resource/index.js b/examples/resource/index.js index 9137167cdf9..627ab24c5a2 100644 --- a/examples/resource/index.js +++ b/examples/resource/index.js @@ -1,3 +1,5 @@ +'use strict' + /** * Module dependencies. */ @@ -10,7 +12,7 @@ var app = module.exports = express(); app.resource = function(path, obj) { this.get(path, obj.index); - this.get(path + '/:a..:b.:format?', function(req, res){ + this.get(path + '/:a..:b{.:format}', function(req, res){ var a = parseInt(req.params.a, 10); var b = parseInt(req.params.b, 10); var format = req.params.format; @@ -26,7 +28,7 @@ app.resource = function(path, obj) { // Fake records var users = [ - { name: 'tj' } + { name: 'tj' } , { name: 'ciaran' } , { name: 'aaron' } , { name: 'guillermo' } @@ -75,7 +77,7 @@ app.resource('/users', User); app.get('/', function(req, res){ res.send([ - '

Examples: