pax_global_header00006660000000000000000000000064142033263760014520gustar00rootroot0000000000000052 comment=3d7fce56a35f4f73fa437866cd1401587a212334 express-4.17.3/000077500000000000000000000000001420332637600133055ustar00rootroot00000000000000express-4.17.3/.editorconfig000066400000000000000000000002631420332637600157630ustar00rootroot00000000000000# http://editorconfig.org root = true [*] charset = utf-8 insert_final_newline = true trim_trailing_whitespace = true [{*.js,*.json,*.yml}] indent_size = 2 indent_style = space express-4.17.3/.eslintignore000066400000000000000000000000261420332637600160060ustar00rootroot00000000000000coverage node_modules express-4.17.3/.eslintrc.yml000066400000000000000000000003571420332637600157360ustar00rootroot00000000000000root: 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 }] express-4.17.3/.github/000077500000000000000000000000001420332637600146455ustar00rootroot00000000000000express-4.17.3/.github/workflows/000077500000000000000000000000001420332637600167025ustar00rootroot00000000000000express-4.17.3/.github/workflows/ci.yml000066400000000000000000000100251420332637600200160ustar00rootroot00000000000000name: ci on: - pull_request - push jobs: test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: name: - Node.js 0.10 - Node.js 0.12 - io.js 1.x - io.js 2.x - io.js 3.x - Node.js 4.x - Node.js 5.x - Node.js 6.x - Node.js 7.x - Node.js 8.x - Node.js 9.x - Node.js 10.x - Node.js 11.x - Node.js 12.x - Node.js 13.x - Node.js 14.x include: - name: Node.js 0.10 node-version: "0.10" npm-i: mocha@3.5.3 nyc@10.3.2 supertest@2.0.0 - name: Node.js 0.12 node-version: "0.12" npm-i: mocha@3.5.3 nyc@10.3.2 supertest@2.0.0 - name: io.js 1.x node-version: "1.8" npm-i: mocha@3.5.3 nyc@10.3.2 supertest@2.0.0 - name: io.js 2.x node-version: "2.5" npm-i: mocha@3.5.3 nyc@10.3.2 supertest@2.0.0 - name: io.js 3.x node-version: "3.3" npm-i: mocha@3.5.3 nyc@10.3.2 supertest@2.0.0 - name: Node.js 4.x node-version: "4.9" npm-i: mocha@5.2.0 nyc@11.9.0 supertest@3.4.2 - name: Node.js 5.x node-version: "5.12" npm-i: mocha@5.2.0 nyc@11.9.0 supertest@3.4.2 - name: Node.js 6.x node-version: "6.17" npm-i: mocha@6.2.2 nyc@14.1.1 supertest@6.1.6 - name: Node.js 7.x node-version: "7.10" npm-i: mocha@6.2.2 nyc@14.1.1 supertest@6.1.6 - name: Node.js 8.x node-version: "8.17" npm-i: mocha@7.2.0 - name: Node.js 9.x node-version: "9.11" npm-i: mocha@7.2.0 - name: Node.js 10.x node-version: "10.24" npm-i: mocha@8.4.0 - name: Node.js 11.x node-version: "11.15" npm-i: mocha@8.4.0 - name: Node.js 12.x node-version: "12.22" - name: Node.js 13.x node-version: "13.14" - name: Node.js 14.x node-version: "14.19" steps: - uses: actions/checkout@v2 - name: Install Node.js ${{ matrix.node-version }} shell: bash -eo pipefail -l {0} run: | nvm install --default ${{ matrix.node-version }} dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH" - name: Configure npm run: | npm config set loglevel error npm config set shrinkwrap false - name: Install npm module(s) ${{ matrix.npm-i }} run: npm install --save-dev ${{ matrix.npm-i }} if: matrix.npm-i != '' - name: Remove non-test dependencies run: npm rm --silent --save-dev connect-redis - name: Setup Node.js version-specific dependencies shell: bash run: | # eslint for linting # - remove on Node.js < 10 if [[ "$(cut -d. -f1 <<< "${{ matrix.node-version }}")" -lt 10 ]]; then node -pe 'Object.keys(require("./package").devDependencies).join("\n")' | \ grep -E '^eslint(-|$)' | \ sort -r | \ xargs -n1 npm rm --silent --save-dev fi - name: Install Node.js dependencies run: npm install - name: List environment id: list_env shell: bash run: | echo "node@$(node -v)" echo "npm@$(npm -v)" npm -s ls ||: (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print "::set-output name=" $2 "::" $3 }' - name: Run tests shell: bash run: npm run test-ci - name: Lint code if: steps.list_env.outputs.eslint != '' run: npm run lint - name: Collect code coverage uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} flag-name: run-${{ matrix.test_number }} parallel: true coverage: needs: test runs-on: ubuntu-latest steps: - name: Upload code coverage uses: coverallsapp/github-action@master with: github-token: ${{ secrets.github_token }} parallel-finished: true express-4.17.3/.gitignore000066400000000000000000000003141420332637600152730ustar00rootroot00000000000000# npm node_modules package-lock.json *.log *.gz # Coveralls .nyc_output coverage # Benchmarking benchmarks/graphs # ignore additional files using core.excludesFile # https://git-scm.com/docs/gitignore express-4.17.3/Charter.md000066400000000000000000000067251420332637600152310ustar00rootroot00000000000000# Express Charter ## Section 0: Guiding Principles The Express project is part of the OpenJS Foundation which operates transparently, openly, collaboratively, and ethically. Project proposals, timelines, and status must not merely be open, but also easily visible to outsiders. ## Section 1: Scope Express is a http web server framework with a simple and expressive API which is highly aligned with Node.js core. We aim to be the best in class for writing performant, spec compliant, and powerful web servers in Node.js. As one of the oldest and most popular web frameworks in the ecosystem, we have an important place for new users and experts alike. ### 1.1: In-scope Express is made of many modules spread between three GitHub Orgs: - [expressjs](http://github.com/expressjs/): Top level middleware and libraries - [pillarjs](http://github.com/pillarjs/): Components which make up Express but can also be used for other web frameworks - [jshttp](http://github.com/jshttp/): Low level http libraries ### 1.2: Out-of-Scope Section Intentionally Left Blank ## Section 2: Relationship with OpenJS Foundation CPC. Technical leadership for the projects within the OpenJS Foundation is delegated to the projects through their project charters by the OpenJS Cross Project Council (CPC). In the case of the Express project, it is delegated to the Express Technical Committee ("TC"). This Technical Committee is in charge of both the day-to-day operations of the project, as well as its technical management. This charter can be amended by the TC requiring at least two approvals and a minimum two week comment period for other TC members or CPC members to object. Any changes the CPC wishes to propose will be considered a priority but will follow the same process. ### 2.1 Other Formal Project Relationships Section Intentionally Left Blank ## Section 3: Express Governing Body The Express project is managed by the Technical Committee ("TC"). Members can be added to the TC at any time. Any committer can nominate another committer to the TC and the TC uses its standard consensus seeking process to evaluate whether or not to add this new member. Members who do not participate consistently at the level of a majority of the other members are expected to resign. ## Section 4: Roles & Responsibilities The Express TC manages all aspects of both the technical and community parts of the project. Members of the TC should attend the regular meetings when possible, and be available for discussion of time sensitive or important issues. ### Section 4.1 Project Operations & Management Section Intentionally Left Blank ### Section 4.2: Decision-making, Voting, and/or Elections The Express TC uses a "consensus seeking" process for issues that are escalated to the TC. The group tries to find a resolution that has no open objections among TC members. If a consensus cannot be reached that has no objections then a majority wins vote is called. It is also expected that the majority of decisions made by the TC are via a consensus seeking process and that voting is only used as a last-resort. Resolution may involve returning the issue to committers with suggestions on how to move forward towards a consensus. It is not expected that a meeting of the TC will resolve all issues on its agenda during that meeting and may prefer to continue the discussion happening among the committers. ### Section 4.3: Other Project Roles Section Intentionally Left Blank ## Section 5: Definitions Section Intentionally Left Blank express-4.17.3/Code-Of-Conduct.md000066400000000000000000000132511420332637600164420ustar00rootroot00000000000000# Contributor Covenant Code of Conduct As a member of the Open JS Foundation, Express has adopted the [Contributor Covenant 2.0][cc-20-doc]. If an issue arises and you cannot resolve it directly with the parties involved, you can report it to the Express project TC through the following email: express-coc@lists.openjsf.org In addition, the OpenJS Foundation maintains a Code of Conduct Panel (CoCP). This is a foundation-wide team established to manage escalation when a reporter believes that a report to a member project or the CPC has not been properly handled. In order to escalate to the CoCP send an email to coc-escalation@lists.openjsf.org. ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at express-coc@lists.openjsf.org. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the project community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant, version 2.0](cc-20-doc). Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [cc-20-doc]: https://www.contributor-covenant.org/version/2/0/code_of_conduct/ For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. express-4.17.3/Collaborator-Guide.md000066400000000000000000000036621420332637600173140ustar00rootroot00000000000000# Express Collaborator Guide ## Website Issues Open issues for the expressjs.com website in https://github.com/expressjs/expressjs.com. ## PRs and Code contributions * Tests must pass. * Follow the [JavaScript Standard Style](http://standardjs.com/) and `npm run lint`. * If you fix a bug, add a test. ## Branches Use the `master` branch for bug fixes or minor work that is intended for the current release stream. Use the correspondingly named branch, e.g. `5.0`, for anything intended for a future release of Express. ## Steps for contributing 1. [Create an issue](https://github.com/expressjs/express/issues/new) for the bug you want to fix or the feature that you want to add. 2. Create your own [fork](https://github.com/expressjs/express) on GitHub, then checkout your fork. 3. Write your code in your local copy. It's good practice to create a branch for each new issue you work on, although not compulsory. 4. To run the test suite, first install the dependencies by running `npm install`, then run `npm test`. 5. Ensure your code is linted by running `npm run lint` -- fix any issue you see listed. 6. If the tests pass, you can commit your changes to your fork and then create a pull request from there. Make sure to reference your issue from the pull request comments by including the issue number e.g. `#123`. ## 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. express-4.17.3/Contributing.md000066400000000000000000000123651420332637600163050ustar00rootroot00000000000000# Express.js Community Contributing Guide 1.0 The goal of this document is to create a contribution process that: * Encourages new contributions. * Encourages contributors to remain involved. * Avoids unnecessary processes and bureaucracy whenever possible. * Creates a transparent decision making process that makes it clear how contributors can be involved in decision making. ## Vocabulary * A **Contributor** is any individual creating or commenting on an issue or pull request. * A **Committer** is a subset of contributors who have been given write access to the repository. * A **TC (Technical Committee)** is a group of committers representing the required technical expertise to resolve rare disputes. * A **Triager** is a subset of contributors who have been given triage access to the repository. ## Logging Issues Log an issue for any question or problem you might have. When in doubt, log an issue, and any additional policies about what to include will be provided in the responses. The only exception is security disclosures which should be sent privately. Committers may direct you to another repository, ask for additional clarifications, and add appropriate metadata before the issue is addressed. Please be courteous and respectful. Every participant is expected to follow the project's Code of Conduct. ## Contributions Any change to resources in this repository must be through pull requests. This applies to all changes to documentation, code, binary files, etc. Even long term committers and TC members must use pull requests. No pull request can be merged without being reviewed. For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that contributors in other timezones have time to review. Consideration should also be given to weekends and other holiday periods to ensure active committers all have reasonable time to become involved in the discussion and review process if they wish. The default for each contribution is that it is accepted once no committer has an objection. During a review, committers may also request that a specific contributor who is most versed in a particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off" process for contributions to land. Once all issues brought by committers are addressed it can be landed by any committer. In the case of an objection being raised in a pull request by another committer, all involved committers should seek to arrive at a consensus by way of addressing concerns being expressed by discussion, compromise on the proposed change, or withdrawal of the proposed change. If a contribution is controversial and committers cannot agree about how to get it to land or if it should land then it should be escalated to the TC. TC members should regularly discuss pending contributions in order to find a resolution. It is expected that only a small minority of issues be brought to the TC for resolution and that discussion and compromise among committers be the default resolution mechanism. ## Becoming a Triager Anyone can become a triager! Read more about the process of being a triager in [the triage process document](Triager-Guide.md). [Open an issue in `expressjs/express` repo](https://github.com/expressjs/express/issues/new) to request the triage role. State that you have read and agree to the [Code of Conduct](Code-Of-Conduct.md) and details of the role. Here is an example issue content you can copy and paste: ``` Title: Request triager role for I have read and understood the project's Code of Conduct. I also have read and understood the process and best practices around Express triaging. I request for a triager role for the following GitHub organizations: jshttp pillarjs express ``` Once you have opened your issue, a member of the TC will add you to the `triage` team in the organizations requested. They will then close the issue. Happy triaging! ## Becoming a Committer All contributors who land a non-trivial contribution should be on-boarded in a timely manner, and added as a committer, and be given write access to the repository. Committers are expected to follow this policy and continue to send pull requests, go through proper review, and have other committers merge their pull requests. ## TC Process The TC uses a "consensus seeking" process for issues that are escalated to the TC. The group tries to find a resolution that has no open objections among TC members. If a consensus cannot be reached that has no objections then a majority wins vote is called. It is also expected that the majority of decisions made by the TC are via a consensus seeking process and that voting is only used as a last-resort. Resolution may involve returning the issue to committers with suggestions on how to move forward towards a consensus. It is not expected that a meeting of the TC will resolve all issues on its agenda during that meeting and may prefer to continue the discussion happening among the committers. Members can be added to the TC at any time. Any committer can nominate another committer to the TC and the TC uses its standard consensus seeking process to evaluate whether or not to add this new member. Members who do not participate consistently at the level of a majority of the other members are expected to resign. express-4.17.3/History.md000066400000000000000000003305631420332637600153020ustar00rootroot000000000000004.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 =================== * deps: accepts@~1.2.10 - deps: mime-types@~2.1.2 * deps: qs@4.0.0 - Fix dropping parameters like `hasOwnProperty` - Fix various parsing edge cases * deps: type-is@~1.6.4 - deps: mime-types@~2.1.2 - perf: enable strict mode - perf: remove argument reassignment 4.13.0 / 2015-06-20 =================== * Add settings to debug output * Fix `res.format` error when only `default` provided * Fix issue where `next('route')` in `app.param` would incorrectly skip values * Fix hiding platform issues with `decodeURIComponent` - Only `URIError`s are a 400 * Fix using `*` before params in routes * Fix using capture groups before params in routes * Simplify `res.cookie` to call `res.append` * Use `array-flatten` module for flattening arrays * deps: accepts@~1.2.9 - deps: mime-types@~2.1.1 - perf: avoid argument reassignment & argument slice - perf: avoid negotiator recursive construction - perf: enable strict mode - perf: remove unnecessary bitwise operator * deps: cookie@0.1.3 - perf: deduce the scope of try-catch deopt - perf: remove argument reassignments * deps: escape-html@1.0.2 * deps: etag@~1.7.0 - Always include entity length in ETags for hash length extensions - Generate non-Stats ETags using MD5 only (no longer CRC32) - Improve stat performance by removing hashing - Improve support for JXcore - Remove base64 padding in ETags to shorten - Support "fake" stats objects in environments without fs - Use MD5 instead of MD4 in weak ETags over 1KB * deps: finalhandler@0.4.0 - Fix a false-positive when unpiping in Node.js 0.8 - Support `statusCode` property on `Error` objects - Use `unpipe` module for unpiping requests - deps: escape-html@1.0.2 - deps: on-finished@~2.3.0 - perf: enable strict mode - perf: remove argument reassignment * deps: fresh@0.3.0 - Add weak `ETag` matching support * deps: on-finished@~2.3.0 - Add defined behavior for HTTP `CONNECT` requests - Add defined behavior for HTTP `Upgrade` requests - deps: ee-first@1.1.1 * deps: path-to-regexp@0.1.6 * deps: send@0.13.0 - Allow Node.js HTTP server to set `Date` response header - Fix incorrectly removing `Content-Location` on 304 response - Improve the default redirect response headers - Send appropriate headers on default error response - Use `http-errors` for standard emitted errors - Use `statuses` instead of `http` module for status messages - deps: escape-html@1.0.2 - deps: etag@~1.7.0 - deps: fresh@0.3.0 - deps: on-finished@~2.3.0 - perf: enable strict mode - perf: remove unnecessary array allocations * deps: serve-static@~1.10.0 - Add `fallthrough` option - Fix reading options from options prototype - Improve the default redirect response headers - Malformed URLs now `next()` instead of 400 - deps: escape-html@1.0.2 - deps: send@0.13.0 - perf: enable strict mode - perf: remove argument reassignment * deps: type-is@~1.6.3 - deps: mime-types@~2.1.1 - perf: reduce try block size - perf: remove bitwise operations * perf: enable strict mode * perf: isolate `app.render` try block * perf: remove argument reassignments in application * perf: remove argument reassignments in request prototype * perf: remove argument reassignments in response prototype * perf: remove argument reassignments in routing * perf: remove argument reassignments in `View` * perf: skip attempting to decode zero length string * perf: use saved reference to `http.STATUS_CODES` 4.12.4 / 2015-05-17 =================== * deps: accepts@~1.2.7 - deps: mime-types@~2.0.11 - deps: negotiator@0.5.3 * deps: debug@~2.2.0 - deps: ms@0.7.1 * deps: depd@~1.0.1 * deps: etag@~1.6.0 - Improve support for JXcore - Support "fake" stats objects in environments without `fs` * deps: finalhandler@0.3.6 - deps: debug@~2.2.0 - deps: on-finished@~2.2.1 * deps: on-finished@~2.2.1 - Fix `isFinished(req)` when data buffered * deps: proxy-addr@~1.0.8 - deps: ipaddr.js@1.0.1 * deps: qs@2.4.2 - Fix allowing parameters like `constructor` * deps: send@0.12.3 - deps: debug@~2.2.0 - deps: depd@~1.0.1 - deps: etag@~1.6.0 - deps: ms@0.7.1 - deps: on-finished@~2.2.1 * deps: serve-static@~1.9.3 - deps: send@0.12.3 * deps: type-is@~1.6.2 - deps: mime-types@~2.0.11 4.12.3 / 2015-03-17 =================== * deps: accepts@~1.2.5 - deps: mime-types@~2.0.10 * deps: debug@~2.1.3 - Fix high intensity foreground color for bold - deps: ms@0.7.0 * deps: finalhandler@0.3.4 - deps: debug@~2.1.3 * deps: proxy-addr@~1.0.7 - deps: ipaddr.js@0.1.9 * deps: qs@2.4.1 - Fix error when parameter `hasOwnProperty` is present * deps: send@0.12.2 - Throw errors early for invalid `extensions` or `index` options - deps: debug@~2.1.3 * deps: serve-static@~1.9.2 - deps: send@0.12.2 * deps: type-is@~1.6.1 - deps: mime-types@~2.0.10 4.12.2 / 2015-03-02 =================== * Fix regression where `"Request aborted"` is logged using `res.sendFile` 4.12.1 / 2015-03-01 =================== * Fix constructing application with non-configurable prototype properties * Fix `ECONNRESET` errors from `res.sendFile` usage * Fix `req.host` when using "trust proxy" hops count * Fix `req.protocol`/`req.secure` when using "trust proxy" hops count * Fix wrong `code` on aborted connections from `res.sendFile` * deps: merge-descriptors@1.0.0 4.12.0 / 2015-02-23 =================== * Fix `"trust proxy"` setting to inherit when app is mounted * Generate `ETag`s for all request responses - No longer restricted to only responses for `GET` and `HEAD` requests * Use `content-type` to parse `Content-Type` headers * deps: accepts@~1.2.4 - Fix preference sorting to be stable for long acceptable lists - deps: mime-types@~2.0.9 - deps: negotiator@0.5.1 * deps: cookie-signature@1.0.6 * deps: send@0.12.1 - Always read the stat size from the file - Fix mutating passed-in `options` - deps: mime@1.3.4 * deps: serve-static@~1.9.1 - deps: send@0.12.1 * deps: type-is@~1.6.0 - fix argument reassignment - fix false-positives in `hasBody` `Transfer-Encoding` check - support wildcard for both type and subtype (`*/*`) - deps: mime-types@~2.0.9 4.11.2 / 2015-02-01 =================== * Fix `res.redirect` double-calling `res.end` for `HEAD` requests * deps: accepts@~1.2.3 - deps: mime-types@~2.0.8 * deps: proxy-addr@~1.0.6 - deps: ipaddr.js@0.1.8 * deps: type-is@~1.5.6 - deps: mime-types@~2.0.8 4.11.1 / 2015-01-20 =================== * deps: send@0.11.1 - Fix root path disclosure * deps: serve-static@~1.8.1 - Fix redirect loop in Node.js 0.11.14 - Fix root path disclosure - deps: send@0.11.1 4.11.0 / 2015-01-13 =================== * Add `res.append(field, val)` to append headers * Deprecate leading `:` in `name` for `app.param(name, fn)` * Deprecate `req.param()` -- use `req.params`, `req.body`, or `req.query` instead * Deprecate `app.param(fn)` * Fix `OPTIONS` responses to include the `HEAD` method properly * Fix `res.sendFile` not always detecting aborted connection * Match routes iteratively to prevent stack overflows * deps: accepts@~1.2.2 - deps: mime-types@~2.0.7 - deps: negotiator@0.5.0 * deps: send@0.11.0 - deps: debug@~2.1.1 - deps: etag@~1.5.1 - deps: ms@0.7.0 - deps: on-finished@~2.2.0 * deps: serve-static@~1.8.0 - deps: send@0.11.0 4.10.8 / 2015-01-13 =================== * Fix crash from error within `OPTIONS` response handler * deps: proxy-addr@~1.0.5 - deps: ipaddr.js@0.1.6 4.10.7 / 2015-01-04 =================== * Fix `Allow` header for `OPTIONS` to not contain duplicate methods * Fix incorrect "Request aborted" for `res.sendFile` when `HEAD` or 304 * deps: debug@~2.1.1 * deps: finalhandler@0.3.3 - deps: debug@~2.1.1 - deps: on-finished@~2.2.0 * deps: methods@~1.1.1 * deps: on-finished@~2.2.0 * deps: serve-static@~1.7.2 - Fix potential open redirect when mounted at root * deps: type-is@~1.5.5 - deps: mime-types@~2.0.7 4.10.6 / 2014-12-12 =================== * Fix exception in `req.fresh`/`req.stale` without response headers 4.10.5 / 2014-12-10 =================== * Fix `res.send` double-calling `res.end` for `HEAD` requests * deps: accepts@~1.1.4 - deps: mime-types@~2.0.4 * deps: type-is@~1.5.4 - deps: mime-types@~2.0.4 4.10.4 / 2014-11-24 =================== * Fix `res.sendfile` logging standard write errors 4.10.3 / 2014-11-23 =================== * Fix `res.sendFile` logging standard write errors * deps: etag@~1.5.1 * deps: proxy-addr@~1.0.4 - deps: ipaddr.js@0.1.5 * deps: qs@2.3.3 - Fix `arrayLimit` behavior 4.10.2 / 2014-11-09 =================== * Correctly invoke async router callback asynchronously * deps: accepts@~1.1.3 - deps: mime-types@~2.0.3 * deps: type-is@~1.5.3 - deps: mime-types@~2.0.3 4.10.1 / 2014-10-28 =================== * Fix handling of URLs containing `://` in the path * deps: qs@2.3.2 - Fix parsing of mixed objects and values 4.10.0 / 2014-10-23 =================== * Add support for `app.set('views', array)` - Views are looked up in sequence in array of directories * Fix `res.send(status)` to mention `res.sendStatus(status)` * Fix handling of invalid empty URLs * Use `content-disposition` module for `res.attachment`/`res.download` - Sends standards-compliant `Content-Disposition` header - Full Unicode support * Use `path.resolve` in view lookup * deps: debug@~2.1.0 - Implement `DEBUG_FD` env variable support * deps: depd@~1.0.0 * deps: etag@~1.5.0 - Improve string performance - Slightly improve speed for weak ETags over 1KB * deps: finalhandler@0.3.2 - Terminate in progress response only on error - Use `on-finished` to determine request status - deps: debug@~2.1.0 - deps: on-finished@~2.1.1 * deps: on-finished@~2.1.1 - Fix handling of pipelined requests * deps: qs@2.3.0 - Fix parsing of mixed implicit and explicit arrays * deps: send@0.10.1 - deps: debug@~2.1.0 - deps: depd@~1.0.0 - deps: etag@~1.5.0 - deps: on-finished@~2.1.1 * deps: serve-static@~1.7.1 - deps: send@0.10.1 4.9.8 / 2014-10-17 ================== * Fix `res.redirect` body when redirect status specified * deps: accepts@~1.1.2 - Fix error when media type has invalid parameter - deps: negotiator@0.4.9 4.9.7 / 2014-10-10 ================== * Fix using same param name in array of paths 4.9.6 / 2014-10-08 ================== * deps: accepts@~1.1.1 - deps: mime-types@~2.0.2 - deps: negotiator@0.4.8 * deps: serve-static@~1.6.4 - Fix redirect loop when index file serving disabled * deps: type-is@~1.5.2 - deps: mime-types@~2.0.2 4.9.5 / 2014-09-24 ================== * deps: etag@~1.4.0 * deps: proxy-addr@~1.0.3 - Use `forwarded` npm module * deps: send@0.9.3 - deps: etag@~1.4.0 * deps: serve-static@~1.6.3 - deps: send@0.9.3 4.9.4 / 2014-09-19 ================== * deps: qs@2.2.4 - Fix issue with object keys starting with numbers truncated 4.9.3 / 2014-09-18 ================== * deps: proxy-addr@~1.0.2 - Fix a global leak when multiple subnets are trusted - deps: ipaddr.js@0.1.3 4.9.2 / 2014-09-17 ================== * Fix regression for empty string `path` in `app.use` * Fix `router.use` to accept array of middleware without path * Improve error message for bad `app.use` arguments 4.9.1 / 2014-09-16 ================== * Fix `app.use` to accept array of middleware without path * deps: depd@0.4.5 * deps: etag@~1.3.1 * deps: send@0.9.2 - deps: depd@0.4.5 - deps: etag@~1.3.1 - deps: range-parser@~1.0.2 * deps: serve-static@~1.6.2 - deps: send@0.9.2 4.9.0 / 2014-09-08 ================== * Add `res.sendStatus` * Invoke callback for sendfile when client aborts - Applies to `res.sendFile`, `res.sendfile`, and `res.download` - `err` will be populated with request aborted error * Support IP address host in `req.subdomains` * Use `etag` to generate `ETag` headers * deps: accepts@~1.1.0 - update `mime-types` * deps: cookie-signature@1.0.5 * deps: debug@~2.0.0 * deps: finalhandler@0.2.0 - Set `X-Content-Type-Options: nosniff` header - deps: debug@~2.0.0 * deps: fresh@0.2.4 * deps: media-typer@0.3.0 - Throw error when parameter format invalid on parse * deps: qs@2.2.3 - Fix issue where first empty value in array is discarded * deps: range-parser@~1.0.2 * deps: send@0.9.1 - Add `lastModified` option - Use `etag` to generate `ETag` header - deps: debug@~2.0.0 - deps: fresh@0.2.4 * deps: serve-static@~1.6.1 - Add `lastModified` option - deps: send@0.9.1 * deps: type-is@~1.5.1 - fix `hasbody` to be true for `content-length: 0` - deps: media-typer@0.3.0 - deps: mime-types@~2.0.1 * deps: vary@~1.0.0 - Accept valid `Vary` header string as `field` 4.8.8 / 2014-09-04 ================== * deps: send@0.8.5 - Fix a path traversal issue when using `root` - Fix malicious path detection for empty string path * deps: serve-static@~1.5.4 - deps: send@0.8.5 4.8.7 / 2014-08-29 ================== * deps: qs@2.2.2 - Remove unnecessary cloning 4.8.6 / 2014-08-27 ================== * deps: qs@2.2.0 - Array parsing fix - Performance improvements 4.8.5 / 2014-08-18 ================== * deps: send@0.8.3 - deps: destroy@1.0.3 - deps: on-finished@2.1.0 * deps: serve-static@~1.5.3 - deps: send@0.8.3 4.8.4 / 2014-08-14 ================== * deps: qs@1.2.2 * deps: send@0.8.2 - Work around `fd` leak in Node.js 0.10 for `fs.ReadStream` * deps: serve-static@~1.5.2 - deps: send@0.8.2 4.8.3 / 2014-08-10 ================== * deps: parseurl@~1.3.0 * deps: qs@1.2.1 * deps: serve-static@~1.5.1 - Fix parsing of weird `req.originalUrl` values - deps: parseurl@~1.3.0 - deps: utils-merge@1.0.0 4.8.2 / 2014-08-07 ================== * deps: qs@1.2.0 - Fix parsing array of objects 4.8.1 / 2014-08-06 ================== * fix incorrect deprecation warnings on `res.download` * deps: qs@1.1.0 - Accept urlencoded square brackets - Accept empty values in implicit array notation 4.8.0 / 2014-08-05 ================== * add `res.sendFile` - accepts a file system path instead of a URL - requires an absolute path or `root` option specified * deprecate `res.sendfile` -- use `res.sendFile` instead * support mounted app as any argument to `app.use()` * deps: qs@1.0.2 - Complete rewrite - Limits array length to 20 - Limits object depth to 5 - Limits parameters to 1,000 * deps: send@0.8.1 - Add `extensions` option * deps: serve-static@~1.5.0 - Add `extensions` option - deps: send@0.8.1 4.7.4 / 2014-08-04 ================== * fix `res.sendfile` regression for serving directory index files * deps: send@0.7.4 - Fix incorrect 403 on Windows and Node.js 0.11 - Fix serving index files without root dir * deps: serve-static@~1.4.4 - deps: send@0.7.4 4.7.3 / 2014-08-04 ================== * deps: send@0.7.3 - Fix incorrect 403 on Windows and Node.js 0.11 * deps: serve-static@~1.4.3 - Fix incorrect 403 on Windows and Node.js 0.11 - deps: send@0.7.3 4.7.2 / 2014-07-27 ================== * deps: depd@0.4.4 - Work-around v8 generating empty stack traces * deps: send@0.7.2 - deps: depd@0.4.4 * deps: serve-static@~1.4.2 4.7.1 / 2014-07-26 ================== * deps: depd@0.4.3 - Fix exception when global `Error.stackTraceLimit` is too low * deps: send@0.7.1 - deps: depd@0.4.3 * deps: serve-static@~1.4.1 4.7.0 / 2014-07-25 ================== * fix `req.protocol` for proxy-direct connections * configurable query parser with `app.set('query parser', parser)` - `app.set('query parser', 'extended')` parse with "qs" module - `app.set('query parser', 'simple')` parse with "querystring" core module - `app.set('query parser', false)` disable query string parsing - `app.set('query parser', true)` enable simple parsing * deprecate `res.json(status, obj)` -- use `res.status(status).json(obj)` instead * deprecate `res.jsonp(status, obj)` -- use `res.status(status).jsonp(obj)` instead * deprecate `res.send(status, body)` -- use `res.status(status).send(body)` instead * deps: debug@1.0.4 * deps: depd@0.4.2 - Add `TRACE_DEPRECATION` environment variable - Remove non-standard grey color from color output - Support `--no-deprecation` argument - Support `--trace-deprecation` argument * deps: finalhandler@0.1.0 - Respond after request fully read - deps: debug@1.0.4 * deps: parseurl@~1.2.0 - Cache URLs based on original value - Remove no-longer-needed URL mis-parse work-around - Simplify the "fast-path" `RegExp` * deps: send@0.7.0 - Add `dotfiles` option - Cap `maxAge` value to 1 year - deps: debug@1.0.4 - deps: depd@0.4.2 * deps: serve-static@~1.4.0 - deps: parseurl@~1.2.0 - deps: send@0.7.0 * perf: prevent multiple `Buffer` creation in `res.send` 4.6.1 / 2014-07-12 ================== * fix `subapp.mountpath` regression for `app.use(subapp)` 4.6.0 / 2014-07-11 ================== * accept multiple callbacks to `app.use()` * add explicit "Rosetta Flash JSONP abuse" protection - previous versions are not vulnerable; this is just explicit protection * catch errors in multiple `req.param(name, fn)` handlers * deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead * fix `res.send(status, num)` to send `num` as json (not error) * remove unnecessary escaping when `res.jsonp` returns JSON response * support non-string `path` in `app.use(path, fn)` - supports array of paths - supports `RegExp` * router: fix optimization on router exit * router: refactor location of `try` blocks * router: speed up standard `app.use(fn)` * deps: debug@1.0.3 - Add support for multiple wildcards in namespaces * deps: finalhandler@0.0.3 - deps: debug@1.0.3 * deps: methods@1.1.0 - add `CONNECT` * deps: parseurl@~1.1.3 - faster parsing of href-only URLs * deps: path-to-regexp@0.1.3 * deps: send@0.6.0 - deps: debug@1.0.3 * deps: serve-static@~1.3.2 - deps: parseurl@~1.1.3 - deps: send@0.6.0 * perf: fix arguments reassign deopt in some `res` methods 4.5.1 / 2014-07-06 ================== * fix routing regression when altering `req.method` 4.5.0 / 2014-07-04 ================== * add deprecation message to non-plural `req.accepts*` * add deprecation message to `res.send(body, status)` * add deprecation message to `res.vary()` * add `headers` option to `res.sendfile` - use to set headers on successful file transfer * add `mergeParams` option to `Router` - merges `req.params` from parent routes * add `req.hostname` -- correct name for what `req.host` returns * deprecate things with `depd` module * deprecate `req.host` -- use `req.hostname` instead * fix behavior when handling request without routes * fix handling when `route.all` is only route * invoke `router.param()` only when route matches * restore `req.params` after invoking router * use `finalhandler` for final response handling * use `media-typer` to alter content-type charset * deps: accepts@~1.0.7 * deps: send@0.5.0 - Accept string for `maxage` (converted by `ms`) - Include link in default redirect response * deps: serve-static@~1.3.0 - Accept string for `maxAge` (converted by `ms`) - Add `setHeaders` option - Include HTML link in redirect response - deps: send@0.5.0 * deps: type-is@~1.3.2 4.4.5 / 2014-06-26 ================== * deps: cookie-signature@1.0.4 - fix for timing attacks 4.4.4 / 2014-06-20 ================== * fix `res.attachment` Unicode filenames in Safari * fix "trim prefix" debug message in `express:router` * deps: accepts@~1.0.5 * deps: buffer-crc32@0.2.3 4.4.3 / 2014-06-11 ================== * fix persistence of modified `req.params[name]` from `app.param()` * deps: accepts@1.0.3 - deps: negotiator@0.4.6 * deps: debug@1.0.2 * deps: send@0.4.3 - 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 uncatchable error on file open race condition - deps: send@0.4.3 4.4.2 / 2014-06-09 ================== * fix catching errors from top-level handlers * use `vary` module for `res.vary` * deps: debug@1.0.1 * deps: proxy-addr@1.0.1 * deps: send@0.4.2 - fix "event emitter leak" warnings - deps: debug@1.0.1 - deps: finished@1.2.1 * deps: serve-static@1.2.2 - fix "event emitter leak" warnings - deps: send@0.4.2 * deps: type-is@1.2.1 4.4.1 / 2014-06-02 ================== * deps: methods@1.0.1 * deps: send@0.4.1 - Send `max-age` in `Cache-Control` in correct format * deps: serve-static@1.2.1 - use `escape-html` for escaping - deps: send@0.4.1 4.4.0 / 2014-05-30 ================== * custom etag control with `app.set('etag', val)` - `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation - `app.set('etag', 'weak')` weak tag - `app.set('etag', 'strong')` strong etag - `app.set('etag', false)` turn off - `app.set('etag', true)` standard etag * mark `res.send` ETag as weak and reduce collisions * update accepts to 1.0.2 - Fix interpretation when header not in request * update send to 0.4.0 - Calculate ETag with md5 for reduced collisions - Ignore stream errors after request ends - deps: debug@0.8.1 * update serve-static to 1.2.0 - Calculate ETag with md5 for reduced collisions - Ignore stream errors after request ends - deps: send@0.4.0 4.3.2 / 2014-05-28 ================== * fix handling of errors from `router.param()` callbacks 4.3.1 / 2014-05-23 ================== * revert "fix behavior of multiple `app.VERB` for the same path" - this caused a regression in the order of route execution 4.3.0 / 2014-05-21 ================== * add `req.baseUrl` to access the path stripped from `req.url` in routes * fix behavior of multiple `app.VERB` for the same path * fix issue routing requests among sub routers * invoke `router.param()` only when necessary instead of every match * proper proxy trust with `app.set('trust proxy', trust)` - `app.set('trust proxy', 1)` trust first hop - `app.set('trust proxy', 'loopback')` trust loopback addresses - `app.set('trust proxy', '10.0.0.1')` trust single IP - `app.set('trust proxy', '10.0.0.1/16')` trust subnet - `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list - `app.set('trust proxy', false)` turn off - `app.set('trust proxy', true)` trust everything * set proper `charset` in `Content-Type` for `res.send` * update type-is to 1.2.0 - support suffix matching 4.2.0 / 2014-05-11 ================== * deprecate `app.del()` -- use `app.delete()` instead * deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead - the edge-case `res.json(status, num)` requires `res.status(status).json(num)` * deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead - the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)` * fix `req.next` when inside router instance * include `ETag` header in `HEAD` requests * keep previous `Content-Type` for `res.jsonp` * support PURGE method - add `app.purge` - add `router.purge` - include PURGE in `app.all` * update debug to 0.8.0 - add `enable()` method - change from stderr to stdout * update methods to 1.0.0 - add PURGE 4.1.2 / 2014-05-08 ================== * fix `req.host` for IPv6 literals * fix `res.jsonp` error if callback param is object 4.1.1 / 2014-04-27 ================== * fix package.json to reflect supported node version 4.1.0 / 2014-04-24 ================== * pass options from `res.sendfile` to `send` * preserve casing of headers in `res.header` and `res.set` * support unicode file names in `res.attachment` and `res.download` * update accepts to 1.0.1 - deps: negotiator@0.4.0 * update cookie to 0.1.2 - Fix for maxAge == 0 - made compat with expires field * update send to 0.3.0 - Accept API options in options object - Coerce option types - Control whether to generate etags - Default directory access to 403 when index disabled - Fix sending files with dots without root set - Include file path in etag - Make "Can't set headers after they are sent." catchable - Send full entity-body for multi range requests - Set etags to "weak" - Support "If-Range" header - Support multiple index paths - deps: mime@1.2.11 * update serve-static to 1.1.0 - Accept options directly to `send` module - Resolve relative paths at middleware setup - Use parseurl to parse the URL from request - deps: send@0.3.0 * update type-is to 1.1.0 - add non-array values support - add `multipart` as a shorthand 4.0.0 / 2014-04-09 ================== * remove: - node 0.8 support - connect and connect's patches except for charset handling - express(1) - moved to [express-generator](https://github.com/expressjs/generator) - `express.createServer()` - it has been deprecated for a long time. Use `express()` - `app.configure` - use logic in your own app code - `app.router` - is removed - `req.auth` - use `basic-auth` instead - `req.accepted*` - use `req.accepts*()` instead - `res.location` - relative URL resolution is removed - `res.charset` - include the charset in the content type when using `res.set()` - all bundled middleware except `static` * change: - `app.route` -> `app.mountpath` when mounting an express app in another express app - `json spaces` no longer enabled by default in development - `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings` - `req.params` is now an object instead of an array - `res.locals` is no longer a function. It is a plain js object. Treat it as such. - `res.headerSent` -> `res.headersSent` to match node.js ServerResponse object * refactor: - `req.accepts*` with [accepts](https://github.com/expressjs/accepts) - `req.is` with [type-is](https://github.com/expressjs/type-is) - [path-to-regexp](https://github.com/component/path-to-regexp) * add: - `app.router()` - returns the app Router instance - `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 =================== * deps: basic-auth@~1.0.3 * deps: connect@2.30.1 - deps: body-parser@~1.13.2 - deps: compression@~1.5.1 - deps: errorhandler@~1.4.1 - deps: morgan@~1.6.1 - deps: pause@0.1.0 - deps: qs@4.0.0 - deps: serve-index@~1.7.1 - deps: type-is@~1.6.4 3.21.0 / 2015-06-18 =================== * deps: basic-auth@1.0.2 - perf: enable strict mode - perf: hoist regular expression - perf: parse with regular expressions - perf: remove argument reassignment * deps: connect@2.30.0 - deps: body-parser@~1.13.1 - deps: bytes@2.1.0 - deps: compression@~1.5.0 - deps: cookie@0.1.3 - deps: cookie-parser@~1.3.5 - deps: csurf@~1.8.3 - deps: errorhandler@~1.4.0 - deps: express-session@~1.11.3 - deps: finalhandler@0.4.0 - deps: fresh@0.3.0 - deps: morgan@~1.6.0 - deps: serve-favicon@~2.3.0 - deps: serve-index@~1.7.0 - deps: serve-static@~1.10.0 - deps: type-is@~1.6.3 * deps: cookie@0.1.3 - perf: deduce the scope of try-catch deopt - perf: remove argument reassignments * deps: escape-html@1.0.2 * deps: etag@~1.7.0 - Always include entity length in ETags for hash length extensions - Generate non-Stats ETags using MD5 only (no longer CRC32) - Improve stat performance by removing hashing - Improve support for JXcore - Remove base64 padding in ETags to shorten - Support "fake" stats objects in environments without fs - Use MD5 instead of MD4 in weak ETags over 1KB * deps: fresh@0.3.0 - Add weak `ETag` matching support * deps: mkdirp@0.5.1 - Work in global strict mode * deps: send@0.13.0 - Allow Node.js HTTP server to set `Date` response header - Fix incorrectly removing `Content-Location` on 304 response - Improve the default redirect response headers - Send appropriate headers on default error response - Use `http-errors` for standard emitted errors - Use `statuses` instead of `http` module for status messages - deps: escape-html@1.0.2 - deps: etag@~1.7.0 - deps: fresh@0.3.0 - deps: on-finished@~2.3.0 - perf: enable strict mode - perf: remove unnecessary array allocations 3.20.3 / 2015-05-17 =================== * deps: connect@2.29.2 - deps: body-parser@~1.12.4 - deps: compression@~1.4.4 - deps: connect-timeout@~1.6.2 - deps: debug@~2.2.0 - deps: depd@~1.0.1 - deps: errorhandler@~1.3.6 - deps: finalhandler@0.3.6 - deps: method-override@~2.3.3 - deps: morgan@~1.5.3 - deps: qs@2.4.2 - deps: response-time@~2.3.1 - deps: serve-favicon@~2.2.1 - deps: serve-index@~1.6.4 - deps: serve-static@~1.9.3 - deps: type-is@~1.6.2 * deps: debug@~2.2.0 - deps: ms@0.7.1 * deps: depd@~1.0.1 * deps: proxy-addr@~1.0.8 - deps: ipaddr.js@1.0.1 * deps: send@0.12.3 - deps: debug@~2.2.0 - deps: depd@~1.0.1 - deps: etag@~1.6.0 - deps: ms@0.7.1 - deps: on-finished@~2.2.1 3.20.2 / 2015-03-16 =================== * deps: connect@2.29.1 - deps: body-parser@~1.12.2 - deps: compression@~1.4.3 - deps: connect-timeout@~1.6.1 - deps: debug@~2.1.3 - deps: errorhandler@~1.3.5 - deps: express-session@~1.10.4 - deps: finalhandler@0.3.4 - deps: method-override@~2.3.2 - deps: morgan@~1.5.2 - deps: qs@2.4.1 - deps: serve-index@~1.6.3 - deps: serve-static@~1.9.2 - deps: type-is@~1.6.1 * deps: debug@~2.1.3 - Fix high intensity foreground color for bold - deps: ms@0.7.0 * deps: merge-descriptors@1.0.0 * deps: proxy-addr@~1.0.7 - deps: ipaddr.js@0.1.9 * deps: send@0.12.2 - Throw errors early for invalid `extensions` or `index` options - deps: debug@~2.1.3 3.20.1 / 2015-02-28 =================== * Fix `req.host` when using "trust proxy" hops count * Fix `req.protocol`/`req.secure` when using "trust proxy" hops count 3.20.0 / 2015-02-18 =================== * Fix `"trust proxy"` setting to inherit when app is mounted * Generate `ETag`s for all request responses - No longer restricted to only responses for `GET` and `HEAD` requests * Use `content-type` to parse `Content-Type` headers * deps: connect@2.29.0 - Use `content-type` to parse `Content-Type` headers - deps: body-parser@~1.12.0 - deps: compression@~1.4.1 - deps: connect-timeout@~1.6.0 - deps: cookie-parser@~1.3.4 - deps: cookie-signature@1.0.6 - deps: csurf@~1.7.0 - deps: errorhandler@~1.3.4 - deps: express-session@~1.10.3 - deps: http-errors@~1.3.1 - deps: response-time@~2.3.0 - deps: serve-index@~1.6.2 - deps: serve-static@~1.9.1 - deps: type-is@~1.6.0 * deps: cookie-signature@1.0.6 * deps: send@0.12.1 - Always read the stat size from the file - Fix mutating passed-in `options` - deps: mime@1.3.4 3.19.2 / 2015-02-01 =================== * deps: connect@2.28.3 - deps: compression@~1.3.1 - deps: csurf@~1.6.6 - deps: errorhandler@~1.3.3 - deps: express-session@~1.10.2 - deps: serve-index@~1.6.1 - deps: type-is@~1.5.6 * deps: proxy-addr@~1.0.6 - deps: ipaddr.js@0.1.8 3.19.1 / 2015-01-20 =================== * deps: connect@2.28.2 - deps: body-parser@~1.10.2 - deps: serve-static@~1.8.1 * deps: send@0.11.1 - Fix root path disclosure 3.19.0 / 2015-01-09 =================== * Fix `OPTIONS` responses to include the `HEAD` method property * Use `readline` for prompt in `express(1)` * deps: commander@2.6.0 * deps: connect@2.28.1 - deps: body-parser@~1.10.1 - deps: compression@~1.3.0 - deps: connect-timeout@~1.5.0 - deps: csurf@~1.6.4 - deps: debug@~2.1.1 - deps: errorhandler@~1.3.2 - deps: express-session@~1.10.1 - deps: finalhandler@0.3.3 - deps: method-override@~2.3.1 - deps: morgan@~1.5.1 - deps: serve-favicon@~2.2.0 - deps: serve-index@~1.6.0 - deps: serve-static@~1.8.0 - deps: type-is@~1.5.5 * deps: debug@~2.1.1 * deps: methods@~1.1.1 * deps: proxy-addr@~1.0.5 - deps: ipaddr.js@0.1.6 * deps: send@0.11.0 - deps: debug@~2.1.1 - deps: etag@~1.5.1 - deps: ms@0.7.0 - deps: on-finished@~2.2.0 3.18.6 / 2014-12-12 =================== * Fix exception in `req.fresh`/`req.stale` without response headers 3.18.5 / 2014-12-11 =================== * deps: connect@2.27.6 - deps: compression@~1.2.2 - deps: express-session@~1.9.3 - deps: http-errors@~1.2.8 - deps: serve-index@~1.5.3 - deps: type-is@~1.5.4 3.18.4 / 2014-11-23 =================== * deps: connect@2.27.4 - deps: body-parser@~1.9.3 - deps: compression@~1.2.1 - deps: errorhandler@~1.2.3 - deps: express-session@~1.9.2 - deps: qs@2.3.3 - deps: serve-favicon@~2.1.7 - deps: serve-static@~1.5.1 - deps: type-is@~1.5.3 * deps: etag@~1.5.1 * deps: proxy-addr@~1.0.4 - deps: ipaddr.js@0.1.5 3.18.3 / 2014-11-09 =================== * deps: connect@2.27.3 - Correctly invoke async callback asynchronously - deps: csurf@~1.6.3 3.18.2 / 2014-10-28 =================== * deps: connect@2.27.2 - Fix handling of URLs containing `://` in the path - deps: body-parser@~1.9.2 - deps: qs@2.3.2 3.18.1 / 2014-10-22 =================== * Fix internal `utils.merge` deprecation warnings * deps: connect@2.27.1 - deps: body-parser@~1.9.1 - deps: express-session@~1.9.1 - deps: finalhandler@0.3.2 - deps: morgan@~1.4.1 - deps: qs@2.3.0 - deps: serve-static@~1.7.1 * deps: send@0.10.1 - deps: on-finished@~2.1.1 3.18.0 / 2014-10-17 =================== * Use `content-disposition` module for `res.attachment`/`res.download` - Sends standards-compliant `Content-Disposition` header - Full Unicode support * Use `etag` module to generate `ETag` headers * deps: connect@2.27.0 - Use `http-errors` module for creating errors - Use `utils-merge` module for merging objects - deps: body-parser@~1.9.0 - deps: compression@~1.2.0 - deps: connect-timeout@~1.4.0 - deps: debug@~2.1.0 - deps: depd@~1.0.0 - deps: express-session@~1.9.0 - deps: finalhandler@0.3.1 - deps: method-override@~2.3.0 - deps: morgan@~1.4.0 - deps: response-time@~2.2.0 - deps: serve-favicon@~2.1.6 - deps: serve-index@~1.5.0 - deps: serve-static@~1.7.0 * deps: debug@~2.1.0 - Implement `DEBUG_FD` env variable support * deps: depd@~1.0.0 * deps: send@0.10.0 - deps: debug@~2.1.0 - deps: depd@~1.0.0 - deps: etag@~1.5.0 3.17.8 / 2014-10-15 =================== * deps: connect@2.26.6 - deps: compression@~1.1.2 - deps: csurf@~1.6.2 - deps: errorhandler@~1.2.2 3.17.7 / 2014-10-08 =================== * deps: connect@2.26.5 - Fix accepting non-object arguments to `logger` - deps: serve-static@~1.6.4 3.17.6 / 2014-10-02 =================== * deps: connect@2.26.4 - deps: morgan@~1.3.2 - deps: type-is@~1.5.2 3.17.5 / 2014-09-24 =================== * deps: connect@2.26.3 - deps: body-parser@~1.8.4 - deps: serve-favicon@~2.1.5 - deps: serve-static@~1.6.3 * deps: proxy-addr@~1.0.3 - Use `forwarded` npm module * deps: send@0.9.3 - deps: etag@~1.4.0 3.17.4 / 2014-09-19 =================== * deps: connect@2.26.2 - deps: body-parser@~1.8.3 - deps: qs@2.2.4 3.17.3 / 2014-09-18 =================== * deps: proxy-addr@~1.0.2 - Fix a global leak when multiple subnets are trusted - deps: ipaddr.js@0.1.3 3.17.2 / 2014-09-15 =================== * Use `crc` instead of `buffer-crc32` for speed * deps: connect@2.26.1 - deps: body-parser@~1.8.2 - deps: depd@0.4.5 - deps: express-session@~1.8.2 - deps: morgan@~1.3.1 - deps: serve-favicon@~2.1.3 - deps: serve-static@~1.6.2 * deps: depd@0.4.5 * deps: send@0.9.2 - deps: depd@0.4.5 - deps: etag@~1.3.1 - deps: range-parser@~1.0.2 3.17.1 / 2014-09-08 =================== * Fix error in `req.subdomains` on empty host 3.17.0 / 2014-09-08 =================== * Support `X-Forwarded-Host` in `req.subdomains` * Support IP address host in `req.subdomains` * deps: connect@2.26.0 - deps: body-parser@~1.8.1 - deps: compression@~1.1.0 - deps: connect-timeout@~1.3.0 - deps: cookie-parser@~1.3.3 - deps: cookie-signature@1.0.5 - deps: csurf@~1.6.1 - deps: debug@~2.0.0 - deps: errorhandler@~1.2.0 - deps: express-session@~1.8.1 - deps: finalhandler@0.2.0 - deps: fresh@0.2.4 - deps: media-typer@0.3.0 - deps: method-override@~2.2.0 - deps: morgan@~1.3.0 - deps: qs@2.2.3 - deps: serve-favicon@~2.1.3 - deps: serve-index@~1.2.1 - deps: serve-static@~1.6.1 - deps: type-is@~1.5.1 - deps: vhost@~3.0.0 * deps: cookie-signature@1.0.5 * deps: debug@~2.0.0 * deps: fresh@0.2.4 * deps: media-typer@0.3.0 - Throw error when parameter format invalid on parse * deps: range-parser@~1.0.2 * deps: send@0.9.1 - Add `lastModified` option - Use `etag` to generate `ETag` header - deps: debug@~2.0.0 - deps: fresh@0.2.4 * deps: vary@~1.0.0 - Accept valid `Vary` header string as `field` 3.16.10 / 2014-09-04 ==================== * deps: connect@2.25.10 - deps: serve-static@~1.5.4 * deps: send@0.8.5 - Fix a path traversal issue when using `root` - Fix malicious path detection for empty string path 3.16.9 / 2014-08-29 =================== * deps: connect@2.25.9 - deps: body-parser@~1.6.7 - deps: qs@2.2.2 3.16.8 / 2014-08-27 =================== * deps: connect@2.25.8 - deps: body-parser@~1.6.6 - deps: csurf@~1.4.1 - deps: qs@2.2.0 3.16.7 / 2014-08-18 =================== * deps: connect@2.25.7 - deps: body-parser@~1.6.5 - deps: express-session@~1.7.6 - deps: morgan@~1.2.3 - deps: serve-static@~1.5.3 * deps: send@0.8.3 - deps: destroy@1.0.3 - deps: on-finished@2.1.0 3.16.6 / 2014-08-14 =================== * deps: connect@2.25.6 - deps: body-parser@~1.6.4 - deps: qs@1.2.2 - deps: serve-static@~1.5.2 * deps: send@0.8.2 - Work around `fd` leak in Node.js 0.10 for `fs.ReadStream` 3.16.5 / 2014-08-11 =================== * deps: connect@2.25.5 - Fix backwards compatibility in `logger` 3.16.4 / 2014-08-10 =================== * Fix original URL parsing in `res.location` * deps: connect@2.25.4 - Fix `query` middleware breaking with argument - deps: body-parser@~1.6.3 - deps: compression@~1.0.11 - deps: connect-timeout@~1.2.2 - deps: express-session@~1.7.5 - deps: method-override@~2.1.3 - deps: on-headers@~1.0.0 - deps: parseurl@~1.3.0 - deps: qs@1.2.1 - deps: response-time@~2.0.1 - deps: serve-index@~1.1.6 - deps: serve-static@~1.5.1 * deps: parseurl@~1.3.0 3.16.3 / 2014-08-07 =================== * deps: connect@2.25.3 - deps: multiparty@3.3.2 3.16.2 / 2014-08-07 =================== * deps: connect@2.25.2 - deps: body-parser@~1.6.2 - deps: qs@1.2.0 3.16.1 / 2014-08-06 =================== * deps: connect@2.25.1 - deps: body-parser@~1.6.1 - deps: qs@1.1.0 3.16.0 / 2014-08-05 =================== * deps: connect@2.25.0 - deps: body-parser@~1.6.0 - deps: compression@~1.0.10 - deps: csurf@~1.4.0 - deps: express-session@~1.7.4 - deps: qs@1.0.2 - deps: serve-static@~1.5.0 * deps: send@0.8.1 - Add `extensions` option 3.15.3 / 2014-08-04 =================== * fix `res.sendfile` regression for serving directory index files * deps: connect@2.24.3 - deps: serve-index@~1.1.5 - deps: serve-static@~1.4.4 * deps: send@0.7.4 - Fix incorrect 403 on Windows and Node.js 0.11 - Fix serving index files without root dir 3.15.2 / 2014-07-27 =================== * deps: connect@2.24.2 - deps: body-parser@~1.5.2 - deps: depd@0.4.4 - deps: express-session@~1.7.2 - deps: morgan@~1.2.2 - deps: serve-static@~1.4.2 * deps: depd@0.4.4 - Work-around v8 generating empty stack traces * deps: send@0.7.2 - deps: depd@0.4.4 3.15.1 / 2014-07-26 =================== * deps: connect@2.24.1 - deps: body-parser@~1.5.1 - deps: depd@0.4.3 - deps: express-session@~1.7.1 - deps: morgan@~1.2.1 - deps: serve-index@~1.1.4 - deps: serve-static@~1.4.1 * deps: depd@0.4.3 - Fix exception when global `Error.stackTraceLimit` is too low * deps: send@0.7.1 - deps: depd@0.4.3 3.15.0 / 2014-07-22 =================== * Fix `req.protocol` for proxy-direct connections * Pass options from `res.sendfile` to `send` * deps: connect@2.24.0 - deps: body-parser@~1.5.0 - deps: compression@~1.0.9 - deps: connect-timeout@~1.2.1 - deps: debug@1.0.4 - deps: depd@0.4.2 - deps: express-session@~1.7.0 - deps: finalhandler@0.1.0 - deps: method-override@~2.1.2 - deps: morgan@~1.2.0 - deps: multiparty@3.3.1 - deps: parseurl@~1.2.0 - deps: serve-static@~1.4.0 * deps: debug@1.0.4 * deps: depd@0.4.2 - Add `TRACE_DEPRECATION` environment variable - Remove non-standard grey color from color output - Support `--no-deprecation` argument - Support `--trace-deprecation` argument * deps: parseurl@~1.2.0 - Cache URLs based on original value - Remove no-longer-needed URL mis-parse work-around - Simplify the "fast-path" `RegExp` * deps: send@0.7.0 - Add `dotfiles` option - Cap `maxAge` value to 1 year - deps: debug@1.0.4 - deps: depd@0.4.2 3.14.0 / 2014-07-11 =================== * add explicit "Rosetta Flash JSONP abuse" protection - previous versions are not vulnerable; this is just explicit protection * deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead * fix `res.send(status, num)` to send `num` as json (not error) * remove unnecessary escaping when `res.jsonp` returns JSON response * deps: basic-auth@1.0.0 - support empty password - support empty username * deps: connect@2.23.0 - deps: debug@1.0.3 - deps: express-session@~1.6.4 - deps: method-override@~2.1.0 - deps: parseurl@~1.1.3 - deps: serve-static@~1.3.1 * deps: debug@1.0.3 - Add support for multiple wildcards in namespaces * deps: methods@1.1.0 - add `CONNECT` * deps: parseurl@~1.1.3 - faster parsing of href-only URLs 3.13.0 / 2014-07-03 =================== * add deprecation message to `app.configure` * add deprecation message to `req.auth` * use `basic-auth` to parse `Authorization` header * deps: connect@2.22.0 - deps: csurf@~1.3.0 - deps: express-session@~1.6.1 - deps: multiparty@3.3.0 - deps: serve-static@~1.3.0 * deps: send@0.5.0 - Accept string for `maxage` (converted by `ms`) - Include link in default redirect response 3.12.1 / 2014-06-26 =================== * deps: connect@2.21.1 - deps: cookie-parser@1.3.2 - deps: cookie-signature@1.0.4 - deps: express-session@~1.5.2 - deps: type-is@~1.3.2 * deps: cookie-signature@1.0.4 - fix for timing attacks 3.12.0 / 2014-06-21 =================== * use `media-typer` to alter content-type charset * 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 - deps: compression@~1.0.8 - deps: errorhandler@~1.1.1 - deps: express-session@~1.5.0 - deps: serve-index@~1.1.3 3.11.0 / 2014-06-19 =================== * deprecate things with `depd` module * deps: buffer-crc32@0.2.3 * deps: connect@2.20.2 - deprecate `verify` option to `json` -- use `body-parser` npm module instead - deprecate `verify` option to `urlencoded` -- use `body-parser` npm module instead - deprecate things with `depd` module - use `finalhandler` for final response handling - use `media-typer` to parse `content-type` for charset - deps: body-parser@1.4.3 - deps: connect-timeout@1.1.1 - deps: cookie-parser@1.3.1 - deps: csurf@1.2.2 - deps: errorhandler@1.1.0 - deps: express-session@1.4.0 - deps: multiparty@3.2.9 - deps: serve-index@1.1.2 - deps: type-is@1.3.1 - deps: vhost@2.0.0 3.10.5 / 2014-06-11 =================== * deps: connect@2.19.6 - deps: body-parser@1.3.1 - deps: compression@1.0.7 - deps: debug@1.0.2 - deps: serve-index@1.1.1 - deps: serve-static@1.2.3 * deps: debug@1.0.2 * deps: send@0.4.3 - 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 3.10.4 / 2014-06-09 =================== * deps: connect@2.19.5 - fix "event emitter leak" warnings - deps: csurf@1.2.1 - deps: debug@1.0.1 - deps: serve-static@1.2.2 - deps: type-is@1.2.1 * deps: debug@1.0.1 * deps: send@0.4.2 - fix "event emitter leak" warnings - deps: finished@1.2.1 - deps: debug@1.0.1 3.10.3 / 2014-06-05 =================== * use `vary` module for `res.vary` * deps: connect@2.19.4 - deps: errorhandler@1.0.2 - deps: method-override@2.0.2 - deps: serve-favicon@2.0.1 * deps: debug@1.0.0 3.10.2 / 2014-06-03 =================== * deps: connect@2.19.3 - deps: compression@1.0.6 3.10.1 / 2014-06-03 =================== * deps: connect@2.19.2 - deps: compression@1.0.4 * deps: proxy-addr@1.0.1 3.10.0 / 2014-06-02 =================== * deps: connect@2.19.1 - deprecate `methodOverride()` -- use `method-override` npm module instead - deps: body-parser@1.3.0 - deps: method-override@2.0.1 - deps: multiparty@3.2.8 - deps: response-time@2.0.0 - deps: serve-static@1.2.1 * deps: methods@1.0.1 * deps: send@0.4.1 - Send `max-age` in `Cache-Control` in correct format 3.9.0 / 2014-05-30 ================== * custom etag control with `app.set('etag', val)` - `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation - `app.set('etag', 'weak')` weak tag - `app.set('etag', 'strong')` strong etag - `app.set('etag', false)` turn off - `app.set('etag', true)` standard etag * Include ETag in HEAD requests * mark `res.send` ETag as weak and reduce collisions * update connect to 2.18.0 - deps: compression@1.0.3 - deps: serve-index@1.1.0 - deps: serve-static@1.2.0 * update send to 0.4.0 - Calculate ETag with md5 for reduced collisions - Ignore stream errors after request ends - deps: debug@0.8.1 3.8.1 / 2014-05-27 ================== * update connect to 2.17.3 - deps: body-parser@1.2.2 - deps: express-session@1.2.1 - deps: method-override@1.0.2 3.8.0 / 2014-05-21 ================== * keep previous `Content-Type` for `res.jsonp` * set proper `charset` in `Content-Type` for `res.send` * update connect to 2.17.1 - fix `res.charset` appending charset when `content-type` has one - deps: express-session@1.2.0 - deps: morgan@1.1.1 - deps: serve-index@1.0.3 3.7.0 / 2014-05-18 ================== * proper proxy trust with `app.set('trust proxy', trust)` - `app.set('trust proxy', 1)` trust first hop - `app.set('trust proxy', 'loopback')` trust loopback addresses - `app.set('trust proxy', '10.0.0.1')` trust single IP - `app.set('trust proxy', '10.0.0.1/16')` trust subnet - `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list - `app.set('trust proxy', false)` turn off - `app.set('trust proxy', true)` trust everything * update connect to 2.16.2 - deprecate `res.headerSent` -- use `res.headersSent` - deprecate `res.on("header")` -- use on-headers module instead - fix edge-case in `res.appendHeader` that would append in wrong order - json: use body-parser - urlencoded: use body-parser - dep: bytes@1.0.0 - dep: cookie-parser@1.1.0 - dep: csurf@1.2.0 - dep: express-session@1.1.0 - dep: method-override@1.0.1 3.6.0 / 2014-05-09 ================== * deprecate `app.del()` -- use `app.delete()` instead * deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead - the edge-case `res.json(status, num)` requires `res.status(status).json(num)` * deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead - the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)` * support PURGE method - add `app.purge` - add `router.purge` - include PURGE in `app.all` * update connect to 2.15.0 * Add `res.appendHeader` * Call error stack even when response has been sent * Patch `res.headerSent` to return Boolean * Patch `res.headersSent` for node.js 0.8 * Prevent default 404 handler after response sent * dep: compression@1.0.2 * dep: connect-timeout@1.1.0 * dep: debug@^0.8.0 * dep: errorhandler@1.0.1 * dep: express-session@1.0.4 * dep: morgan@1.0.1 * dep: serve-favicon@2.0.0 * dep: serve-index@1.0.2 * update debug to 0.8.0 * add `enable()` method * change from stderr to stdout * update methods to 1.0.0 - add PURGE * update mkdirp to 0.5.0 3.5.3 / 2014-05-08 ================== * fix `req.host` for IPv6 literals * fix `res.jsonp` error if callback param is object 3.5.2 / 2014-04-24 ================== * update connect to 2.14.5 * update cookie to 0.1.2 * update mkdirp to 0.4.0 * update send to 0.3.0 3.5.1 / 2014-03-25 ================== * pin less-middleware in generated app 3.5.0 / 2014-03-06 ================== * bump deps 3.4.8 / 2014-01-13 ================== * prevent incorrect automatic OPTIONS responses #1868 @dpatti * update binary and examples for jade 1.0 #1876 @yossi, #1877 @reqshark, #1892 @matheusazzi * throw 400 in case of malformed paths @rlidwka 3.4.7 / 2013-12-10 ================== * update connect 3.4.6 / 2013-12-01 ================== * update connect (raw-body) 3.4.5 / 2013-11-27 ================== * update connect * res.location: remove leading ./ #1802 @kapouer * res.redirect: fix `res.redirect('toString') #1829 @michaelficarra * res.send: always send ETag when content-length > 0 * router: add Router.all() method 3.4.4 / 2013-10-29 ================== * update connect * update supertest * update methods * express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04 3.4.3 / 2013-10-23 ================== * update connect 3.4.2 / 2013-10-18 ================== * update connect * downgrade commander 3.4.1 / 2013-10-15 ================== * update connect * update commander * jsonp: check if callback is a function * router: wrap encodeURIComponent in a try/catch #1735 (@lxe) * res.format: now includes charset @1747 (@sorribas) * res.links: allow multiple calls @1746 (@sorribas) 3.4.0 / 2013-09-07 ================== * add res.vary(). Closes #1682 * update connect 3.3.8 / 2013-09-02 ================== * update connect 3.3.7 / 2013-08-28 ================== * update connect 3.3.6 / 2013-08-27 ================== * Revert "remove charset from json responses. Closes #1631" (causes issues in some clients) * add: req.accepts take an argument list 3.3.4 / 2013-07-08 ================== * update send and connect 3.3.3 / 2013-07-04 ================== * update connect 3.3.2 / 2013-07-03 ================== * update connect * update send * remove .version export 3.3.1 / 2013-06-27 ================== * update connect 3.3.0 / 2013-06-26 ================== * update connect * add support for multiple X-Forwarded-Proto values. Closes #1646 * change: remove charset from json responses. Closes #1631 * change: return actual booleans from req.accept* functions * fix jsonp callback array throw 3.2.6 / 2013-06-02 ================== * update connect 3.2.5 / 2013-05-21 ================== * update connect * update node-cookie * add: throw a meaningful error when there is no default engine * change generation of ETags with res.send() to GET requests only. Closes #1619 3.2.4 / 2013-05-09 ================== * fix `req.subdomains` when no Host is present * fix `req.host` when no Host is present, return undefined 3.2.3 / 2013-05-07 ================== * update connect / qs 3.2.2 / 2013-05-03 ================== * update qs 3.2.1 / 2013-04-29 ================== * add app.VERB() paths array deprecation warning * update connect * update qs and remove all ~ semver crap * fix: accept number as value of Signed Cookie 3.2.0 / 2013-04-15 ================== * add "view" constructor setting to override view behaviour * add req.acceptsEncoding(name) * add req.acceptedEncodings * revert cookie signature change causing session race conditions * fix sorting of Accept values of the same quality 3.1.2 / 2013-04-12 ================== * add support for custom Accept parameters * update cookie-signature 3.1.1 / 2013-04-01 ================== * add X-Forwarded-Host support to `req.host` * fix relative redirects * update mkdirp * update buffer-crc32 * remove legacy app.configure() method from app template. 3.1.0 / 2013-01-25 ================== * add support for leading "." in "view engine" setting * add array support to `res.set()` * add node 0.8.x to travis.yml * add "subdomain offset" setting for tweaking `req.subdomains` * add `res.location(url)` implementing `res.redirect()`-like setting of Location * use app.get() for x-powered-by setting for inheritance * fix colons in passwords for `req.auth` 3.0.6 / 2013-01-04 ================== * add http verb methods to Router * update connect * fix mangling of the `res.cookie()` options object * fix jsonp whitespace escape. Closes #1132 3.0.5 / 2012-12-19 ================== * add throwing when a non-function is passed to a route * fix: explicitly remove Transfer-Encoding header from 204 and 304 responses * revert "add 'etag' option" 3.0.4 / 2012-12-05 ================== * add 'etag' option to disable `res.send()` Etags * add escaping of urls in text/plain in `res.redirect()` for old browsers interpreting as html * change crc32 module for a more liberal license * update connect 3.0.3 / 2012-11-13 ================== * update connect * update cookie module * fix cookie max-age 3.0.2 / 2012-11-08 ================== * add OPTIONS to cors example. Closes #1398 * fix route chaining regression. Closes #1397 3.0.1 / 2012-11-01 ================== * update connect 3.0.0 / 2012-10-23 ================== * add `make clean` * add "Basic" check to req.auth * add `req.auth` test coverage * add cb && cb(payload) to `res.jsonp()`. Closes #1374 * add backwards compat for `res.redirect()` status. Closes #1336 * add support for `res.json()` to retain previously defined Content-Types. Closes #1349 * update connect * change `res.redirect()` to utilize a pathname-relative Location again. Closes #1382 * remove non-primitive string support for `res.send()` * fix view-locals example. Closes #1370 * fix route-separation example 3.0.0rc5 / 2012-09-18 ================== * update connect * add redis search example * add static-files example * add "x-powered-by" setting (`app.disable('x-powered-by')`) * add "application/octet-stream" redirect Accept test case. Closes #1317 3.0.0rc4 / 2012-08-30 ================== * add `res.jsonp()`. Closes #1307 * add "verbose errors" option to error-pages example * add another route example to express(1) so people are not so confused * add redis online user activity tracking example * update connect dep * fix etag quoting. Closes #1310 * fix error-pages 404 status * fix jsonp callback char restrictions * remove old OPTIONS default response 3.0.0rc3 / 2012-08-13 ================== * update connect dep * fix signed cookies to work with `connect.cookieParser()` ("s:" prefix was missing) [tnydwrds] * fix `res.render()` clobbering of "locals" 3.0.0rc2 / 2012-08-03 ================== * add CORS example * update connect dep * deprecate `.createServer()` & remove old stale examples * fix: escape `res.redirect()` link * fix vhost example 3.0.0rc1 / 2012-07-24 ================== * add more examples to view-locals * add scheme-relative redirects (`res.redirect("//foo.com")`) support * update cookie dep * update connect dep * update send dep * fix `express(1)` -h flag, use -H for hogan. Closes #1245 * fix `res.sendfile()` socket error handling regression 3.0.0beta7 / 2012-07-16 ================== * update connect dep for `send()` root normalization regression 3.0.0beta6 / 2012-07-13 ================== * add `err.view` property for view errors. Closes #1226 * add "jsonp callback name" setting * add support for "/foo/:bar*" non-greedy matches * change `res.sendfile()` to use `send()` module * change `res.send` to use "response-send" module * remove `app.locals.use` and `res.locals.use`, use regular middleware 3.0.0beta5 / 2012-07-03 ================== * add "make check" support * add route-map example * add `res.json(obj, status)` support back for BC * add "methods" dep, remove internal methods module * update connect dep * update auth example to utilize cores pbkdf2 * updated tests to use "supertest" 3.0.0beta4 / 2012-06-25 ================== * Added `req.auth` * Added `req.range(size)` * Added `res.links(obj)` * Added `res.send(body, status)` support back for backwards compat * Added `.default()` support to `res.format()` * Added 2xx / 304 check to `req.fresh` * Revert "Added + support to the router" * Fixed `res.send()` freshness check, respect res.statusCode 3.0.0beta3 / 2012-06-15 ================== * Added hogan `--hjs` to express(1) [nullfirm] * Added another example to content-negotiation * Added `fresh` dep * Changed: `res.send()` always checks freshness * Fixed: expose connects mime module. Closes #1165 3.0.0beta2 / 2012-06-06 ================== * Added `+` support to the router * Added `req.host` * Changed `req.param()` to check route first * Update connect dep 3.0.0beta1 / 2012-06-01 ================== * Added `res.format()` callback to override default 406 behaviour * Fixed `res.redirect()` 406. Closes #1154 3.0.0alpha5 / 2012-05-30 ================== * Added `req.ip` * Added `{ signed: true }` option to `res.cookie()` * Removed `res.signedCookie()` * Changed: dont reverse `req.ips` * Fixed "trust proxy" setting check for `req.ips` 3.0.0alpha4 / 2012-05-09 ================== * Added: allow `[]` in jsonp callback. Closes #1128 * Added `PORT` env var support in generated template. Closes #1118 [benatkin] * Updated: connect 2.2.2 3.0.0alpha3 / 2012-05-04 ================== * Added public `app.routes`. Closes #887 * Added _view-locals_ example * Added _mvc_ example * Added `res.locals.use()`. Closes #1120 * Added conditional-GET support to `res.send()` * Added: coerce `res.set()` values to strings * Changed: moved `static()` in generated apps below router * Changed: `res.send()` only set ETag when not previously set * Changed connect 2.2.1 dep * Changed: `make test` now runs unit / acceptance tests * Fixed req/res proto inheritance 3.0.0alpha2 / 2012-04-26 ================== * Added `make benchmark` back * Added `res.send()` support for `String` objects * Added client-side data exposing example * Added `res.header()` and `req.header()` aliases for BC * Added `express.createServer()` for BC * Perf: memoize parsed urls * Perf: connect 2.2.0 dep * Changed: make `expressInit()` middleware self-aware * Fixed: use app.get() for all core settings * Fixed redis session example * Fixed session example. Closes #1105 * Fixed generated express dep. Closes #1078 3.0.0alpha1 / 2012-04-15 ================== * Added `app.locals.use(callback)` * Added `app.locals` object * Added `app.locals(obj)` * Added `res.locals` object * Added `res.locals(obj)` * Added `res.format()` for content-negotiation * Added `app.engine()` * Added `res.cookie()` JSON cookie support * Added "trust proxy" setting * Added `req.subdomains` * Added `req.protocol` * Added `req.secure` * Added `req.path` * Added `req.ips` * Added `req.fresh` * Added `req.stale` * Added comma-delimited / array support for `req.accepts()` * Added debug instrumentation * Added `res.set(obj)` * Added `res.set(field, value)` * Added `res.get(field)` * Added `app.get(setting)`. Closes #842 * Added `req.acceptsLanguage()` * Added `req.acceptsCharset()` * Added `req.accepted` * Added `req.acceptedLanguages` * Added `req.acceptedCharsets` * Added "json replacer" setting * Added "json spaces" setting * Added X-Forwarded-Proto support to `res.redirect()`. Closes #92 * Added `--less` support to express(1) * Added `express.response` prototype * Added `express.request` prototype * Added `express.application` prototype * Added `app.path()` * Added `app.render()` * Added `res.type()` to replace `res.contentType()` * Changed: `res.redirect()` to add relative support * Changed: enable "jsonp callback" by default * Changed: renamed "case sensitive routes" to "case sensitive routing" * Rewrite of all tests with mocha * Removed "root" setting * Removed `res.redirect('home')` support * Removed `req.notify()` * Removed `app.register()` * Removed `app.redirect()` * Removed `app.is()` * Removed `app.helpers()` * Removed `app.dynamicHelpers()` * Fixed `res.sendfile()` with non-GET. Closes #723 * Fixed express(1) public dir for windows. Closes #866 2.5.9/ 2012-04-02 ================== * Added support for PURGE request method [pbuyle] * Fixed `express(1)` generated app `app.address()` before `listening` [mmalecki] 2.5.8 / 2012-02-08 ================== * Update mkdirp dep. Closes #991 2.5.7 / 2012-02-06 ================== * Fixed `app.all` duplicate DELETE requests [mscdex] 2.5.6 / 2012-01-13 ================== * Updated hamljs dev dep. Closes #953 2.5.5 / 2012-01-08 ================== * Fixed: set `filename` on cached templates [matthewleon] 2.5.4 / 2012-01-02 ================== * Fixed `express(1)` eol on 0.4.x. Closes #947 2.5.3 / 2011-12-30 ================== * Fixed `req.is()` when a charset is present 2.5.2 / 2011-12-10 ================== * Fixed: express(1) LF -> CRLF for windows 2.5.1 / 2011-11-17 ================== * Changed: updated connect to 1.8.x * Removed sass.js support from express(1) 2.5.0 / 2011-10-24 ================== * Added ./routes dir for generated app by default * Added npm install reminder to express(1) app gen * Added 0.5.x support * Removed `make test-cov` since it wont work with node 0.5.x * Fixed express(1) public dir for windows. Closes #866 2.4.7 / 2011-10-05 ================== * Added mkdirp to express(1). Closes #795 * Added simple _json-config_ example * Added shorthand for the parsed request's pathname via `req.path` * Changed connect dep to 1.7.x to fix npm issue... * Fixed `res.redirect()` __HEAD__ support. [reported by xerox] * Fixed `req.flash()`, only escape args * Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie] 2.4.6 / 2011-08-22 ================== * Fixed multiple param callback regression. Closes #824 [reported by TroyGoode] 2.4.5 / 2011-08-19 ================== * Added support for routes to handle errors. Closes #809 * Added `app.routes.all()`. Closes #803 * Added "basepath" setting to work in conjunction with reverse proxies etc. * Refactored `Route` to use a single array of callbacks * Added support for multiple callbacks for `app.param()`. Closes #801 Closes #805 * Changed: removed .call(self) for route callbacks * Dependency: `qs >= 0.3.1` * Fixed `res.redirect()` on windows due to `join()` usage. Closes #808 2.4.4 / 2011-08-05 ================== * Fixed `res.header()` intention of a set, even when `undefined` * Fixed `*`, value no longer required * Fixed `res.send(204)` support. Closes #771 2.4.3 / 2011-07-14 ================== * Added docs for `status` option special-case. Closes #739 * Fixed `options.filename`, exposing the view path to template engines 2.4.2. / 2011-07-06 ================== * Revert "removed jsonp stripping" for XSS 2.4.1 / 2011-07-06 ================== * Added `res.json()` JSONP support. Closes #737 * Added _extending-templates_ example. Closes #730 * Added "strict routing" setting for trailing slashes * Added support for multiple envs in `app.configure()` calls. Closes #735 * Changed: `res.send()` using `res.json()` * Changed: when cookie `path === null` don't default it * Changed; default cookie path to "home" setting. Closes #731 * Removed _pids/logs_ creation from express(1) 2.4.0 / 2011-06-28 ================== * Added chainable `res.status(code)` * Added `res.json()`, an explicit version of `res.send(obj)` * Added simple web-service example 2.3.12 / 2011-06-22 ================== * \#express is now on freenode! come join! * Added `req.get(field, param)` * Added links to Japanese documentation, thanks @hideyukisaito! * Added; the `express(1)` generated app outputs the env * Added `content-negotiation` example * Dependency: connect >= 1.5.1 < 2.0.0 * Fixed view layout bug. Closes #720 * Fixed; ignore body on 304. Closes #701 2.3.11 / 2011-06-04 ================== * Added `npm test` * Removed generation of dummy test file from `express(1)` * Fixed; `express(1)` adds express as a dep * Fixed; prune on `prepublish` 2.3.10 / 2011-05-27 ================== * Added `req.route`, exposing the current route * Added _package.json_ generation support to `express(1)` * Fixed call to `app.param()` function for optional params. Closes #682 2.3.9 / 2011-05-25 ================== * Fixed bug-ish with `../' in `res.partial()` calls 2.3.8 / 2011-05-24 ================== * Fixed `app.options()` 2.3.7 / 2011-05-23 ================== * Added route `Collection`, ex: `app.get('/user/:id').remove();` * Added support for `app.param(fn)` to define param logic * Removed `app.param()` support for callback with return value * Removed module.parent check from express(1) generated app. Closes #670 * Refactored router. Closes #639 2.3.6 / 2011-05-20 ================== * Changed; using devDependencies instead of git submodules * Fixed redis session example * Fixed markdown example * Fixed view caching, should not be enabled in development 2.3.5 / 2011-05-20 ================== * Added export `.view` as alias for `.View` 2.3.4 / 2011-05-08 ================== * Added `./examples/say` * Fixed `res.sendfile()` bug preventing the transfer of files with spaces 2.3.3 / 2011-05-03 ================== * Added "case sensitive routes" option. * Changed; split methods supported per rfc [slaskis] * Fixed route-specific middleware when using the same callback function several times 2.3.2 / 2011-04-27 ================== * Fixed view hints 2.3.1 / 2011-04-26 ================== * Added `app.match()` as `app.match.all()` * Added `app.lookup()` as `app.lookup.all()` * Added `app.remove()` for `app.remove.all()` * Added `app.remove.VERB()` * Fixed template caching collision issue. Closes #644 * Moved router over from connect and started refactor 2.3.0 / 2011-04-25 ================== * Added options support to `res.clearCookie()` * Added `res.helpers()` as alias of `res.locals()` * Added; json defaults to UTF-8 with `res.send()`. Closes #632. [Daniel * Dependency `connect >= 1.4.0` * Changed; auto set Content-Type in res.attachement [Aaron Heckmann] * Renamed "cache views" to "view cache". Closes #628 * Fixed caching of views when using several apps. Closes #637 * Fixed gotcha invoking `app.param()` callbacks once per route middleware. Closes #638 * Fixed partial lookup precedence. Closes #631 Shaw] 2.2.2 / 2011-04-12 ================== * Added second callback support for `res.download()` connection errors * Fixed `filename` option passing to template engine 2.2.1 / 2011-04-04 ================== * Added `layout(path)` helper to change the layout within a view. Closes #610 * Fixed `partial()` collection object support. Previously only anything with `.length` would work. When `.length` is present one must still be aware of holes, however now `{ collection: {foo: 'bar'}}` is valid, exposes `keyInCollection` and `keysInCollection`. * Performance improved with better view caching * Removed `request` and `response` locals * Changed; errorHandler page title is now `Express` instead of `Connect` 2.2.0 / 2011-03-30 ================== * Added `app.lookup.VERB()`, ex `app.lookup.put('/user/:id')`. Closes #606 * Added `app.match.VERB()`, ex `app.match.put('/user/12')`. Closes #606 * Added `app.VERB(path)` as alias of `app.lookup.VERB()`. * Dependency `connect >= 1.2.0` 2.1.1 / 2011-03-29 ================== * Added; expose `err.view` object when failing to locate a view * Fixed `res.partial()` call `next(err)` when no callback is given [reported by aheckmann] * Fixed; `res.send(undefined)` responds with 204 [aheckmann] 2.1.0 / 2011-03-24 ================== * Added `/_?` partial lookup support. Closes #447 * Added `request`, `response`, and `app` local variables * Added `settings` local variable, containing the app's settings * Added `req.flash()` exception if `req.session` is not available * Added `res.send(bool)` support (json response) * Fixed stylus example for latest version * Fixed; wrap try/catch around `res.render()` 2.0.0 / 2011-03-17 ================== * Fixed up index view path alternative. * Changed; `res.locals()` without object returns the locals 2.0.0rc3 / 2011-03-17 ================== * Added `res.locals(obj)` to compliment `res.local(key, val)` * Added `res.partial()` callback support * Fixed recursive error reporting issue in `res.render()` 2.0.0rc2 / 2011-03-17 ================== * Changed; `partial()` "locals" are now optional * Fixed `SlowBuffer` support. Closes #584 [reported by tyrda01] * Fixed .filename view engine option [reported by drudge] * Fixed blog example * Fixed `{req,res}.app` reference when mounting [Ben Weaver] 2.0.0rc / 2011-03-14 ================== * Fixed; expose `HTTPSServer` constructor * Fixed express(1) default test charset. Closes #579 [reported by secoif] * Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP] 2.0.0beta3 / 2011-03-09 ================== * Added support for `res.contentType()` literal The original `res.contentType('.json')`, `res.contentType('application/json')`, and `res.contentType('json')` will work now. * Added `res.render()` status option support back * Added charset option for `res.render()` * Added `.charset` support (via connect 1.0.4) * Added view resolution hints when in development and a lookup fails * Added layout lookup support relative to the page view. For example while rendering `./views/user/index.jade` if you create `./views/user/layout.jade` it will be used in favour of the root layout. * Fixed `res.redirect()`. RFC states absolute url [reported by unlink] * Fixed; default `res.send()` string charset to utf8 * Removed `Partial` constructor (not currently used) 2.0.0beta2 / 2011-03-07 ================== * Added res.render() `.locals` support back to aid in migration process * Fixed flash example 2.0.0beta / 2011-03-03 ================== * Added HTTPS support * Added `res.cookie()` maxAge support * Added `req.header()` _Referrer_ / _Referer_ special-case, either works * Added mount support for `res.redirect()`, now respects the mount-point * Added `union()` util, taking place of `merge(clone())` combo * Added stylus support to express(1) generated app * Added secret to session middleware used in examples and generated app * Added `res.local(name, val)` for progressive view locals * Added default param support to `req.param(name, default)` * Added `app.disabled()` and `app.enabled()` * Added `app.register()` support for omitting leading ".", either works * Added `res.partial()`, using the same interface as `partial()` within a view. Closes #539 * Added `app.param()` to map route params to async/sync logic * Added; aliased `app.helpers()` as `app.locals()`. Closes #481 * Added extname with no leading "." support to `res.contentType()` * Added `cache views` setting, defaulting to enabled in "production" env * Added index file partial resolution, eg: partial('user') may try _views/user/index.jade_. * Added `req.accepts()` support for extensions * Changed; `res.download()` and `res.sendfile()` now utilize Connect's static file server `connect.static.send()`. * Changed; replaced `connect.utils.mime()` with npm _mime_ module * Changed; allow `req.query` to be pre-defined (via middleware or other parent * Changed view partial resolution, now relative to parent view * Changed view engine signature. no longer `engine.render(str, options, callback)`, now `engine.compile(str, options) -> Function`, the returned function accepts `fn(locals)`. * Fixed `req.param()` bug returning Array.prototype methods. Closes #552 * Fixed; using `Stream#pipe()` instead of `sys.pump()` in `res.sendfile()` * Fixed; using _qs_ module instead of _querystring_ * Fixed; strip unsafe chars from jsonp callbacks * Removed "stream threshold" setting 1.0.8 / 2011-03-01 ================== * Allow `req.query` to be pre-defined (via middleware or other parent app) * "connect": ">= 0.5.0 < 1.0.0". Closes #547 * Removed the long deprecated __EXPRESS_ENV__ support 1.0.7 / 2011-02-07 ================== * Fixed `render()` setting inheritance. Mounted apps would not inherit "view engine" 1.0.6 / 2011-02-07 ================== * Fixed `view engine` setting bug when period is in dirname 1.0.5 / 2011-02-05 ================== * Added secret to generated app `session()` call 1.0.4 / 2011-02-05 ================== * Added `qs` dependency to _package.json_ * Fixed namespaced `require()`s for latest connect support 1.0.3 / 2011-01-13 ================== * Remove unsafe characters from JSONP callback names [Ryan Grove] 1.0.2 / 2011-01-10 ================== * Removed nested require, using `connect.router` 1.0.1 / 2010-12-29 ================== * Fixed for middleware stacked via `createServer()` previously the `foo` middleware passed to `createServer(foo)` would not have access to Express methods such as `res.send()` or props like `req.query` etc. 1.0.0 / 2010-11-16 ================== * Added; deduce partial object names from the last segment. For example by default `partial('forum/post', postObject)` will give you the _post_ object, providing a meaningful default. * Added http status code string representation to `res.redirect()` body * Added; `res.redirect()` supporting _text/plain_ and _text/html_ via __Accept__. * Added `req.is()` to aid in content negotiation * Added partial local inheritance [suggested by masylum]. Closes #102 providing access to parent template locals. * Added _-s, --session[s]_ flag to express(1) to add session related middleware * Added _--template_ flag to express(1) to specify the template engine to use. * Added _--css_ flag to express(1) to specify the stylesheet engine to use (or just plain css by default). * Added `app.all()` support [thanks aheckmann] * Added partial direct object support. You may now `partial('user', user)` providing the "user" local, vs previously `partial('user', { object: user })`. * Added _route-separation_ example since many people question ways to do this with CommonJS modules. Also view the _blog_ example for an alternative. * Performance; caching view path derived partial object names * Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454 * Fixed jsonp support; _text/javascript_ as per mailinglist discussion 1.0.0rc4 / 2010-10-14 ================== * Added _NODE_ENV_ support, _EXPRESS_ENV_ is deprecated and will be removed in 1.0.0 * Added route-middleware support (very helpful, see the [docs](http://expressjs.com/guide.html#Route-Middleware)) * Added _jsonp callback_ setting to enable/disable jsonp autowrapping [Dav Glass] * Added callback query check on response.send to autowrap JSON objects for simple webservice implementations [Dav Glass] * Added `partial()` support for array-like collections. Closes #434 * Added support for swappable querystring parsers * Added session usage docs. Closes #443 * Added dynamic helper caching. Closes #439 [suggested by maritz] * Added authentication example * Added basic Range support to `res.sendfile()` (and `res.download()` etc) * Changed; `express(1)` generated app using 2 spaces instead of 4 * Default env to "development" again [aheckmann] * Removed _context_ option is no more, use "scope" * Fixed; exposing _./support_ libs to examples so they can run without installs * Fixed mvc example 1.0.0rc3 / 2010-09-20 ================== * Added confirmation for `express(1)` app generation. Closes #391 * Added extending of flash formatters via `app.flashFormatters` * Added flash formatter support. Closes #411 * Added streaming support to `res.sendfile()` using `sys.pump()` when >= "stream threshold" * Added _stream threshold_ setting for `res.sendfile()` * Added `res.send()` __HEAD__ support * Added `res.clearCookie()` * Added `res.cookie()` * Added `res.render()` headers option * Added `res.redirect()` response bodies * Added `res.render()` status option support. Closes #425 [thanks aheckmann] * Fixed `res.sendfile()` responding with 403 on malicious path * Fixed `res.download()` bug; when an error occurs remove _Content-Disposition_ * Fixed; mounted apps settings now inherit from parent app [aheckmann] * Fixed; stripping Content-Length / Content-Type when 204 * Fixed `res.send()` 204. Closes #419 * Fixed multiple _Set-Cookie_ headers via `res.header()`. Closes #402 * Fixed bug messing with error handlers when `listenFD()` is called instead of `listen()`. [thanks guillermo] 1.0.0rc2 / 2010-08-17 ================== * Added `app.register()` for template engine mapping. Closes #390 * Added `res.render()` callback support as second argument (no options) * Added callback support to `res.download()` * Added callback support for `res.sendfile()` * Added support for middleware access via `express.middlewareName()` vs `connect.middlewareName()` * Added "partials" setting to docs * Added default expresso tests to `express(1)` generated app. Closes #384 * Fixed `res.sendfile()` error handling, defer via `next()` * Fixed `res.render()` callback when a layout is used [thanks guillermo] * Fixed; `make install` creating ~/.node_libraries when not present * Fixed issue preventing error handlers from being defined anywhere. Closes #387 1.0.0rc / 2010-07-28 ================== * Added mounted hook. Closes #369 * Added connect dependency to _package.json_ * Removed "reload views" setting and support code development env never caches, production always caches. * Removed _param_ in route callbacks, signature is now simply (req, res, next), previously (req, res, params, next). Use _req.params_ for path captures, _req.query_ for GET params. * Fixed "home" setting * Fixed middleware/router precedence issue. Closes #366 * Fixed; _configure()_ callbacks called immediately. Closes #368 1.0.0beta2 / 2010-07-23 ================== * Added more examples * Added; exporting `Server` constructor * Added `Server#helpers()` for view locals * Added `Server#dynamicHelpers()` for dynamic view locals. Closes #349 * Added support for absolute view paths * Added; _home_ setting defaults to `Server#route` for mounted apps. Closes #363 * Added Guillermo Rauch to the contributor list * Added support for "as" for non-collection partials. Closes #341 * Fixed _install.sh_, ensuring _~/.node_libraries_ exists. Closes #362 [thanks jf] * Fixed `res.render()` exceptions, now passed to `next()` when no callback is given [thanks guillermo] * Fixed instanceof `Array` checks, now `Array.isArray()` * Fixed express(1) expansion of public dirs. Closes #348 * Fixed middleware precedence. Closes #345 * Fixed view watcher, now async [thanks aheckmann] 1.0.0beta / 2010-07-15 ================== * Re-write - much faster - much lighter - Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs 0.14.0 / 2010-06-15 ================== * Utilize relative requires * Added Static bufferSize option [aheckmann] * Fixed caching of view and partial subdirectories [aheckmann] * Fixed mime.type() comments now that ".ext" is not supported * Updated haml submodule * Updated class submodule * Removed bin/express 0.13.0 / 2010-06-01 ================== * 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 view support due to fs.readFile Buffers * Changed; mime.type() no longer accepts ".type" due to node extname() changes 0.12.0 / 2010-05-22 ================== * Added node v0.1.96 compatibility * Added view `helpers` export which act as additional local variables * Updated haml submodule * Changed ETag; removed inode, modified time only * Fixed LF to CRLF for setting multiple cookies * Fixed cookie compilation; values are now urlencoded * Fixed cookies parsing; accepts quoted values and url escaped cookies 0.11.0 / 2010-05-06 ================== * Added support for layouts using different engines - this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' }) - this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml' - this.render('page.html.haml', { layout: false }) // no layout * Updated ext submodule * Updated haml submodule * Fixed EJS partial support by passing along the context. Issue #307 0.10.1 / 2010-05-03 ================== * Fixed binary uploads. 0.10.0 / 2010-04-30 ================== * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s 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 * Added error response support for text/plain, application/json. Closes #297 * Added callback function param to Request#error() * Added Request#sendHead() * Added Request#stream() * Added support for Request#respond(304, null) for empty response bodies * Added ETag support to Request#sendfile() * Added options to Request#sendfile(), passed to fs.createReadStream() * Added filename arg to Request#download() * Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request * Performance enhanced by preventing several calls to toLowerCase() in Router#match() * Changed; Request#sendfile() now streams * Changed; Renamed Request#halt() to Request#respond(). Closes #289 * Changed; Using sys.inspect() instead of JSON.encode() for error output * Changed; run() returns the http.Server instance. Closes #298 * Changed; Defaulting Server#host to null (INADDR_ANY) * Changed; Logger "common" format scale of 0.4f * Removed Logger "request" format * Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found * Fixed several issues with http client * Fixed Logger Content-Length output * Fixed bug preventing Opera from retaining the generated session id. Closes #292 0.9.0 / 2010-04-14 ================== * Added DSL level error() route support * Added DSL level notFound() route support * Added Request#error() * Added Request#notFound() * Added Request#render() callback function. Closes #258 * Added "max upload size" setting * Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254 * 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) * 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) * Changed; session cookie is now httpOnly * Changed; Request is no longer global * Changed; Event is no longer global * Changed; "sys" module is no longer global * Changed; moved Request#download to Static plugin where it belongs * Changed; Request instance created before body parsing. Closes #262 * Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253 * Changed; Pre-caching view partials in memory when "cache view partials" is enabled * Updated support to node --version 0.1.90 * Updated dependencies * Removed set("session cookie") in favour of use(Session, { cookie: { ... }}) * Removed utils.mixin(); use Object#mergeDeep() 0.8.0 / 2010-03-19 ================== * Added coffeescript example app. Closes #242 * Changed; cache api now async friendly. Closes #240 * Removed deprecated 'express/static' support. Use 'express/plugins/static' 0.7.6 / 2010-03-19 ================== * Added Request#isXHR. Closes #229 * Added `make install` (for the executable) * Added `express` executable for setting up simple app templates * Added "GET /public/*" to Static plugin, defaulting to /public * Added Static plugin * Fixed; Request#render() only calls cache.get() once * Fixed; Namespacing View caches with "view:" * Fixed; Namespacing Static caches with "static:" * Fixed; Both example apps now use the Static plugin * Fixed set("views"). Closes #239 * Fixed missing space for combined log format * Deprecated Request#sendfile() and 'express/static' * Removed Server#running 0.7.5 / 2010-03-16 ================== * Added Request#flash() support without args, now returns all flashes * Updated ext submodule 0.7.4 / 2010-03-16 ================== * Fixed session reaper * Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft) 0.7.3 / 2010-03-16 ================== * Added package.json * Fixed requiring of haml / sass due to kiwi removal 0.7.2 / 2010-03-16 ================== * Fixed GIT submodules (HAH!) 0.7.1 / 2010-03-16 ================== * Changed; Express now using submodules again until a PM is adopted * Changed; chat example using millisecond conversions from ext 0.7.0 / 2010-03-15 ================== * Added Request#pass() support (finds the next matching route, or the given path) * Added Logger plugin (default "common" format replaces CommonLogger) * Removed Profiler plugin * Removed CommonLogger plugin 0.6.0 / 2010-03-11 ================== * Added seed.yml for kiwi package management support * Added HTTP client query string support when method is GET. Closes #205 * Added support for arbitrary view engines. For example "foo.engine.html" will now require('engine'), the exports from this module are cached after the first require(). * Added async plugin support * Removed usage of RESTful route funcs as http client get() etc, use http.get() and friends * Removed custom exceptions 0.5.0 / 2010-03-10 ================== * Added ext dependency (library of js extensions) * Removed extname() / basename() utils. Use path module * Removed toArray() util. Use arguments.values * Removed escapeRegexp() util. Use RegExp.escape() * Removed process.mixin() dependency. Use utils.mixin() * Removed Collection * Removed ElementCollection * Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com) ;) 0.4.0 / 2010-02-11 ================== * Added flash() example to sample upload app * Added high level restful http client module (express/http) * Changed; RESTful route functions double as HTTP clients. Closes #69 * Changed; throwing error when routes are added at runtime * Changed; defaulting render() context to the current Request. Closes #197 * Updated haml submodule 0.3.0 / 2010-02-11 ================== * Updated haml / sass submodules. Closes #200 * Added flash message support. Closes #64 * Added accepts() now allows multiple args. fixes #117 * Added support for plugins to halt. Closes #189 * Added alternate layout support. Closes #119 * Removed Route#run(). Closes #188 * Fixed broken specs due to use(Cookie) missing 0.2.1 / 2010-02-05 ================== * Added "plot" format option for Profiler (for gnuplot processing) * Added request number to Profiler plugin * 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 0.2.0 / 2010-02-03 ================== * Added parseParam() support for name[] etc. (allows for file inputs with "multiple" attr) Closes #180 * Added Both Cache and Session option "reapInterval" may be "reapEvery". Closes #174 * Added expiration support to cache api with reaper. Closes #133 * Added cache Store.Memory#reap() * Added Cache; cache api now uses first class Cache instances * Added abstract session Store. Closes #172 * Changed; cache Memory.Store#get() utilizing Collection * Renamed MemoryStore -> Store.Memory * Fixed use() of the same plugin several time will always use latest options. Closes #176 0.1.0 / 2010-02-03 ================== * Changed; Hooks (before / after) pass request as arg as well as evaluated in their context * Updated node support to 0.1.27 Closes #169 * Updated dirname(__filename) -> __dirname * Updated libxmljs support to v0.2.0 * Added session support with memory store / reaping * Added quick uid() helper * Added multi-part upload support * Added Sass.js support / submodule * Added production env caching view contents and static files * Added static file caching. Closes #136 * Added cache plugin with memory stores * Added support to StaticFile so that it works with non-textual files. * Removed dirname() helper * Removed several globals (now their modules must be required) 0.0.2 / 2010-01-10 ================== * Added view benchmarks; currently haml vs ejs * Added Request#attachment() specs. Closes #116 * Added use of node's parseQuery() util. Closes #123 * Added `make init` for submodules * Updated Haml * 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 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 * Fixed `make test` now builds libxmljs.node before testing 0.0.1 / 2010-01-03 ================== * Initial release express-4.17.3/LICENSE000066400000000000000000000023411420332637600143120ustar00rootroot00000000000000(The MIT License) Copyright (c) 2009-2014 TJ Holowaychuk Copyright (c) 2013-2014 Roman Shtylman Copyright (c) 2014-2015 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. express-4.17.3/Readme-Guide.md000066400000000000000000000103151420332637600160570ustar00rootroot00000000000000# README guidelines Every module in the expressjs, pillarjs, and jshttp organizations should have a README file named `README.md`. The purpose of the README is to: - Explain the purpose of the module and how to use it. - Act as a landing page (both on GitHub and npmjs.com) for the module to help people find it via search. Middleware module READMEs are also incorporated into https://expressjs.com/en/resources/middleware.html. - Encourage community contributions and participation. Use the [README template](https://github.com/expressjs/express/wiki/README-template) to quickly create a new README file. ## Top-level items **Badges** (optional): At the very top (with no subheading), include any applicable badges, such as npm version/downloads, build status, test coverage, and so on. Badges should resolve properly (not display a broken image). Possible badges include: - npm version: `[![NPM Version][npm-image]][npm-url]` - npm downloads: `[![NPM Downloads][downloads-image]][downloads-url]` - Build status: `[![Build Status][travis-image]][travis-url]` - Test coverage: `[![Test Coverage][coveralls-image]][coveralls-url]` - Tips: `[![Gratipay][gratipay-image]][gratipay-url]` **Summary**: Following badges, provide a one- or two-sentence description of what the module does. This should be the same as the npmjs.org blurb (which comes from the description property of `package.json`). Since npm doesn't handle markdown for the blurb, avoid using markdown in the summary sentence. **TOC** (Optional): For longer READMEs, provide a table of contents that has a relative link to each section. A tool such as [doctoc](https://www.npmjs.com/package/doctoc) makes it very easy to generate a TOC. ## Overview Optionally, include a section of one or two paragraphs with more high-level information on what the module does, what problems it solves, why one would use it and how. Don't just repeat what's in the summary. ## Installation Required. This section is typically just: ```sh $ npm install module-name ``` But include any other steps or requirements. NOTE: Use the `sh` code block to make the shell command display properly on the website. ## Basic use - Provide a general description of how to use the module with code sample. Include any important caveats or restrictions. - Explain the most common use cases. - Optional: a simple "hello world" type example (where applicable). This example is in addition to the more comprehensive [example section](#examples) later. ## API Provide complete API documentation. Formatting conventions: Each function is listed in a 3rd-level heading (`###`), like this: ``` ### Function_name(arg, options [, optional_arg] ... ) ``` **Options objects** For arguments that are objects (for example, options object), describe the properties in a table, as follows. This matches the formatting used in the [Express API docs](https://expressjs.com/en/4x/api.html). |Property | Description | Type | Default| |----------|-----------|------------|-------------| |Name of the property in `monospace`. | Brief description | String, Number, Boolean, etc. | If applicable.| If all the properties are required (i.e. there are no defaults), then you can omit the default column. Instead of very lengthy descriptions, link out to subsequent paragraphs for more detailed explanation of specific cases (e.g. "When this property is set to 'foobar', xyz happens; see <link to following section >.) If there are options properties that are themselves options, use additional tables. See [`trust proxy` and `etag` properties](https://expressjs.com/en/4x/api.html#app.settings.table). ## Examples Every README should have at least one example; ideally more. For code samples, be sure to use the `js` code block, for proper display in the website, e.g.: ```js var csurf = require('csurf') ... ``` ## Tests What tests are included. How to run them. The convention for running tests is `npm test`. All our projects should follow this convention. ## Contributors Names of module "owners" (lead developers) and other developers who have contributed. ## License Link to the license, with a short description of what it is, e.g. "MIT" or whatever. Ideally, avoid putting the license text directly in the README; link to it instead. express-4.17.3/Readme.md000066400000000000000000000113131420332637600150230ustar00rootroot00000000000000[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/) Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Linux Build][ci-image]][ci-url] [![Windows Build][appveyor-image]][appveyor-url] [![Test Coverage][coveralls-image]][coveralls-url] ```js const express = require('express') const app = express() app.get('/', function (req, res) { res.send('Hello World') }) app.listen(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 0.10 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 ``` Follow [our installing guide](http://expressjs.com/en/starter/installing.html) for more information. ## Features * Robust routing * Focus on high performance * Super-high test coverage * HTTP helpers (redirection, caching, etc) * View system supporting 14+ template engines * Content negotiation * Executable for generating applications quickly ## Docs & Community * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/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/expressjs/express/wiki) * [Google Group](https://groups.google.com/group/express-js) for discussion * [Gitter](https://gitter.im/expressjs/express) for support and discussion **PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x). ### Security Issues If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md). ## Quick Start The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below: Install the executable. The executable's major version will match Express's: ```bash $ npm install -g express-generator@4 ``` Create the app: ```bash $ express /tmp/foo && cd /tmp/foo ``` Install dependencies: ```bash $ npm install ``` Start the server: ```bash $ 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, 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), you can quickly craft your perfect framework. ## Examples To view the examples, clone the Express repo and install the dependencies: ```bash $ git clone git://github.com/expressjs/express.git --depth 1 $ cd express $ npm install ``` Then run whichever example you want: ```bash $ node examples/content-negotiation ``` ## Tests To run the test suite, first install the dependencies, then run `npm test`: ```bash $ npm install $ npm test ``` ## Contributing [Contributing Guide](Contributing.md) ## People The original author of Express is [TJ Holowaychuk](https://github.com/tj) The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [List of all contributors](https://github.com/expressjs/express/graphs/contributors) ## License [MIT](LICENSE) [ci-image]: https://img.shields.io/github/workflow/status/expressjs/express/ci/master.svg?label=linux [ci-url]: https://github.com/expressjs/express/actions?query=workflow%3Aci [npm-image]: https://img.shields.io/npm/v/express.svg [npm-url]: https://npmjs.org/package/express [downloads-image]: https://img.shields.io/npm/dm/express.svg [downloads-url]: https://npmcharts.com/compare/express?minimal=true [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/expressjs/express/master.svg [coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master express-4.17.3/Release-Process.md000066400000000000000000000146641420332637600166360ustar00rootroot00000000000000# Express Release Process This document contains the technical aspects of the Express release process. The intended audience is those who have been authorized by the Express Technical Committee (TC) to create, promote and sign official release builds for Express, as npm packages hosted on https://npmjs.com/package/express. ## Who can make releases? Release authorization is given by the Express TC. Once authorized, an individual must have the following access permissions: ### 1. Github release access The individual making the release will need to be a member of the expressjs/express team with Write permission level so they are able to tag the release commit and push changes to the expressjs/express repository (see Steps 4 and 5). ### 2. npmjs.com release access The individual making the release will need to be made an owner on the `express` package on npmjs.com so they are able to publish the release (see Step 6). ## How to publish a release Before publishing, the following preconditions should be met: - A release proposal issue or tracking pull request (see "Proposal branch" below) will exist documenting: - the proposed changes - the type of release: patch, minor or major - the version number (according to semantic versioning - http://semver.org) - The proposed changes should be complete. There are two main release flows: patch and non-patch. The patch flow is for making **patch releases**. As per semantic versioning, patch releases are for simple changes, eg: typo fixes, patch dependency updates, and simple/low-risk bug fixes. Every other type of change is made via the non-patch flow. ### Branch terminology "Master branch" - There is a branch in git used for the current major version of Express, named `master`. - This branch contains the completed commits for the next patch release of the current major version. - Releases for the current major version are published from this branch. "Version branch" - For any given major version of Express (current, previous or next) there is a branch in git for that release named `.x` (eg: `4.x`). - This branch points to the commit of the latest tag for the given major version. "Release branch" - For any given major version of Express, there is a branch used for publishing releases. - For the current major version of Express, the release branch is the "Master branch" named `master`. - For all other major versions of Express, the release branch is the "Version branch" named `.x`. "Proposal branch" - A branch in git representing a proposed new release of Express. This can be a minor or major release, named `.0` for a major release, `.` for a minor release. - A tracking pull request should exist to document the proposed release, targeted at the appropriate release branch. Prior to opening the tracking pull request the content of the release may have be discussed in an issue. - This branch contains the commits accepted so far that implement the proposal in the tracking pull request. ### Patch flow In the patch flow, simple changes are committed to the release branch which acts as an ever-present branch for the next patch release of the associated major version of Express. The release branch is usually kept in a state where it is ready to release. Releases are made when sufficient time or change has been made to warrant it. This is usually proposed and decided using a github issue. ### Non-patch flow In the non-patch flow, changes are committed to a temporary proposal branch created specifically for that release proposal. The branch is based on the most recent release of the major version of Express that the release targets. Releases are made when all the changes on a proposal branch are complete and approved. This is done by merging the proposal branch into the release branch (using a fast-forward merge), tagging it with the new version number and publishing the release package to npmjs.com. ### Flow Below is a detailed description of the steps to publish a release. #### Step 1. Check the release is ready to publish Check any relevant information to ensure the release is ready, eg: any milestone, label, issue or tracking pull request for the release. The release is ready when all proposed code, tests and documentation updates are complete (either merged, closed or re-targeted to another release). #### Step 2. (Non-patch flow only) Merge the proposal branch into the release branch In the patch flow: skip this step. In the non-patch flow: ```sh $ git checkout $ git merge --ff-only ``` - see "Release branch" of "Branches" above. - see "Proposal branch" of "Non-patch flow" above. **NOTE:** You may need to rebase the proposal branch to allow a fast-forward merge. Using a fast-forward merge keeps the history clean as it does not introduce merge commits. ### Step 3. Update the History.md and package.json to the new version number The changes so far for the release should already be documented under the "unreleased" section at the top of the History.md file, as per the usual development practice. Change "unreleased" to the new release version / date. Example diff fragment: ```diff -unreleased -========== +4.13.3 / 2015-08-02 +=================== ``` The version property in the package.json should already contain the version of the previous release. Change it to the new release version. Commit these changes together under a single commit with the message set to the new release version (eg: `4.13.3`): ```sh $ git checkout <..edit files..> $ git add History.md package.json $ git commit -m '' ``` ### Step 4. Identify and tag the release commit with the new release version Create a lightweight tag (rather than an annotated tag) named after the new release version (eg: `4.13.3`). ```sh $ git tag ``` ### Step 5. Push the release branch changes and tag to github The branch and tag should be pushed directly to the main repository (https://github.com/expressjs/express). ```sh $ git push origin $ git push origin ``` ### Step 6. Publish to npmjs.com Ensure your local working copy is completely clean (no extra or changed files). You can use `git status` for this purpose. ```sh $ npm login $ npm publish ``` **NOTE:** The version number to publish will be picked up automatically from package.json. express-4.17.3/Security.md000066400000000000000000000035751420332637600154500ustar00rootroot00000000000000# 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 the lead maintainer in the Readme.md file. 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. You can also report a vulnerability through the [Node Security Project](https://nodesecurity.io/report). ## 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. ## Comments on this Policy If you have suggestions on how this process could be improved please submit a pull request. express-4.17.3/Triager-Guide.md000066400000000000000000000073551420332637600162710ustar00rootroot00000000000000# Express Triager Guide ## Issue Triage Process When a new issue or pull request is opened the issue will be labeled with `needs triage`. If a triage team member is available they can help make sure all the required information is provided. Depending on the issue or PR there are several next labels they can add for further classification: * `needs triage`: This can be kept if the triager is unsure which next steps to take * `awaiting more info`: If more info has been requested from the author, apply this label. * `question`: User questions that do not appear to be bugs or enhancements. * `discuss`: Topics for discussion. Might end in an `enhancement` or `question` label. * `bug`: Issues that present a reasonable conviction there is a reproducible bug. * `enhancement`: Issues that are found to be a reasonable candidate feature additions. In all cases, issues may be closed by maintainers if they don't receive a timely response when further information is sought, or when additional questions are asked. ## Approaches and Best Practices for getting into triage contributions Review the organization's [StatusBoard](https://expressjs.github.io/statusboard/), pay special attention to these columns: stars, watchers, open issues, and contributors. This gives you a general idea about the criticality and health of the repository. Pick a few projects based on that criteria, your interests, and skills (existing or aspiring). Review the project's contribution guideline if present. In a nutshell, commit to the community's standards and values. Review the documentation, for most of the projects it is just the README.md, and make sure you understand the key APIs, semantics, configurations, and use cases. It might be helpful to write your own test apps to re-affirm your understanding of the key functions. This may identify some gaps in documentation, record those as they might be good PR's to open. Skim through the issue backlog; identify low hanging issues and mostly new ones. From those, attempt to recreate issues based on the OP description and ask questions if required. No question is a bad question! ## Removal of Triage Role There are a few cases where members can be removed as triagers: - Breaking the CoC or project contributor guidelines - Abuse or misuse of the role as deemed by the TC - Lack of participation for more than 6 months If any of these happen we will discuss as a part of the triage portion of the regular TC meetings. If you have questions feel free to reach out to any of the TC members. ## Other Helpful Hints: - Everyone is welcome to attend the [Express Technical Committee Meetings](https://github.com/expressjs/discussions#expressjs-tc-meetings), and as a triager, it might help to get a better idea of what's happening with the project. - When exploring the module's functionality there are a few helpful steps: - Turn on `DEBUG=*` (see https://www.npmjs.com/package/debug) to get detailed log information - It is also a good idea to do live debugging to follow the control flow, try using `node --inspect` - It is a good idea to make at least one pass of reading through the entire source - When reviewing the list of open issues there are some common types and suggested actions: - New/unattended issues or simple questions: A good place to start - Hard bugs & ongoing discussions: always feel free to chime in and help - Issues that imply gaps in the documentation: open PRs with changes or help the user to do so - For recurring issues, it is helpful to create functional examples to demonstrate (publish as gists or a repo) - Review and identify the maintainers. If necessary, at-mention one or more of them if you are unsure what to do - Make sure all your interactions are professional, welcoming, and respectful to the parties involved. express-4.17.3/appveyor.yml000066400000000000000000000064421420332637600157030ustar00rootroot00000000000000environment: matrix: - nodejs_version: "0.10" - nodejs_version: "0.12" - nodejs_version: "1.8" - nodejs_version: "2.5" - nodejs_version: "3.3" - nodejs_version: "4.9" - nodejs_version: "5.12" - nodejs_version: "6.17" - nodejs_version: "7.10" - nodejs_version: "8.17" - nodejs_version: "9.11" - nodejs_version: "10.24" - nodejs_version: "11.15" - nodejs_version: "12.22" - nodejs_version: "13.14" - nodejs_version: "14.19" cache: - node_modules install: # Install Node.js - ps: >- try { Install-Product node $env:nodejs_version -ErrorAction Stop } catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) } # Configure npm - ps: | npm config set loglevel error npm config set shrinkwrap false # Remove all non-test dependencies - ps: | # Remove example dependencies npm rm --silent --save-dev connect-redis # Remove lint dependencies cmd.exe /c "node -pe `"Object.keys(require('./package').devDependencies).join('\n')`"" | ` sls "^eslint(-|$)" | ` %{ npm rm --silent --save-dev $_ } # Setup Node.js version-specific dependencies - ps: | # mocha for testing # - use 3.x for Node.js < 4 # - use 5.x for Node.js < 6 # - use 6.x for Node.js < 8 # - use 7.x for Node.js < 10 # - use 8.x for Node.js < 12 if ([int]$env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev mocha@3.5.3 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev mocha@5.2.0 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) { npm install --silent --save-dev mocha@6.2.2 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 10) { npm install --silent --save-dev mocha@7.2.0 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 12) { npm install --silent --save-dev mocha@8.4.0 } - ps: | # nyc for test coverage # - use 10.3.2 for Node.js < 4 # - use 11.9.0 for Node.js < 6 # - use 14.1.1 for Node.js < 8 if ([int]$env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev nyc@10.3.2 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev nyc@11.9.0 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) { npm install --silent --save-dev nyc@14.1.1 } - ps: | # supertest for http calls # - use 2.0.0 for Node.js < 4 # - use 3.4.2 for Node.js < 6 # - use 6.1.6 for Node.js < 8 if ([int]$env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev supertest@2.0.0 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev supertest@3.4.2 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) { npm install --silent --save-dev supertest@6.1.6 } # Update Node.js modules - ps: | # Prune & rebuild node_modules if (Test-Path -Path node_modules) { npm prune npm rebuild } # Install Node.js modules - npm install build: off test_script: # Output version data - ps: | node --version npm --version # Run test script - npm run test-ci version: "{build}" express-4.17.3/benchmarks/000077500000000000000000000000001420332637600154225ustar00rootroot00000000000000express-4.17.3/benchmarks/Makefile000066400000000000000000000003111420332637600170550ustar00rootroot00000000000000 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 @echo .PHONY: all express-4.17.3/benchmarks/middleware.js000066400000000000000000000004701420332637600200760ustar00rootroot00000000000000 var express = require('..'); var app = express(); // number of middleware var n = parseInt(process.env.MW || '1', 10); console.log(' %s middleware', n); while (n--) { app.use(function(req, res, next){ next(); }); } app.use(function(req, res, next){ res.send('Hello World') }); app.listen(3333); express-4.17.3/benchmarks/run000077500000000000000000000003041420332637600161510ustar00rootroot00000000000000#!/usr/bin/env bash echo MW=$1 node $2 & pid=$! sleep 2 wrk 'http://localhost:3333/?foo[bar]=baz' \ -d 3 \ -c 50 \ -t 8 \ | grep 'Requests/sec' \ | awk '{ print " " $2 }' kill $pid express-4.17.3/examples/000077500000000000000000000000001420332637600151235ustar00rootroot00000000000000express-4.17.3/examples/README.md000066400000000000000000000031671420332637600164110ustar00rootroot00000000000000# 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 - [multipart](./multipart) - Accepting multipart-encoded forms - [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 express-4.17.3/examples/auth/000077500000000000000000000000001420332637600160645ustar00rootroot00000000000000express-4.17.3/examples/auth/index.js000066400000000000000000000066721420332637600175440ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var hash = require('pbkdf2-password')() var path = require('path'); var session = require('express-session'); var app = module.exports = express(); // config app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); // middleware app.use(express.urlencoded({ extended: false })) app.use(session({ resave: false, // don't save session if unmodified saveUninitialized: false, // don't create session until something stored secret: 'shhhh, very secret' })); // Session-persisted message middleware app.use(function(req, res, next){ var err = req.session.error; var msg = req.session.success; delete req.session.error; delete req.session.success; res.locals.message = ''; if (err) res.locals.message = '

' + err + '

'; if (msg) res.locals.message = '

' + msg + '

'; next(); }); // dummy database var users = { tj: { name: 'tj' } }; // when you create a user, generate a salt // and hash the password ('foobar' is the pass here) hash({ password: 'foobar' }, function (err, pass, salt, hash) { if (err) throw err; // store the salt & hash in the "db" users.tj.salt = salt; users.tj.hash = hash; }); // Authenticate using our plain-object database of doom! 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(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({ password: pass, salt: user.salt }, function (err, pass, salt, hash) { if (err) return fn(err); if (hash === user.hash) return fn(null, user) fn(null, null) }); } function restrict(req, res, next) { if (req.session.user) { next(); } else { req.session.error = 'Access denied!'; res.redirect('/login'); } } app.get('/', function(req, res){ res.redirect('/login'); }); app.get('/restricted', restrict, function(req, res){ res.send('Wahoo! restricted area, click to logout'); }); app.get('/logout', function(req, res){ // destroy the user's session to log them out // will be re-created next request req.session.destroy(function(){ res.redirect('/'); }); }); app.get('/login', function(req, res){ res.render('login'); }); app.post('/login', function (req, res, next) { 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 req.session.regenerate(function(){ // Store the user's primary key // in the session store to be retrieved, // or in this case the entire user object req.session.user = user; req.session.success = 'Authenticated as ' + user.name + ' click to logout. ' + ' You may now access /restricted.'; res.redirect('back'); }); } else { req.session.error = 'Authentication failed, please check your ' + ' username and password.' + ' (use "tj" and "foobar")'; res.redirect('/login'); } }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/auth/views/000077500000000000000000000000001420332637600172215ustar00rootroot00000000000000express-4.17.3/examples/auth/views/foot.ejs000066400000000000000000000000221420332637600206650ustar00rootroot00000000000000 express-4.17.3/examples/auth/views/head.ejs000066400000000000000000000006111420332637600206230ustar00rootroot00000000000000 <%= title %> express-4.17.3/examples/auth/views/login.ejs000066400000000000000000000007331420332637600210370ustar00rootroot00000000000000 <%- include('head', { title: 'Authentication Example' }) -%>

Login

<%- message %> Try accessing /restricted, then authenticate with "tj" and "foobar".

<%- include('foot') -%> express-4.17.3/examples/content-negotiation/000077500000000000000000000000001420332637600211135ustar00rootroot00000000000000express-4.17.3/examples/content-negotiation/db.js000066400000000000000000000002221420332637600220320ustar00rootroot00000000000000'use strict' var users = []; users.push({ name: 'Tobi' }); users.push({ name: 'Loki' }); users.push({ name: 'Jane' }); module.exports = users; express-4.17.3/examples/content-negotiation/index.js000066400000000000000000000017531420332637600225660ustar00rootroot00000000000000'use strict' var express = require('../../'); var app = module.exports = express(); var users = require('./db'); // so either you can deal with different types of formatting // for expected response in index.js app.get('/', function(req, res){ res.format({ html: function(){ res.send('
    ' + users.map(function(user){ return '
  • ' + user.name + '
  • '; }).join('') + '
'); }, text: function(){ res.send(users.map(function(user){ return ' - ' + user.name + '\n'; }).join('')); }, json: function(){ res.json(users); } }); }); // or you could write a tiny middleware like // this to add a layer of abstraction // and make things a bit more declarative: function format(path) { var obj = require(path); return function(req, res){ res.format(obj); }; } app.get('/users', format('./users')); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/content-negotiation/users.js000066400000000000000000000005761420332637600226220ustar00rootroot00000000000000'use strict' var users = require('./db'); exports.html = function(req, res){ res.send('
    ' + users.map(function(user){ return '
  • ' + user.name + '
  • '; }).join('') + '
'); }; exports.text = function(req, res){ res.send(users.map(function(user){ return ' - ' + user.name + '\n'; }).join('')); }; exports.json = function(req, res){ res.json(users); }; express-4.17.3/examples/cookie-sessions/000077500000000000000000000000001420332637600202405ustar00rootroot00000000000000express-4.17.3/examples/cookie-sessions/index.js000066400000000000000000000011041420332637600217010ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var cookieSession = require('cookie-session'); var express = require('../../'); var app = module.exports = express(); // add req.session cookie support app.use(cookieSession({ secret: 'manny is cool' })); // do something with the session app.use(count); // custom middleware function count(req, res) { req.session.count = (req.session.count || 0) + 1 res.send('viewed ' + req.session.count + ' times\n') } /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/cookies/000077500000000000000000000000001420332637600165575ustar00rootroot00000000000000express-4.17.3/examples/cookies/index.js000066400000000000000000000023631420332637600202300ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var app = module.exports = express(); var logger = require('morgan'); var cookieParser = require('cookie-parser'); // custom log format if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url')) // parses request cookies, populating // req.cookies and req.signedCookies // when the secret is passed, used // for signing the cookies. app.use(cookieParser('my secret here')); // parses x-www-form-urlencoded app.use(express.urlencoded({ extended: false })) app.get('/', function(req, res){ if (req.cookies.remember) { res.send('Remembered :). Click to forget!.'); } else { res.send('

Check to ' + '.

'); } }); app.get('/forget', function(req, res){ res.clearCookie('remember'); res.redirect('back'); }); app.post('/', function(req, res){ var minute = 60000; if (req.body.remember) res.cookie('remember', 1, { maxAge: minute }); res.redirect('back'); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/downloads/000077500000000000000000000000001420332637600171155ustar00rootroot00000000000000express-4.17.3/examples/downloads/files/000077500000000000000000000000001420332637600202175ustar00rootroot00000000000000express-4.17.3/examples/downloads/files/CCTV大赛上海分赛区.txt000066400000000000000000000000461420332637600312050ustar00rootroot00000000000000Only for test. The file name is faked.express-4.17.3/examples/downloads/files/amazing.txt000066400000000000000000000000301420332637600223770ustar00rootroot00000000000000what an amazing downloadexpress-4.17.3/examples/downloads/files/notes/000077500000000000000000000000001420332637600213475ustar00rootroot00000000000000express-4.17.3/examples/downloads/files/notes/groceries.txt000066400000000000000000000000261420332637600240700ustar00rootroot00000000000000* milk * eggs * bread express-4.17.3/examples/downloads/index.js000066400000000000000000000023431420332637600205640ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var path = require('path'); var resolvePath = require('resolve-path') var app = module.exports = express(); // path to where the files are stored on disk var FILES_DIR = path.join(__dirname, 'files') app.get('/', function(req, res){ res.send('') }); // /files/* is accessed via req.params[0] // but here we name it :file app.get('/files/:file(*)', function(req, res, next){ var filePath = resolvePath(FILES_DIR, req.params.file) res.download(filePath, function (err) { if (!err) return; // file sent if (err.status !== 404) return next(err); // non-404 error // file for download not found res.statusCode = 404; res.send('Cant find that file, sorry!'); }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/ejs/000077500000000000000000000000001420332637600157045ustar00rootroot00000000000000express-4.17.3/examples/ejs/index.js000066400000000000000000000024501420332637600173520ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var path = require('path'); var app = module.exports = express(); // Register ejs as .html. If we did // not call this, we would need to // name our views foo.ejs instead // of foo.html. The __express method // is simply a function that engines // use to hook into the Express view // system by default, so if we want // to change "foo.ejs" to "foo.html" // we simply pass _any_ function, in this // case `ejs.__express`. app.engine('.html', require('ejs').__express); // Optional since express defaults to CWD/views app.set('views', path.join(__dirname, 'views')); // Path to our public directory app.use(express.static(path.join(__dirname, 'public'))); // Without this you would need to // supply the extension to res.render() // ex: res.render('users.html'). app.set('view engine', 'html'); // Dummy users var users = [ { name: 'tobi', email: 'tobi@learnboost.com' }, { name: 'loki', email: 'loki@learnboost.com' }, { name: 'jane', email: 'jane@learnboost.com' } ]; app.get('/', function(req, res){ res.render('users', { users: users, title: "EJS example", header: "Some users" }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/ejs/public/000077500000000000000000000000001420332637600171625ustar00rootroot00000000000000express-4.17.3/examples/ejs/public/stylesheets/000077500000000000000000000000001420332637600215365ustar00rootroot00000000000000express-4.17.3/examples/ejs/public/stylesheets/style.css000066400000000000000000000001421420332637600234050ustar00rootroot00000000000000body { padding: 50px 80px; font: 14px "Helvetica Neue", "Lucida Grande", Arial, sans-serif; } express-4.17.3/examples/ejs/views/000077500000000000000000000000001420332637600170415ustar00rootroot00000000000000express-4.17.3/examples/ejs/views/footer.html000066400000000000000000000000201420332637600212150ustar00rootroot00000000000000 express-4.17.3/examples/ejs/views/header.html000066400000000000000000000003541420332637600211610ustar00rootroot00000000000000 <%= title %> express-4.17.3/examples/ejs/views/users.html000066400000000000000000000003161420332637600210700ustar00rootroot00000000000000<%- include('header.html') -%>

Users

    <% users.forEach(function(user){ %>
  • <%= user.name %> <<%= user.email %>>
  • <% }) %>
<%- include('footer.html') -%> express-4.17.3/examples/error-pages/000077500000000000000000000000001420332637600173515ustar00rootroot00000000000000express-4.17.3/examples/error-pages/index.js000066400000000000000000000051441420332637600210220ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var path = require('path'); var app = module.exports = express(); var logger = require('morgan'); var silent = process.env.NODE_ENV === 'test' // general config app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // our custom "verbose errors" setting // which we can use in the templates // via settings['verbose errors'] app.enable('verbose errors'); // disable them in production // use $ NODE_ENV=production node examples/error-pages if (app.settings.env === 'production') app.disable('verbose errors') silent || app.use(logger('dev')); // Routes app.get('/', function(req, res){ res.render('index.ejs'); }); app.get('/404', function(req, res, next){ // trigger a 404 since no other middleware // will match /404 after this one, and we're not // responding here next(); }); app.get('/403', function(req, res, next){ // trigger a 403 error var err = new Error('not allowed!'); err.status = 403; next(err); }); app.get('/500', function(req, res, next){ // trigger a generic (500) error next(new Error('keyboard cat!')); }); // Error handlers // Since this is the last non-error-handling // middleware use()d, we assume 404, as nothing else // responded. // $ curl http://localhost:3000/notfound // $ curl http://localhost:3000/notfound -H "Accept: application/json" // $ curl http://localhost:3000/notfound -H "Accept: text/plain" app.use(function(req, res, next){ res.status(404); 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 // as regular middleware, however they require an // arity of 4, aka the signature (err, req, res, next). // when connect has an error, it will invoke ONLY error-handling // middleware. // If we were to next() here any remaining non-error-handling // middleware would then be executed, or if we next(err) to // continue passing the error, only error-handling middleware // would remain being executed, however here // we simply respond with an error page. app.use(function(err, req, res, next){ // we may use properties of the error object // here and next(err) appropriately, or if // we possibly recovered from the error, simply next(). res.status(err.status || 500); res.render('500', { error: err }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/error-pages/views/000077500000000000000000000000001420332637600205065ustar00rootroot00000000000000express-4.17.3/examples/error-pages/views/404.ejs000066400000000000000000000001321420332637600215140ustar00rootroot00000000000000<%- include('error_header') -%>

Cannot find <%= url %>

<%- include('footer') -%> express-4.17.3/examples/error-pages/views/500.ejs000066400000000000000000000003321420332637600215130ustar00rootroot00000000000000<%- include('error_header') -%>

Error: <%= error.message %>

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

An error occurred!

<% } %> <%- include('footer') -%> express-4.17.3/examples/error-pages/views/error_header.ejs000066400000000000000000000002721420332637600236530ustar00rootroot00000000000000 Error

An error occurred!

express-4.17.3/examples/error-pages/views/footer.ejs000066400000000000000000000000201420332637600224770ustar00rootroot00000000000000 express-4.17.3/examples/error-pages/views/index.ejs000066400000000000000000000005441420332637600223230ustar00rootroot00000000000000 Custom Pages Example

My Site

Pages Example

express-4.17.3/examples/error/000077500000000000000000000000001420332637600162545ustar00rootroot00000000000000express-4.17.3/examples/error/index.js000066400000000000000000000024731420332637600177270ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var logger = require('morgan'); var app = module.exports = express(); var test = app.get('env') === 'test' if (!test) app.use(logger('dev')); // error handling middleware have an arity of 4 // instead of the typical (req, res, next), // otherwise they behave exactly like regular // middleware, you may have several of them, // in different orders etc. function error(err, req, res, next) { // log it if (!test) console.error(err.stack); // respond with 500 "Internal Server Error". res.status(500); res.send('Internal Server Error'); } app.get('/', function(req, res){ // 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!')); }); }); // the error handler is placed after routes // if it were above it would not receive errors // from app.get() etc app.use(error); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/hello-world/000077500000000000000000000000001420332637600173535ustar00rootroot00000000000000express-4.17.3/examples/hello-world/index.js000066400000000000000000000004151420332637600210200ustar00rootroot00000000000000'use strict' var express = require('../../'); var app = module.exports = express() app.get('/', function(req, res){ res.send('Hello World'); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/markdown/000077500000000000000000000000001420332637600167455ustar00rootroot00000000000000express-4.17.3/examples/markdown/index.js000066400000000000000000000017651420332637600204230ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var escapeHtml = require('escape-html'); var express = require('../..'); var fs = require('fs'); var marked = require('marked'); var path = require('path'); var app = module.exports = express(); // register .md as an engine in express view system app.engine('md', function(path, options, fn){ fs.readFile(path, 'utf8', function(err, str){ if (err) return fn(err); var html = marked.parse(str).replace(/\{([^}]+)\}/g, function(_, name){ return escapeHtml(options[name] || ''); }); fn(null, html); }); }); app.set('views', path.join(__dirname, 'views')); // make it the default so we dont need .md app.set('view engine', 'md'); app.get('/', function(req, res){ res.render('index', { title: 'Markdown Example' }); }); app.get('/fail', function(req, res){ res.render('missing', { title: 'Markdown Example' }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/markdown/views/000077500000000000000000000000001420332637600201025ustar00rootroot00000000000000express-4.17.3/examples/markdown/views/index.md000066400000000000000000000000721420332637600215320ustar00rootroot00000000000000 # {title} Just an example view rendered with _markdown_.express-4.17.3/examples/multi-router/000077500000000000000000000000001420332637600175735ustar00rootroot00000000000000express-4.17.3/examples/multi-router/controllers/000077500000000000000000000000001420332637600221415ustar00rootroot00000000000000express-4.17.3/examples/multi-router/controllers/api_v1.js000066400000000000000000000004201420332637600236520ustar00rootroot00000000000000'use strict' var express = require('../../..'); var apiv1 = express.Router(); apiv1.get('/', function(req, res) { res.send('Hello from APIv1 root route.'); }); apiv1.get('/users', function(req, res) { res.send('List of APIv1 users.'); }); module.exports = apiv1; express-4.17.3/examples/multi-router/controllers/api_v2.js000066400000000000000000000004201420332637600236530ustar00rootroot00000000000000'use strict' var express = require('../../..'); var apiv2 = express.Router(); apiv2.get('/', function(req, res) { res.send('Hello from APIv2 root route.'); }); apiv2.get('/users', function(req, res) { res.send('List of APIv2 users.'); }); module.exports = apiv2; express-4.17.3/examples/multi-router/index.js000066400000000000000000000006031420332637600212370ustar00rootroot00000000000000'use strict' var express = require('../..'); var app = module.exports = express(); app.use('/api/v1', require('./controllers/api_v1')); app.use('/api/v2', require('./controllers/api_v2')); app.get('/', function(req, res) { res.send('Hello from root route.') }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/multipart/000077500000000000000000000000001420332637600171445ustar00rootroot00000000000000express-4.17.3/examples/multipart/index.js000066400000000000000000000026131420332637600206130ustar00rootroot00000000000000'use strict' /** * 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'); } express-4.17.3/examples/mvc/000077500000000000000000000000001420332637600157105ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/000077500000000000000000000000001420332637600202565ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/main/000077500000000000000000000000001420332637600212025ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/main/index.js000066400000000000000000000001171420332637600226460ustar00rootroot00000000000000'use strict' exports.index = function(req, res){ res.redirect('/users'); }; express-4.17.3/examples/mvc/controllers/pet/000077500000000000000000000000001420332637600210465ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/pet/index.js000066400000000000000000000011271420332637600225140ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var db = require('../../db'); exports.engine = 'ejs'; exports.before = function(req, res, next){ var pet = db.pets[req.params.pet_id]; if (!pet) return next('route'); req.pet = pet; next(); }; exports.show = function(req, res, next){ res.render('show', { pet: req.pet }); }; exports.edit = function(req, res, next){ res.render('edit', { pet: req.pet }); }; exports.update = function(req, res, next){ var body = req.body; req.pet.name = body.pet.name; res.message('Information updated!'); res.redirect('/pet/' + req.pet.id); }; express-4.17.3/examples/mvc/controllers/pet/views/000077500000000000000000000000001420332637600222035ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/pet/views/edit.ejs000066400000000000000000000007001420332637600236300ustar00rootroot00000000000000 Edit <%= pet.name %>

<%= pet.name %>

express-4.17.3/examples/mvc/controllers/pet/views/show.ejs000066400000000000000000000005161420332637600236700ustar00rootroot00000000000000 <%= pet.name %>

<%= pet.name %> edit

You are viewing <%= pet.name %>

express-4.17.3/examples/mvc/controllers/user-pet/000077500000000000000000000000001420332637600220225ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/user-pet/index.js000066400000000000000000000007241420332637600234720ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var db = require('../../db'); exports.name = 'pet'; exports.prefix = '/user/:user_id'; exports.create = function(req, res, next){ var id = req.params.user_id; var user = db.users[id]; var body = req.body; if (!user) return next('route'); var pet = { name: body.pet.name }; pet.id = db.pets.push(pet) - 1; user.pets.push(pet); res.message('Added pet ' + body.pet.name); res.redirect('/user/' + id); }; express-4.17.3/examples/mvc/controllers/user/000077500000000000000000000000001420332637600212345ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/user/index.js000066400000000000000000000015501420332637600227020ustar00rootroot00000000000000'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(); // pretend to query a database... process.nextTick(function(){ req.user = db.users[id]; // cant find that user if (!req.user) return next('route'); // found it, move on to the routes next(); }); }; exports.list = function(req, res, next){ res.render('list', { users: db.users }); }; exports.edit = function(req, res, next){ res.render('edit', { user: req.user }); }; exports.show = function(req, res, next){ res.render('show', { user: req.user }); }; exports.update = function(req, res, next){ var body = req.body; req.user.name = body.user.name; res.message('Information updated!'); res.redirect('/user/' + req.user.id); }; express-4.17.3/examples/mvc/controllers/user/views/000077500000000000000000000000001420332637600223715ustar00rootroot00000000000000express-4.17.3/examples/mvc/controllers/user/views/edit.hbs000066400000000000000000000013331420332637600240140ustar00rootroot00000000000000 Edit {{user.name}}

{{user.name}}

express-4.17.3/examples/mvc/controllers/user/views/list.hbs000066400000000000000000000006041420332637600240420ustar00rootroot00000000000000 Users

Users

Click a user below to view their pets.

express-4.17.3/examples/mvc/controllers/user/views/show.hbs000066400000000000000000000011311420332637600240430ustar00rootroot00000000000000 {{user.name}}

{{user.name}} edit

{{#if hasMessages}}
    {{#each messages}}
  • {{this}}
  • {{/each}}
{{/if}} {{#if user.pets.length}}

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

    {{#each user.pets}}
  • {{name}}
  • {{/each}}
{{else}}

No pets!

{{/if}} express-4.17.3/examples/mvc/db.js000066400000000000000000000006441420332637600166370ustar00rootroot00000000000000'use strict' // faux database var pets = exports.pets = []; pets.push({ name: 'Tobi', id: 0 }); pets.push({ name: 'Loki', id: 1 }); pets.push({ name: 'Jane', id: 2 }); pets.push({ name: 'Raul', id: 3 }); 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 }); express-4.17.3/examples/mvc/index.js000066400000000000000000000044131420332637600173570ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var logger = require('morgan'); var path = require('path'); var session = require('express-session'); var methodOverride = require('method-override'); var app = module.exports = express(); // 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', path.join(__dirname, 'views')); // define a custom res.message() method // which stores messages in the session app.response.message = function(msg){ // reference `req.session` via the `this.req` reference var sess = this.req.session; // simply add the msg to an array for later sess.messages = sess.messages || []; sess.messages.push(msg); return this; }; // log if (!module.parent) app.use(logger('dev')); // serve static files app.use(express.static(path.join(__dirname, 'public'))); // session support app.use(session({ resave: false, // don't save session if unmodified saveUninitialized: false, // don't create session until something stored secret: 'some secret here' })); // parse request bodies (req.body) app.use(express.urlencoded({ extended: true })) // allow overriding methods in query (?_method=put) app.use(methodOverride('_method')); // expose the "messages" local variable when views are rendered app.use(function(req, res, next){ var msgs = req.session.messages || []; // expose "messages" local variable res.locals.messages = msgs; // expose "hasMessages" res.locals.hasMessages = !! msgs.length; /* This is equivalent: res.locals({ messages: msgs, hasMessages: !! msgs.length }); */ next(); // empty or "flush" the messages so they // don't build up req.session.messages = []; }); // load controllers require('./lib/boot')(app, { verbose: !module.parent }); app.use(function(err, req, res, next){ // log it if (!module.parent) console.error(err.stack); // error page res.status(500).render('5xx'); }); // assume 404 since no middleware responded app.use(function(req, res, next){ res.status(404).render('404', { url: req.originalUrl }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/mvc/lib/000077500000000000000000000000001420332637600164565ustar00rootroot00000000000000express-4.17.3/examples/mvc/lib/boot.js000066400000000000000000000043151420332637600177620ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../..'); var fs = require('fs'); var path = require('path'); module.exports = function(parent, options){ var dir = path.join(__dirname, '..', 'controllers'); var verbose = options.verbose; 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(file); var name = obj.name || name; var prefix = obj.prefix || ''; var app = express(); var handler; var method; var url; // allow specifying the view engine if (obj.engine) app.set('view engine', obj.engine); app.set('views', path.join(__dirname, '..', 'controllers', name, 'views')); // generate routes based // on the exported methods for (var key in obj) { // "reserved" exports if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue; // route exports switch (key) { case 'show': method = 'get'; url = '/' + name + '/:' + name + '_id'; break; case 'list': method = 'get'; url = '/' + name + 's'; break; case 'edit': method = 'get'; url = '/' + name + '/:' + name + '_id/edit'; break; case 'update': method = 'put'; url = '/' + name + '/:' + name + '_id'; break; case 'create': method = 'post'; url = '/' + name; break; case 'index': method = 'get'; url = '/'; break; default: /* istanbul ignore next */ throw new Error('unrecognized route: ' + name + '.' + key); } // setup handler = obj[key]; url = prefix + url; // before middleware support if (obj.before) { app[method](url, obj.before, handler); verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), url, key); } else { app[method](url, handler); verbose && console.log(' %s %s -> %s', method.toUpperCase(), url, key); } } // mount the app parent.use(app); }); }; express-4.17.3/examples/mvc/public/000077500000000000000000000000001420332637600171665ustar00rootroot00000000000000express-4.17.3/examples/mvc/public/style.css000066400000000000000000000003161420332637600210400ustar00rootroot00000000000000body { padding: 50px; font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif; } a { color: #107aff; text-decoration: none; } a:hover { text-decoration: underline; } h1 a { font-size: 16px; } express-4.17.3/examples/mvc/views/000077500000000000000000000000001420332637600170455ustar00rootroot00000000000000express-4.17.3/examples/mvc/views/404.ejs000066400000000000000000000004711420332637600200610ustar00rootroot00000000000000 Not Found

404: Not Found

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

express-4.17.3/examples/mvc/views/5xx.ejs000066400000000000000000000005201420332637600202710ustar00rootroot00000000000000 Internal Server Error

500: Internal Server Error

Looks like something blew up!

express-4.17.3/examples/online/000077500000000000000000000000001420332637600164075ustar00rootroot00000000000000express-4.17.3/examples/online/index.js000066400000000000000000000020001420332637600200440ustar00rootroot00000000000000'use strict' // install redis first: // https://redis.io/ // then: // $ npm install redis online // $ redis-server /** * Module dependencies. */ var express = require('../..'); var online = require('online'); var redis = require('redis'); var db = redis.createClient(); // online online = online(db); // app var app = express(); // activity tracking, in this case using // the UA string, you would use req.user.id etc app.use(function(req, res, next){ // fire-and-forget online.add(req.headers['user-agent']); next(); }); /** * List helper. */ function list(ids) { return '
    ' + ids.map(function(id){ return '
  • ' + id + '
  • '; }).join('') + '
'; } /** * GET users online. */ app.get('/', function(req, res, next){ online.last(5, function(err, ids){ if (err) return next(err); res.send('

Users online: ' + ids.length + '

' + list(ids)); }); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/params/000077500000000000000000000000001420332637600164065ustar00rootroot00000000000000express-4.17.3/examples/params/index.js000066400000000000000000000026431420332637600200600ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var app = module.exports = express(); // Faux database var users = [ { 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){ req.params[name] = parseInt(num, 10); if( isNaN(req.params[name]) ){ next(createError(400, 'failed to parseInt '+num)); } else { next(); } }); // Load user by id app.param('user', function(req, res, next, id){ if (req.user = users[id]) { next(); } else { next(createError(404, 'failed to find user')); } }); /** * GET index. */ app.get('/', function(req, res){ res.send('Visit /user/0 or /users/0-2'); }); /** * GET :user. */ app.get('/user/:user', function(req, res, next){ res.send('user ' + req.user.name); }); /** * GET users :from - :to. */ app.get('/users/:from-:to', function(req, res, next){ 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 + 1).join(', ')); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/resource/000077500000000000000000000000001420332637600167525ustar00rootroot00000000000000express-4.17.3/examples/resource/index.js000066400000000000000000000043661420332637600204300ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var app = module.exports = express(); // Ad-hoc example resource method app.resource = function(path, obj) { this.get(path, obj.index); 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; obj.range(req, res, a, b, format); }); this.get(path + '/:id', obj.show); this.delete(path + '/:id', function(req, res){ var id = parseInt(req.params.id, 10); obj.destroy(req, res, id); }); }; // Fake records var users = [ { name: 'tj' } , { name: 'ciaran' } , { name: 'aaron' } , { name: 'guillermo' } , { name: 'simon' } , { name: 'tobi' } ]; // Fake controller. var User = { index: function(req, res){ res.send(users); }, show: function(req, res){ res.send(users[req.params.id] || { error: 'Cannot find user' }); }, destroy: function(req, res, id){ var destroyed = id in users; delete users[id]; res.send(destroyed ? 'destroyed' : 'Cannot find user'); }, range: function(req, res, a, b, format){ var range = users.slice(a, b + 1); switch (format) { case 'json': res.send(range); break; case 'html': default: var html = '
    ' + range.map(function(user){ return '
  • ' + user.name + '
  • '; }).join('\n') + '
'; res.send(html); break; } } }; // curl http://localhost:3000/users -- responds with all users // curl http://localhost:3000/users/1 -- responds with user 1 // curl http://localhost:3000/users/4 -- responds with error // curl http://localhost:3000/users/1..3 -- responds with several users // curl -X DELETE http://localhost:3000/users/1 -- deletes the user app.resource('/users', User); app.get('/', function(req, res){ res.send([ '

Examples:

    ' , '
  • GET /users
  • ' , '
  • GET /users/1
  • ' , '
  • GET /users/3
  • ' , '
  • GET /users/1..3
  • ' , '
  • GET /users/1..3.json
  • ' , '
  • DELETE /users/4
  • ' , '
' ].join('\n')); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/route-map/000077500000000000000000000000001420332637600170345ustar00rootroot00000000000000express-4.17.3/examples/route-map/index.js000066400000000000000000000026131420332637600205030ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var escapeHtml = require('escape-html') var express = require('../../lib/express'); var verbose = process.env.NODE_ENV !== 'test' var app = module.exports = express(); app.map = function(a, route){ route = route || ''; for (var key in a) { switch (typeof a[key]) { // { '/path': { ... }} case 'object': app.map(a[key], route + key); break; // get: function(){ ... } case 'function': if (verbose) console.log('%s %s', key, route); app[key](route, a[key]); break; } } }; var users = { list: function(req, res){ res.send('user list'); }, get: function(req, res){ res.send('user ' + escapeHtml(req.params.uid)) }, delete: function(req, res){ res.send('delete users'); } }; var pets = { list: function(req, res){ res.send('user ' + escapeHtml(req.params.uid) + '\'s pets') }, delete: function(req, res){ res.send('delete ' + escapeHtml(req.params.uid) + '\'s pet ' + escapeHtml(req.params.pid)) } }; app.map({ '/users': { get: users.list, delete: users.delete, '/:uid': { get: users.get, '/pets': { get: pets.list, '/:pid': { delete: pets.delete } } } } }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/route-middleware/000077500000000000000000000000001420332637600203745ustar00rootroot00000000000000express-4.17.3/examples/route-middleware/index.js000066400000000000000000000045311420332637600220440ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../lib/express'); var app = express(); // Example requests: // curl http://localhost:3000/user/0 // curl http://localhost:3000/user/0/edit // curl http://localhost:3000/user/1 // curl http://localhost:3000/user/1/edit (unauthorized since this is not you) // curl -X DELETE http://localhost:3000/user/0 (unauthorized since you are not an admin) // Dummy users var users = [ { id: 0, name: 'tj', email: 'tj@vision-media.ca', role: 'member' } , { id: 1, name: 'ciaran', email: 'ciaranj@gmail.com', role: 'member' } , { id: 2, name: 'aaron', email: 'aaron.heckmann+github@gmail.com', role: 'admin' } ]; function loadUser(req, res, next) { // You would fetch your user from the db var user = users[req.params.id]; if (user) { req.user = user; next(); } else { next(new Error('Failed to load user ' + req.params.id)); } } function andRestrictToSelf(req, res, next) { // If our authenticated user is the user we are viewing // then everything is fine :) if (req.authenticatedUser.id === req.user.id) { next(); } else { // You may want to implement specific exceptions // such as UnauthorizedError or similar so that you // can handle these can be special-cased in an error handler // (view ./examples/pages for this) next(new Error('Unauthorized')); } } function andRestrictTo(role) { return function(req, res, next) { if (req.authenticatedUser.role === role) { next(); } else { next(new Error('Unauthorized')); } } } // Middleware for faux authentication // you would of course implement something real, // but this illustrates how an authenticated user // may interact with middleware app.use(function(req, res, next){ req.authenticatedUser = users[0]; next(); }); app.get('/', function(req, res){ res.redirect('/user/0'); }); app.get('/user/:id', loadUser, function(req, res){ res.send('Viewing user ' + req.user.name); }); app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){ res.send('Editing user ' + req.user.name); }); app.delete('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){ res.send('Deleted user ' + req.user.name); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/route-separation/000077500000000000000000000000001420332637600204245ustar00rootroot00000000000000express-4.17.3/examples/route-separation/index.js000066400000000000000000000021521420332637600220710ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var path = require('path'); var app = express(); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var methodOverride = require('method-override'); var site = require('./site'); var post = require('./post'); var user = require('./user'); module.exports = app; // Config app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); /* istanbul ignore next */ if (!module.parent) { app.use(logger('dev')); } app.use(methodOverride('_method')); app.use(cookieParser()); app.use(express.urlencoded({ extended: true })) app.use(express.static(path.join(__dirname, 'public'))); // General app.get('/', site.index); // User app.get('/users', user.list); app.all('/user/:id/:op?', user.load); app.get('/user/:id', user.view); app.get('/user/:id/view', user.view); app.get('/user/:id/edit', user.edit); app.put('/user/:id/edit', user.update); // Posts app.get('/posts', post.list); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/route-separation/post.js000066400000000000000000000004441420332637600217510ustar00rootroot00000000000000'use strict' // Fake posts database var posts = [ { title: 'Foo', body: 'some foo bar' }, { title: 'Foo bar', body: 'more foo bar' }, { title: 'Foo bar baz', body: 'more foo bar baz' } ]; exports.list = function(req, res){ res.render('posts', { title: 'Posts', posts: posts }); }; express-4.17.3/examples/route-separation/public/000077500000000000000000000000001420332637600217025ustar00rootroot00000000000000express-4.17.3/examples/route-separation/public/style.css000066400000000000000000000004361420332637600235570ustar00rootroot00000000000000body { padding: 50px; font: 14px "Helvetica Neue", Arial, sans-serif; } a { color: #00AEFF; text-decoration: none; } a.edit { color: #000; opacity: .3; } a.edit::before { content: ' ['; } a.edit::after { content: ']'; } dt { font-weight: bold; } dd { margin: 15px; }express-4.17.3/examples/route-separation/site.js000066400000000000000000000001631420332637600217260ustar00rootroot00000000000000'use strict' exports.index = function(req, res){ res.render('index', { title: 'Route Separation Example' }); }; express-4.17.3/examples/route-separation/user.js000066400000000000000000000017321420332637600217430ustar00rootroot00000000000000'use strict' // Fake user database var users = [ { name: 'TJ', email: 'tj@vision-media.ca' }, { name: 'Tobi', email: 'tobi@vision-media.ca' } ]; exports.list = function(req, res){ res.render('users', { title: 'Users', users: users }); }; exports.load = function(req, res, next){ var id = req.params.id; req.user = users[id]; if (req.user) { next(); } else { var err = new Error('cannot find user ' + id); err.status = 404; next(err); } }; exports.view = function(req, res){ res.render('users/view', { title: 'Viewing user ' + req.user.name, user: req.user }); }; exports.edit = function(req, res){ res.render('users/edit', { title: 'Editing user ' + req.user.name, user: req.user }); }; exports.update = function(req, res){ // Normally you would handle all kinds of // validation and save back to the db var user = req.body.user; req.user.name = user.name; req.user.email = user.email; res.redirect('back'); }; express-4.17.3/examples/route-separation/views/000077500000000000000000000000001420332637600215615ustar00rootroot00000000000000express-4.17.3/examples/route-separation/views/footer.ejs000066400000000000000000000000201420332637600235520ustar00rootroot00000000000000 express-4.17.3/examples/route-separation/views/header.ejs000066400000000000000000000003401420332637600235110ustar00rootroot00000000000000 <%= title %> express-4.17.3/examples/route-separation/views/index.ejs000066400000000000000000000003041420332637600233700ustar00rootroot00000000000000<%- include('header') -%>

<%= title %>

<%- include('footer') -%> express-4.17.3/examples/route-separation/views/posts/000077500000000000000000000000001420332637600227315ustar00rootroot00000000000000express-4.17.3/examples/route-separation/views/posts/index.ejs000066400000000000000000000003211420332637600245370ustar00rootroot00000000000000<%- include('../header') -%>

Posts

<% posts.forEach(function(post) { %>
<%= post.title %>
<%= post.body %>
<% }) %>
<%- include('../footer') -%> express-4.17.3/examples/route-separation/views/users/000077500000000000000000000000001420332637600227225ustar00rootroot00000000000000express-4.17.3/examples/route-separation/views/users/edit.ejs000066400000000000000000000006701420332637600243550ustar00rootroot00000000000000<%- include('../header') -%>

Editing <%= user.name %>

Name:

Email:

<%- include('../footer') -%> express-4.17.3/examples/route-separation/views/users/index.ejs000066400000000000000000000004401420332637600245320ustar00rootroot00000000000000<%- include('../header') -%>

<%= title %>

<% users.forEach(function(user, index) { %>
  • <%= user.name %> edit
  • <% }) %>
    <%- include('../footer') -%> express-4.17.3/examples/route-separation/views/users/view.ejs000066400000000000000000000002201420332637600243710ustar00rootroot00000000000000<%- include('../header') -%>

    <%= user.name %>

    Email: <%= user.email %>

    <%- include('../footer') -%> express-4.17.3/examples/search/000077500000000000000000000000001420332637600163705ustar00rootroot00000000000000express-4.17.3/examples/search/index.js000066400000000000000000000022061420332637600200350ustar00rootroot00000000000000'use strict' // install redis first: // https://redis.io/ // then: // $ npm install redis // $ redis-server /** * Module dependencies. */ var express = require('../..'); var path = require('path'); var redis = require('redis'); var db = redis.createClient(); // npm install redis var app = express(); app.use(express.static(path.join(__dirname, 'public'))); // populate search db.sadd('ferret', 'tobi'); db.sadd('ferret', 'loki'); db.sadd('ferret', 'jane'); db.sadd('cat', 'manny'); db.sadd('cat', 'luna'); /** * GET search for :query. */ app.get('/search/:query?', function(req, res){ var query = req.params.query; db.smembers(query, function(err, vals){ if (err) return res.send(500); res.send(vals); }); }); /** * GET client javascript. Here we use sendFile() * because serving __dirname with the static() middleware * would also mean serving our server "index.js" and the "search.jade" * template. */ app.get('/client.js', function(req, res){ res.sendFile(path.join(__dirname, 'client.js')); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/search/public/000077500000000000000000000000001420332637600176465ustar00rootroot00000000000000express-4.17.3/examples/search/public/client.js000066400000000000000000000006061420332637600214640ustar00rootroot00000000000000'use strict' var search = document.querySelector('[type=search]'); var code = document.querySelector('pre'); search.addEventListener('keyup', function(){ var xhr = new XMLHttpRequest; xhr.open('GET', '/search/' + search.value, true); xhr.onreadystatechange = function(){ if (xhr.readyState === 4) { code.textContent = xhr.responseText; } }; xhr.send(); }, false); express-4.17.3/examples/search/public/index.html000066400000000000000000000007571420332637600216540ustar00rootroot00000000000000 Search example

    Search

    Try searching for "ferret" or "cat".

      
    
    
    express-4.17.3/examples/session/000077500000000000000000000000001420332637600166065ustar00rootroot00000000000000express-4.17.3/examples/session/index.js000066400000000000000000000015141420332637600202540ustar00rootroot00000000000000'use strict'
    
    // install redis first:
    // https://redis.io/
    
    // then:
    // $ npm install redis
    // $ redis-server
    
    var express = require('../..');
    var session = require('express-session');
    
    var app = express();
    
    // Populates req.session
    app.use(session({
      resave: false, // don't save session if unmodified
      saveUninitialized: false, // don't create session until something stored
      secret: 'keyboard cat'
    }));
    
    app.get('/', function(req, res){
      var body = '';
      if (req.session.views) {
        ++req.session.views;
      } else {
        req.session.views = 1;
        body += '

    First time visiting? view this page in several browsers :)

    '; } res.send(body + '

    viewed ' + req.session.views + ' times.

    '); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/session/redis.js000066400000000000000000000016751420332637600202630ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var logger = require('morgan'); var session = require('express-session'); // pass the express to the connect redis module // allowing it to inherit from session.Store var RedisStore = require('connect-redis')(session); var app = express(); app.use(logger('dev')); // Populates req.session app.use(session({ resave: false, // don't save session if unmodified saveUninitialized: false, // don't create session until something stored secret: 'keyboard cat', store: new RedisStore })); app.get('/', function(req, res){ var body = ''; if (req.session.views) { ++req.session.views; } else { req.session.views = 1; body += '

    First time visiting? view this page in several browsers :)

    '; } res.send(body + '

    viewed ' + req.session.views + ' times.

    '); }); app.listen(3000); console.log('Express app started on port 3000'); express-4.17.3/examples/static-files/000077500000000000000000000000001420332637600175125ustar00rootroot00000000000000express-4.17.3/examples/static-files/index.js000066400000000000000000000025161420332637600211630ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var logger = require('morgan'); var path = require('path'); var app = express(); // log requests app.use(logger('dev')); // express on its own has no notion // of a "file". The express.static() // middleware checks for a file matching // the `req.path` within the directory // that you pass it. In this case "GET /js/app.js" // will look for "./public/js/app.js". app.use(express.static(path.join(__dirname, 'public'))); // if you wanted to "prefix" you may use // the mounting feature of Connect, for example // "GET /static/js/app.js" instead of "GET /js/app.js". // The mount-path "/static" is simply removed before // passing control to the express.static() middleware, // thus it serves the file correctly by ignoring "/static" app.use('/static', express.static(path.join(__dirname, 'public'))); // if for some reason you want to serve files from // several directories, you can use express.static() // multiple times! Here we're passing "./public/css", // this will allow "GET /style.css" instead of "GET /css/style.css": app.use(express.static(path.join(__dirname, 'public', 'css'))); app.listen(3000); console.log('listening on port 3000'); console.log('try:'); console.log(' GET /hello.txt'); console.log(' GET /js/app.js'); console.log(' GET /css/style.css'); express-4.17.3/examples/static-files/public/000077500000000000000000000000001420332637600207705ustar00rootroot00000000000000express-4.17.3/examples/static-files/public/css/000077500000000000000000000000001420332637600215605ustar00rootroot00000000000000express-4.17.3/examples/static-files/public/css/style.css000066400000000000000000000000131420332637600234240ustar00rootroot00000000000000body { }express-4.17.3/examples/static-files/public/hello.txt000066400000000000000000000000031420332637600226250ustar00rootroot00000000000000heyexpress-4.17.3/examples/static-files/public/js/000077500000000000000000000000001420332637600214045ustar00rootroot00000000000000express-4.17.3/examples/static-files/public/js/app.js000066400000000000000000000000071420332637600225170ustar00rootroot00000000000000// foo express-4.17.3/examples/vhost/000077500000000000000000000000001420332637600162665ustar00rootroot00000000000000express-4.17.3/examples/vhost/index.js000066400000000000000000000020151420332637600177310ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var logger = require('morgan'); var vhost = require('vhost'); /* edit /etc/hosts: 127.0.0.1 foo.example.com 127.0.0.1 bar.example.com 127.0.0.1 example.com */ // Main server app var main = express(); if (!module.parent) main.use(logger('dev')); main.get('/', function(req, res){ res.send('Hello from main app!'); }); main.get('/:sub', function(req, res){ res.send('requested ' + req.params.sub); }); // Redirect app var redirect = express(); redirect.use(function(req, res){ if (!module.parent) console.log(req.vhost); res.redirect('http://example.com:3000/' + req.vhost[0]); }); // Vhost app var app = module.exports = express(); app.use(vhost('*.example.com', redirect)); // Serves all subdomains via Redirect app app.use(vhost('example.com', main)); // Serves top level domain via Main server app /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/view-constructor/000077500000000000000000000000001420332637600204605ustar00rootroot00000000000000express-4.17.3/examples/view-constructor/github-view.js000066400000000000000000000020431420332637600232470ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var https = require('https'); var path = require('path'); var extname = path.extname; /** * Expose `GithubView`. */ module.exports = GithubView; /** * Custom view that fetches and renders * remove github templates. You could * render templates from a database etc. */ function GithubView(name, options){ this.name = name; options = options || {}; this.engine = options.engines[extname(name)]; // "root" is the app.set('views') setting, however // in your own implementation you could ignore this this.path = '/' + options.root + '/master/' + name; } /** * Render the view. */ GithubView.prototype.render = function(options, fn){ var self = this; var opts = { host: 'raw.githubusercontent.com', port: 443, path: this.path, method: 'GET' }; https.request(opts, function(res) { var buf = ''; res.setEncoding('utf8'); res.on('data', function(str){ buf += str }); res.on('end', function(){ self.engine(buf, options, fn); }); }).end(); }; express-4.17.3/examples/view-constructor/index.js000066400000000000000000000022171420332637600221270ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var GithubView = require('./github-view'); var md = require('marked').parse; var app = module.exports = express(); // register .md as an engine in express view system app.engine('md', function(str, options, fn){ try { var html = md(str); html = html.replace(/\{([^}]+)\}/g, function(_, name){ return options[name] || ''; }); fn(null, html); } catch(err) { fn(err); } }); // pointing to a particular github repo to load files from it app.set('views', 'expressjs/express'); // register a new view constructor app.set('view', GithubView); app.get('/', function(req, res){ // rendering a view relative to the repo. // app.locals, res.locals, and locals passed // work like they normally would res.render('examples/markdown/views/index.md', { title: 'Example' }); }); app.get('/Readme.md', function(req, res){ // rendering a view from https://github.com/expressjs/express/blob/master/Readme.md res.render('Readme.md'); }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/view-locals/000077500000000000000000000000001420332637600173505ustar00rootroot00000000000000express-4.17.3/examples/view-locals/index.js000066400000000000000000000060721420332637600210220ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../..'); var path = require('path'); var User = require('./user'); var app = express(); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // filter ferrets only function ferrets(user) { return user.species === 'ferret' } // naive nesting approach, // delegating errors to next(err) // in order to expose the "count" // and "users" locals app.get('/', function(req, res, next){ User.count(function(err, count){ if (err) return next(err); User.all(function(err, users){ if (err) return next(err); res.render('index', { title: 'Users', count: count, users: users.filter(ferrets) }); }) }) }); // this approach is cleaner, // less nesting and we have // the variables available // on the request object function count(req, res, next) { User.count(function(err, count){ if (err) return next(err); req.count = count; next(); }) } function users(req, res, next) { User.all(function(err, users){ if (err) return next(err); req.users = users; next(); }) } app.get('/middleware', count, users, function(req, res, next){ res.render('index', { title: 'Users', count: req.count, users: req.users.filter(ferrets) }); }); // this approach is much like the last // however we're explicitly exposing // the locals within each middleware // // note that this may not always work // well, for example here we filter // the users in the middleware, which // may not be ideal for our application. // so in that sense the previous example // is more flexible with `req.users`. function count2(req, res, next) { User.count(function(err, count){ if (err) return next(err); res.locals.count = count; next(); }) } function users2(req, res, next) { User.all(function(err, users){ if (err) return next(err); res.locals.users = users.filter(ferrets); next(); }) } app.get('/middleware-locals', count2, users2, function(req, res, next){ // you can see now how we have much less // to pass to res.render(). If we have // several routes related to users this // can be a great productivity booster res.render('index', { title: 'Users' }); }); // keep in mind that middleware may be placed anywhere // and in various combinations, so if you have locals // that you wish to make available to all subsequent // middleware/routes you can do something like this: /* app.use(function(req, res, next){ res.locals.user = req.user; res.locals.sess = req.session; next(); }); */ // or suppose you have some /admin // "global" local variables: /* app.use('/api', function(req, res, next){ res.locals.user = req.user; res.locals.sess = req.session; next(); }); */ // the following is effectively the same, // but uses a route instead: /* app.all('/api/*', function(req, res, next){ res.locals.user = req.user; res.locals.sess = req.session; next(); }); */ /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/examples/view-locals/user.js000066400000000000000000000013321420332637600206630ustar00rootroot00000000000000'use strict' module.exports = User; // faux model function User(name, age, species) { this.name = name; this.age = age; this.species = species; } User.all = function(fn){ // process.nextTick makes sure this function API // behaves in an asynchronous manner, like if it // was a real DB query to read all users. process.nextTick(function(){ fn(null, users); }); }; User.count = function(fn){ process.nextTick(function(){ fn(null, users.length); }); }; // faux database var users = []; users.push(new User('Tobi', 2, 'ferret')); users.push(new User('Loki', 1, 'ferret')); users.push(new User('Jane', 6, 'ferret')); users.push(new User('Luna', 1, 'cat')); users.push(new User('Manny', 1, 'cat')); express-4.17.3/examples/view-locals/views/000077500000000000000000000000001420332637600205055ustar00rootroot00000000000000express-4.17.3/examples/view-locals/views/index.ejs000066400000000000000000000007641420332637600223260ustar00rootroot00000000000000 <%= title %>

    <%= title %>

    <% users.forEach(function(user) { %>
  • <%= user.name %> is a <% user.age %> year old <%= user.species %>
  • <% }); %> express-4.17.3/examples/web-service/000077500000000000000000000000001420332637600173365ustar00rootroot00000000000000express-4.17.3/examples/web-service/index.js000066400000000000000000000057541420332637600210160ustar00rootroot00000000000000'use strict' /** * Module dependencies. */ var express = require('../../'); var app = module.exports = express(); // create an error with .status. we // can then use the property in our // custom error handler (Connect respects this prop as well) function error(status, msg) { var err = new Error(msg); err.status = status; return err; } // if we wanted to supply more than JSON, we could // use something similar to the content-negotiation // example. // here we validate the API key, // by mounting this middleware to /api // meaning only paths prefixed with "/api" // will cause this middleware to be invoked app.use('/api', function(req, res, next){ var key = req.query['api-key']; // key isn't present if (!key) return next(error(400, 'api key required')); // key is invalid if (apiKeys.indexOf(key) === -1) return next(error(401, 'invalid api key')) // all good, store req.key for route access req.key = key; next(); }); // map of valid api keys, typically mapped to // account info with some sort of database like redis. // api keys do _not_ serve as authentication, merely to // track API usage or help prevent malicious behavior etc. var apiKeys = ['foo', 'bar', 'baz']; // these two objects will serve as our faux database var repos = [ { name: 'express', url: 'https://github.com/expressjs/express' }, { name: 'stylus', url: 'https://github.com/learnboost/stylus' }, { name: 'cluster', url: 'https://github.com/learnboost/cluster' } ]; var users = [ { name: 'tobi' } , { name: 'loki' } , { name: 'jane' } ]; var userRepos = { tobi: [repos[0], repos[1]] , loki: [repos[1]] , jane: [repos[2]] }; // we now can assume the api key is valid, // and simply expose the data // example: http://localhost:3000/api/users/?api-key=foo app.get('/api/users', function(req, res, next){ res.send(users); }); // example: http://localhost:3000/api/repos/?api-key=foo app.get('/api/repos', function(req, res, next){ res.send(repos); }); // example: http://localhost:3000/api/user/tobi/repos/?api-key=foo app.get('/api/user/:name/repos', function(req, res, next){ var name = req.params.name; var user = userRepos[name]; if (user) res.send(user); else next(); }); // middleware with an arity of 4 are considered // error handling middleware. When you next(err) // it will be passed through the defined middleware // in order, but ONLY those with an arity of 4, ignoring // regular middleware. app.use(function(err, req, res, next){ // whatever you want here, feel free to populate // properties on `err` to treat it differently in here. res.status(err.status || 500); res.send({ error: err.message }); }); // our custom JSON 404 middleware. Since it's placed last // it will be the last middleware called, if all others // invoke next() and do not respond. app.use(function(req, res){ res.status(404); res.send({ error: "Sorry, can't find that" }) }); /* istanbul ignore next */ if (!module.parent) { app.listen(3000); console.log('Express started on port 3000'); } express-4.17.3/index.js000066400000000000000000000003401420332637600147470ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; module.exports = require('./lib/express'); express-4.17.3/lib/000077500000000000000000000000001420332637600140535ustar00rootroot00000000000000express-4.17.3/lib/application.js000066400000000000000000000336771420332637600167340ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var finalhandler = require('finalhandler'); var Router = require('./router'); var methods = require('methods'); var middleware = require('./middleware/init'); var query = require('./middleware/query'); var debug = require('debug')('express:application'); var View = require('./view'); var http = require('http'); var compileETag = require('./utils').compileETag; var compileQueryParser = require('./utils').compileQueryParser; var compileTrust = require('./utils').compileTrust; var deprecate = require('depd')('express'); var flatten = require('array-flatten'); var merge = require('utils-merge'); var resolve = require('path').resolve; var setPrototypeOf = require('setprototypeof') var slice = Array.prototype.slice; /** * Application prototype. */ var app = exports = module.exports = {}; /** * Variable for trust proxy inheritance back-compat * @private */ var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default'; /** * Initialize the server. * * - setup default configuration * - setup default middleware * - setup route reflection methods * * @private */ app.init = function init() { this.cache = {}; this.engines = {}; this.settings = {}; this.defaultConfiguration(); }; /** * Initialize application configuration. * @private */ app.defaultConfiguration = function defaultConfiguration() { var env = process.env.NODE_ENV || 'development'; // default settings this.enable('x-powered-by'); this.set('etag', 'weak'); this.set('env', env); this.set('query parser', 'extended'); this.set('subdomain offset', 2); this.set('trust proxy', false); // trust proxy inherit back-compat Object.defineProperty(this.settings, trustProxyDefaultSymbol, { configurable: true, value: true }); debug('booting in %s mode', env); this.on('mount', function onmount(parent) { // inherit trust proxy if (this.settings[trustProxyDefaultSymbol] === true && typeof parent.settings['trust proxy fn'] === 'function') { delete this.settings['trust proxy']; delete this.settings['trust proxy fn']; } // inherit protos setPrototypeOf(this.request, parent.request) setPrototypeOf(this.response, parent.response) setPrototypeOf(this.engines, parent.engines) setPrototypeOf(this.settings, parent.settings) }); // setup locals this.locals = Object.create(null); // top-most app is mounted at / this.mountpath = '/'; // default locals this.locals.settings = this.settings; // default configuration this.set('view', View); this.set('views', resolve('views')); this.set('jsonp callback name', 'callback'); if (env === 'production') { this.enable('view cache'); } Object.defineProperty(this, 'router', { get: function() { throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.'); } }); }; /** * lazily adds the base router if it has not yet been added. * * We cannot add the base router in the defaultConfiguration because * it reads app settings which might be set after that has run. * * @private */ app.lazyrouter = function lazyrouter() { if (!this._router) { this._router = new Router({ caseSensitive: this.enabled('case sensitive routing'), strict: this.enabled('strict routing') }); this._router.use(query(this.get('query parser fn'))); this._router.use(middleware.init(this)); } }; /** * Dispatch a req, res pair into the application. Starts pipeline processing. * * If no callback is provided, then default error handlers will respond * in the event of an error bubbling through the stack. * * @private */ app.handle = function handle(req, res, callback) { var router = this._router; // final handler var done = callback || finalhandler(req, res, { env: this.get('env'), onerror: logerror.bind(this) }); // no routes if (!router) { debug('no routes defined on app'); done(); return; } router.handle(req, res, done); }; /** * Proxy `Router#use()` to add middleware to the app router. * See Router#use() documentation for details. * * If the _fn_ parameter is an express app, then it will be * mounted at the _route_ specified. * * @public */ app.use = function use(fn) { var offset = 0; var path = '/'; // default path to '/' // disambiguate app.use([fn]) if (typeof fn !== 'function') { var arg = fn; while (Array.isArray(arg) && arg.length !== 0) { arg = arg[0]; } // first arg is the path if (typeof arg !== 'function') { offset = 1; path = fn; } } var fns = flatten(slice.call(arguments, offset)); if (fns.length === 0) { throw new TypeError('app.use() requires a middleware function') } // setup router this.lazyrouter(); var router = this._router; fns.forEach(function (fn) { // non-express app if (!fn || !fn.handle || !fn.set) { return router.use(path, fn); } debug('.use app under %s', path); fn.mountpath = path; fn.parent = this; // restore .app property on req and res router.use(path, function mounted_app(req, res, next) { var orig = req.app; fn.handle(req, res, function (err) { setPrototypeOf(req, orig.request) setPrototypeOf(res, orig.response) next(err); }); }); // mounted an app fn.emit('mount', this); }, this); return this; }; /** * Proxy to the app `Router#route()` * Returns a new `Route` instance for the _path_. * * Routes are isolated middleware stacks for specific paths. * See the Route api docs for details. * * @public */ app.route = function route(path) { this.lazyrouter(); return this._router.route(path); }; /** * Register the given template engine callback `fn` * as `ext`. * * By default will `require()` the engine based on the * file extension. For example if you try to render * a "foo.ejs" file Express will invoke the following internally: * * app.engine('ejs', require('ejs').__express); * * For engines that do not provide `.__express` out of the box, * or if you wish to "map" a different extension to the template engine * you may use this method. For example mapping the EJS template engine to * ".html" files: * * app.engine('html', require('ejs').renderFile); * * In this case EJS provides a `.renderFile()` method with * the same signature that Express expects: `(path, options, callback)`, * though note that it aliases this method as `ejs.__express` internally * so if you're using ".ejs" extensions you don't need to do anything. * * Some template engines do not follow this convention, the * [Consolidate.js](https://github.com/tj/consolidate.js) * library was created to map all of node's popular template * engines to follow this convention, thus allowing them to * work seamlessly within Express. * * @param {String} ext * @param {Function} fn * @return {app} for chaining * @public */ app.engine = function engine(ext, fn) { if (typeof fn !== 'function') { throw new Error('callback function required'); } // get file extension var extension = ext[0] !== '.' ? '.' + ext : ext; // store engine this.engines[extension] = fn; return this; }; /** * Proxy to `Router#param()` with one added api feature. The _name_ parameter * can be an array of names. * * See the Router#param() docs for more details. * * @param {String|Array} name * @param {Function} fn * @return {app} for chaining * @public */ app.param = function param(name, fn) { this.lazyrouter(); if (Array.isArray(name)) { for (var i = 0; i < name.length; i++) { this.param(name[i], fn); } return this; } this._router.param(name, fn); return this; }; /** * Assign `setting` to `val`, or return `setting`'s value. * * app.set('foo', 'bar'); * app.set('foo'); * // => "bar" * * Mounted servers inherit their parent server's settings. * * @param {String} setting * @param {*} [val] * @return {Server} for chaining * @public */ app.set = function set(setting, val) { if (arguments.length === 1) { // app.get(setting) return this.settings[setting]; } debug('set "%s" to %o', setting, val); // set value this.settings[setting] = val; // trigger matched settings switch (setting) { case 'etag': this.set('etag fn', compileETag(val)); break; case 'query parser': this.set('query parser fn', compileQueryParser(val)); break; case 'trust proxy': this.set('trust proxy fn', compileTrust(val)); // trust proxy inherit back-compat Object.defineProperty(this.settings, trustProxyDefaultSymbol, { configurable: true, value: false }); break; } return this; }; /** * Return the app's absolute pathname * based on the parent(s) that have * mounted it. * * For example if the application was * mounted as "/admin", which itself * was mounted as "/blog" then the * return value would be "/blog/admin". * * @return {String} * @private */ app.path = function path() { return this.parent ? this.parent.path() + this.mountpath : ''; }; /** * Check if `setting` is enabled (truthy). * * app.enabled('foo') * // => false * * app.enable('foo') * app.enabled('foo') * // => true * * @param {String} setting * @return {Boolean} * @public */ app.enabled = function enabled(setting) { return Boolean(this.set(setting)); }; /** * Check if `setting` is disabled. * * app.disabled('foo') * // => true * * app.enable('foo') * app.disabled('foo') * // => false * * @param {String} setting * @return {Boolean} * @public */ app.disabled = function disabled(setting) { return !this.set(setting); }; /** * Enable `setting`. * * @param {String} setting * @return {app} for chaining * @public */ app.enable = function enable(setting) { return this.set(setting, true); }; /** * Disable `setting`. * * @param {String} setting * @return {app} for chaining * @public */ app.disable = function disable(setting) { return this.set(setting, false); }; /** * Delegate `.VERB(...)` calls to `router.VERB(...)`. */ methods.forEach(function(method){ app[method] = function(path){ if (method === 'get' && arguments.length === 1) { // app.get(setting) return this.set(path); } this.lazyrouter(); var route = this._router.route(path); route[method].apply(route, slice.call(arguments, 1)); return this; }; }); /** * Special-cased "all" method, applying the given route `path`, * middleware, and callback to _every_ HTTP method. * * @param {String} path * @param {Function} ... * @return {app} for chaining * @public */ app.all = function all(path) { this.lazyrouter(); var route = this._router.route(path); var args = slice.call(arguments, 1); for (var i = 0; i < methods.length; i++) { route[methods[i]].apply(route, args); } return this; }; // del -> delete alias app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead'); /** * Render the given view `name` name with `options` * and a callback accepting an error and the * rendered template string. * * Example: * * app.render('email', { name: 'Tobi' }, function(err, html){ * // ... * }) * * @param {String} name * @param {Object|Function} options or fn * @param {Function} callback * @public */ app.render = function render(name, options, callback) { var cache = this.cache; var done = callback; var engines = this.engines; var opts = options; var renderOptions = {}; var view; // support callback function as second arg if (typeof options === 'function') { done = options; opts = {}; } // merge app.locals merge(renderOptions, this.locals); // merge options._locals if (opts._locals) { merge(renderOptions, opts._locals); } // merge options merge(renderOptions, opts); // set .cache unless explicitly provided if (renderOptions.cache == null) { renderOptions.cache = this.enabled('view cache'); } // primed cache if (renderOptions.cache) { view = cache[name]; } // view if (!view) { var View = this.get('view'); view = new View(name, { defaultEngine: this.get('view engine'), root: this.get('views'), engines: engines }); if (!view.path) { var dirs = Array.isArray(view.root) && view.root.length > 1 ? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"' : 'directory "' + view.root + '"' var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs); err.view = view; return done(err); } // prime the cache if (renderOptions.cache) { cache[name] = view; } } // render tryRender(view, renderOptions, done); }; /** * Listen for connections. * * A node `http.Server` is returned, with this * application (which is a `Function`) as its * callback. If you wish to create both an HTTP * and HTTPS server you may do so with the "http" * and "https" modules as shown here: * * var http = require('http') * , https = require('https') * , express = require('express') * , app = express(); * * http.createServer(app).listen(80); * https.createServer({ ... }, app).listen(443); * * @return {http.Server} * @public */ app.listen = function listen() { var server = http.createServer(this); return server.listen.apply(server, arguments); }; /** * Log error using console.error. * * @param {Error} err * @private */ function logerror(err) { /* istanbul ignore next */ if (this.get('env') !== 'test') console.error(err.stack || err.toString()); } /** * Try rendering a view. * @private */ function tryRender(view, options, callback) { try { view.render(options, callback); } catch (err) { callback(err); } } express-4.17.3/lib/express.js000066400000000000000000000045511420332637600161070ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. */ var bodyParser = require('body-parser') var EventEmitter = require('events').EventEmitter; var mixin = require('merge-descriptors'); var proto = require('./application'); var Route = require('./router/route'); var Router = require('./router'); var req = require('./request'); var res = require('./response'); /** * Expose `createApplication()`. */ exports = module.exports = createApplication; /** * Create an express application. * * @return {Function} * @api public */ function createApplication() { var app = function(req, res, next) { app.handle(req, res, next); }; mixin(app, EventEmitter.prototype, false); mixin(app, proto, false); // expose the prototype that will get set on requests app.request = Object.create(req, { app: { configurable: true, enumerable: true, writable: true, value: app } }) // expose the prototype that will get set on responses app.response = Object.create(res, { app: { configurable: true, enumerable: true, writable: true, value: app } }) app.init(); return app; } /** * Expose the prototypes. */ exports.application = proto; exports.request = req; exports.response = res; /** * Expose constructors. */ exports.Route = Route; exports.Router = Router; /** * Expose middleware */ exports.json = bodyParser.json exports.query = require('./middleware/query'); exports.raw = bodyParser.raw exports.static = require('serve-static'); exports.text = bodyParser.text exports.urlencoded = bodyParser.urlencoded /** * Replace removed middleware with an appropriate error message. */ var removedMiddlewares = [ 'bodyParser', 'compress', 'cookieSession', 'session', 'logger', 'cookieParser', 'favicon', 'responseTime', 'errorHandler', 'timeout', 'methodOverride', 'vhost', 'csrf', 'directory', 'limit', 'multipart', 'staticCache' ] removedMiddlewares.forEach(function (name) { Object.defineProperty(exports, name, { get: function () { throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.'); }, configurable: true }); }); express-4.17.3/lib/middleware/000077500000000000000000000000001420332637600161705ustar00rootroot00000000000000express-4.17.3/lib/middleware/init.js000066400000000000000000000015251420332637600174740ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var setPrototypeOf = require('setprototypeof') /** * Initialization middleware, exposing the * request and response to each other, as well * as defaulting the X-Powered-By header field. * * @param {Function} app * @return {Function} * @api private */ exports.init = function(app){ return function expressInit(req, res, next){ if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express'); req.res = res; res.req = req; req.next = next; setPrototypeOf(req, app.request) setPrototypeOf(res, app.response) res.locals = res.locals || Object.create(null); next(); }; }; express-4.17.3/lib/middleware/query.js000066400000000000000000000015651420332637600177020ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. */ var merge = require('utils-merge') var parseUrl = require('parseurl'); var qs = require('qs'); /** * @param {Object} options * @return {Function} * @api public */ module.exports = function query(options) { var opts = merge({}, options) var queryparse = qs.parse; if (typeof options === 'function') { queryparse = options; opts = undefined; } if (opts !== undefined && opts.allowPrototypes === undefined) { // back-compat for qs module opts.allowPrototypes = true; } return function query(req, res, next){ if (!req.query) { var val = parseUrl(req).query; req.query = queryparse(val, opts); } next(); }; }; express-4.17.3/lib/request.js000066400000000000000000000303311420332637600161010ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var accepts = require('accepts'); var deprecate = require('depd')('express'); var isIP = require('net').isIP; var typeis = require('type-is'); var http = require('http'); var fresh = require('fresh'); var parseRange = require('range-parser'); var parse = require('parseurl'); var proxyaddr = require('proxy-addr'); /** * Request prototype. * @public */ var req = Object.create(http.IncomingMessage.prototype) /** * Module exports. * @public */ module.exports = req /** * Return request header. * * The `Referrer` header field is special-cased, * both `Referrer` and `Referer` are interchangeable. * * Examples: * * req.get('Content-Type'); * // => "text/plain" * * req.get('content-type'); * // => "text/plain" * * req.get('Something'); * // => undefined * * Aliased as `req.header()`. * * @param {String} name * @return {String} * @public */ req.get = req.header = function header(name) { if (!name) { throw new TypeError('name argument is required to req.get'); } if (typeof name !== 'string') { throw new TypeError('name must be a string to req.get'); } var lc = name.toLowerCase(); switch (lc) { case 'referer': case 'referrer': return this.headers.referrer || this.headers.referer; default: return this.headers[lc]; } }; /** * To do: update docs. * * Check if the given `type(s)` is acceptable, returning * the best match when true, otherwise `undefined`, in which * case you should respond with 406 "Not Acceptable". * * The `type` value may be a single MIME type string * such as "application/json", an extension name * such as "json", a comma-delimited list such as "json, html, text/plain", * an argument list such as `"json", "html", "text/plain"`, * or an array `["json", "html", "text/plain"]`. When a list * or array is given, the _best_ match, if any is returned. * * Examples: * * // Accept: text/html * req.accepts('html'); * // => "html" * * // Accept: text/*, application/json * req.accepts('html'); * // => "html" * req.accepts('text/html'); * // => "text/html" * req.accepts('json, text'); * // => "json" * req.accepts('application/json'); * // => "application/json" * * // Accept: text/*, application/json * req.accepts('image/png'); * req.accepts('png'); * // => undefined * * // Accept: text/*;q=.5, application/json * req.accepts(['html', 'json']); * req.accepts('html', 'json'); * req.accepts('html, json'); * // => "json" * * @param {String|Array} type(s) * @return {String|Array|Boolean} * @public */ req.accepts = function(){ var accept = accepts(this); return accept.types.apply(accept, arguments); }; /** * Check if the given `encoding`s are accepted. * * @param {String} ...encoding * @return {String|Array} * @public */ req.acceptsEncodings = function(){ var accept = accepts(this); return accept.encodings.apply(accept, arguments); }; req.acceptsEncoding = deprecate.function(req.acceptsEncodings, 'req.acceptsEncoding: Use acceptsEncodings instead'); /** * Check if the given `charset`s are acceptable, * otherwise you should respond with 406 "Not Acceptable". * * @param {String} ...charset * @return {String|Array} * @public */ req.acceptsCharsets = function(){ var accept = accepts(this); return accept.charsets.apply(accept, arguments); }; req.acceptsCharset = deprecate.function(req.acceptsCharsets, 'req.acceptsCharset: Use acceptsCharsets instead'); /** * Check if the given `lang`s are acceptable, * otherwise you should respond with 406 "Not Acceptable". * * @param {String} ...lang * @return {String|Array} * @public */ req.acceptsLanguages = function(){ var accept = accepts(this); return accept.languages.apply(accept, arguments); }; req.acceptsLanguage = deprecate.function(req.acceptsLanguages, 'req.acceptsLanguage: Use acceptsLanguages instead'); /** * Parse Range header field, capping to the given `size`. * * Unspecified ranges such as "0-" require knowledge of your resource length. In * the case of a byte range this is of course the total number of bytes. If the * Range header field is not given `undefined` is returned, `-1` when unsatisfiable, * and `-2` when syntactically invalid. * * When ranges are returned, the array has a "type" property which is the type of * range that is required (most commonly, "bytes"). Each array element is an object * with a "start" and "end" property for the portion of the range. * * The "combine" option can be set to `true` and overlapping & adjacent ranges * will be combined into a single range. * * NOTE: remember that ranges are inclusive, so for example "Range: users=0-3" * should respond with 4 users when available, not 3. * * @param {number} size * @param {object} [options] * @param {boolean} [options.combine=false] * @return {number|array} * @public */ req.range = function range(size, options) { var range = this.get('Range'); if (!range) return; return parseRange(size, range, options); }; /** * Return the value of param `name` when present or `defaultValue`. * * - Checks route placeholders, ex: _/user/:id_ * - Checks body params, ex: id=12, {"id":12} * - Checks query string params, ex: ?id=12 * * To utilize request bodies, `req.body` * should be an object. This can be done by using * the `bodyParser()` middleware. * * @param {String} name * @param {Mixed} [defaultValue] * @return {String} * @public */ req.param = function param(name, defaultValue) { var params = this.params || {}; var body = this.body || {}; var query = this.query || {}; var args = arguments.length === 1 ? 'name' : 'name, default'; deprecate('req.param(' + args + '): Use req.params, req.body, or req.query instead'); if (null != params[name] && params.hasOwnProperty(name)) return params[name]; if (null != body[name]) return body[name]; if (null != query[name]) return query[name]; return defaultValue; }; /** * Check if the incoming request contains the "Content-Type" * header field, and it contains the given mime `type`. * * Examples: * * // With Content-Type: text/html; charset=utf-8 * req.is('html'); * req.is('text/html'); * req.is('text/*'); * // => true * * // When Content-Type is application/json * req.is('json'); * req.is('application/json'); * req.is('application/*'); * // => true * * req.is('html'); * // => false * * @param {String|Array} types... * @return {String|false|null} * @public */ req.is = function is(types) { var arr = types; // support flattened arguments if (!Array.isArray(types)) { arr = new Array(arguments.length); for (var i = 0; i < arr.length; i++) { arr[i] = arguments[i]; } } return typeis(this, arr); }; /** * Return the protocol string "http" or "https" * when requested with TLS. When the "trust proxy" * setting trusts the socket address, the * "X-Forwarded-Proto" header field will be trusted * and used if present. * * If you're running behind a reverse proxy that * supplies https for you this may be enabled. * * @return {String} * @public */ defineGetter(req, 'protocol', function protocol(){ var proto = this.connection.encrypted ? 'https' : 'http'; var trust = this.app.get('trust proxy fn'); if (!trust(this.connection.remoteAddress, 0)) { return proto; } // Note: X-Forwarded-Proto is normally only ever a // single value, but this is to be safe. var header = this.get('X-Forwarded-Proto') || proto var index = header.indexOf(',') return index !== -1 ? header.substring(0, index).trim() : header.trim() }); /** * Short-hand for: * * req.protocol === 'https' * * @return {Boolean} * @public */ defineGetter(req, 'secure', function secure(){ return this.protocol === 'https'; }); /** * Return the remote address from the trusted proxy. * * The is the remote address on the socket unless * "trust proxy" is set. * * @return {String} * @public */ defineGetter(req, 'ip', function ip(){ var trust = this.app.get('trust proxy fn'); return proxyaddr(this, trust); }); /** * When "trust proxy" is set, trusted proxy addresses + client. * * For example if the value were "client, proxy1, proxy2" * you would receive the array `["client", "proxy1", "proxy2"]` * where "proxy2" is the furthest down-stream and "proxy1" and * "proxy2" were trusted. * * @return {Array} * @public */ defineGetter(req, 'ips', function ips() { var trust = this.app.get('trust proxy fn'); var addrs = proxyaddr.all(this, trust); // reverse the order (to farthest -> closest) // and remove socket address addrs.reverse().pop() return addrs }); /** * Return subdomains as an array. * * Subdomains are the dot-separated parts of the host before the main domain of * the app. By default, the domain of the app is assumed to be the last two * parts of the host. This can be changed by setting "subdomain offset". * * For example, if the domain is "tobi.ferrets.example.com": * If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`. * If "subdomain offset" is 3, req.subdomains is `["tobi"]`. * * @return {Array} * @public */ defineGetter(req, 'subdomains', function subdomains() { var hostname = this.hostname; if (!hostname) return []; var offset = this.app.get('subdomain offset'); var subdomains = !isIP(hostname) ? hostname.split('.').reverse() : [hostname]; return subdomains.slice(offset); }); /** * Short-hand for `url.parse(req.url).pathname`. * * @return {String} * @public */ defineGetter(req, 'path', function path() { return parse(this).pathname; }); /** * Parse the "Host" header field to a hostname. * * When the "trust proxy" setting trusts the socket * address, the "X-Forwarded-Host" header field will * be trusted. * * @return {String} * @public */ defineGetter(req, 'hostname', function hostname(){ var trust = this.app.get('trust proxy fn'); var host = this.get('X-Forwarded-Host'); if (!host || !trust(this.connection.remoteAddress, 0)) { host = this.get('Host'); } else if (host.indexOf(',') !== -1) { // Note: X-Forwarded-Host is normally only ever a // single value, but this is to be safe. host = host.substring(0, host.indexOf(',')).trimRight() } if (!host) return; // IPv6 literal support var offset = host[0] === '[' ? host.indexOf(']') + 1 : 0; var index = host.indexOf(':', offset); return index !== -1 ? host.substring(0, index) : host; }); // TODO: change req.host to return host in next major defineGetter(req, 'host', deprecate.function(function host(){ return this.hostname; }, 'req.host: Use req.hostname instead')); /** * Check if the request is fresh, aka * Last-Modified and/or the ETag * still match. * * @return {Boolean} * @public */ defineGetter(req, 'fresh', function(){ var method = this.method; var res = this.res var status = res.statusCode // GET or HEAD for weak freshness validation only if ('GET' !== method && 'HEAD' !== method) return false; // 2xx or 304 as per rfc2616 14.26 if ((status >= 200 && status < 300) || 304 === status) { return fresh(this.headers, { 'etag': res.get('ETag'), 'last-modified': res.get('Last-Modified') }) } return false; }); /** * Check if the request is stale, aka * "Last-Modified" and / or the "ETag" for the * resource has changed. * * @return {Boolean} * @public */ defineGetter(req, 'stale', function stale(){ return !this.fresh; }); /** * Check if the request was an _XMLHttpRequest_. * * @return {Boolean} * @public */ defineGetter(req, 'xhr', function xhr(){ var val = this.get('X-Requested-With') || ''; return val.toLowerCase() === 'xmlhttprequest'; }); /** * Helper function for creating a getter on an object. * * @param {Object} obj * @param {String} name * @param {Function} getter * @private */ function defineGetter(obj, name, getter) { Object.defineProperty(obj, name, { configurable: true, enumerable: true, get: getter }); } express-4.17.3/lib/response.js000066400000000000000000000652271420332637600162630ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var Buffer = require('safe-buffer').Buffer var contentDisposition = require('content-disposition'); var deprecate = require('depd')('express'); var encodeUrl = require('encodeurl'); var escapeHtml = require('escape-html'); var http = require('http'); var isAbsolute = require('./utils').isAbsolute; var onFinished = require('on-finished'); var path = require('path'); var statuses = require('statuses') var merge = require('utils-merge'); var sign = require('cookie-signature').sign; var normalizeType = require('./utils').normalizeType; var normalizeTypes = require('./utils').normalizeTypes; var setCharset = require('./utils').setCharset; var cookie = require('cookie'); var send = require('send'); var extname = path.extname; var mime = send.mime; var resolve = path.resolve; var vary = require('vary'); /** * Response prototype. * @public */ var res = Object.create(http.ServerResponse.prototype) /** * Module exports. * @public */ module.exports = res /** * Module variables. * @private */ var charsetRegExp = /;\s*charset\s*=/; /** * Set status `code`. * * @param {Number} code * @return {ServerResponse} * @public */ res.status = function status(code) { this.statusCode = code; return this; }; /** * Set Link header field with the given `links`. * * Examples: * * res.links({ * next: 'http://api.example.com/users?page=2', * last: 'http://api.example.com/users?page=5' * }); * * @param {Object} links * @return {ServerResponse} * @public */ res.links = function(links){ var link = this.get('Link') || ''; if (link) link += ', '; return this.set('Link', link + Object.keys(links).map(function(rel){ return '<' + links[rel] + '>; rel="' + rel + '"'; }).join(', ')); }; /** * Send a response. * * Examples: * * res.send(Buffer.from('wahoo')); * res.send({ some: 'json' }); * res.send('

    some html

    '); * * @param {string|number|boolean|object|Buffer} body * @public */ res.send = function send(body) { var chunk = body; var encoding; var req = this.req; var type; // settings var app = this.app; // allow status / body if (arguments.length === 2) { // res.send(body, status) backwards compat if (typeof arguments[0] !== 'number' && typeof arguments[1] === 'number') { deprecate('res.send(body, status): Use res.status(status).send(body) instead'); this.statusCode = arguments[1]; } else { deprecate('res.send(status, body): Use res.status(status).send(body) instead'); this.statusCode = arguments[0]; chunk = arguments[1]; } } // disambiguate res.send(status) and res.send(status, num) if (typeof chunk === 'number' && arguments.length === 1) { // res.send(status) will set status message as text string if (!this.get('Content-Type')) { this.type('txt'); } deprecate('res.send(status): Use res.sendStatus(status) instead'); this.statusCode = chunk; chunk = statuses[chunk] } switch (typeof chunk) { // string defaulting to html case 'string': if (!this.get('Content-Type')) { this.type('html'); } break; case 'boolean': case 'number': case 'object': if (chunk === null) { chunk = ''; } else if (Buffer.isBuffer(chunk)) { if (!this.get('Content-Type')) { this.type('bin'); } } else { return this.json(chunk); } break; } // write strings in utf-8 if (typeof chunk === 'string') { encoding = 'utf8'; type = this.get('Content-Type'); // reflect this in content-type if (typeof type === 'string') { this.set('Content-Type', setCharset(type, 'utf-8')); } } // determine if ETag should be generated var etagFn = app.get('etag fn') var generateETag = !this.get('ETag') && typeof etagFn === 'function' // populate Content-Length var len if (chunk !== undefined) { if (Buffer.isBuffer(chunk)) { // get length of Buffer len = chunk.length } else if (!generateETag && chunk.length < 1000) { // just calculate length when no ETag + small chunk len = Buffer.byteLength(chunk, encoding) } else { // convert chunk to Buffer and calculate chunk = Buffer.from(chunk, encoding) encoding = undefined; len = chunk.length } this.set('Content-Length', len); } // populate ETag var etag; if (generateETag && len !== undefined) { if ((etag = etagFn(chunk, encoding))) { this.set('ETag', etag); } } // freshness if (req.fresh) this.statusCode = 304; // strip irrelevant headers if (204 === this.statusCode || 304 === this.statusCode) { this.removeHeader('Content-Type'); this.removeHeader('Content-Length'); this.removeHeader('Transfer-Encoding'); chunk = ''; } if (req.method === 'HEAD') { // skip body for HEAD this.end(); } else { // respond this.end(chunk, encoding); } return this; }; /** * Send JSON response. * * Examples: * * res.json(null); * res.json({ user: 'tj' }); * * @param {string|number|boolean|object} obj * @public */ res.json = function json(obj) { var val = obj; // allow status / body if (arguments.length === 2) { // res.json(body, status) backwards compat if (typeof arguments[1] === 'number') { deprecate('res.json(obj, status): Use res.status(status).json(obj) instead'); this.statusCode = arguments[1]; } else { deprecate('res.json(status, obj): Use res.status(status).json(obj) instead'); this.statusCode = arguments[0]; val = arguments[1]; } } // settings var app = this.app; var escape = app.get('json escape') var replacer = app.get('json replacer'); var spaces = app.get('json spaces'); var body = stringify(val, replacer, spaces, escape) // content-type if (!this.get('Content-Type')) { this.set('Content-Type', 'application/json'); } return this.send(body); }; /** * Send JSON response with JSONP callback support. * * Examples: * * res.jsonp(null); * res.jsonp({ user: 'tj' }); * * @param {string|number|boolean|object} obj * @public */ res.jsonp = function jsonp(obj) { var val = obj; // allow status / body if (arguments.length === 2) { // res.jsonp(body, status) backwards compat if (typeof arguments[1] === 'number') { deprecate('res.jsonp(obj, status): Use res.status(status).jsonp(obj) instead'); this.statusCode = arguments[1]; } else { deprecate('res.jsonp(status, obj): Use res.status(status).jsonp(obj) instead'); this.statusCode = arguments[0]; val = arguments[1]; } } // settings var app = this.app; var escape = app.get('json escape') var replacer = app.get('json replacer'); var spaces = app.get('json spaces'); var body = stringify(val, replacer, spaces, escape) var callback = this.req.query[app.get('jsonp callback name')]; // content-type if (!this.get('Content-Type')) { this.set('X-Content-Type-Options', 'nosniff'); this.set('Content-Type', 'application/json'); } // fixup callback if (Array.isArray(callback)) { callback = callback[0]; } // jsonp if (typeof callback === 'string' && callback.length !== 0) { this.set('X-Content-Type-Options', 'nosniff'); this.set('Content-Type', 'text/javascript'); // restrict callback charset callback = callback.replace(/[^\[\]\w$.]/g, ''); if (body === undefined) { // empty argument body = '' } else if (typeof body === 'string') { // replace chars not allowed in JavaScript that are in JSON body = body .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029') } // the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse" // the typeof check is just to reduce client error noise body = '/**/ typeof ' + callback + ' === \'function\' && ' + callback + '(' + body + ');'; } return this.send(body); }; /** * Send given HTTP status code. * * Sets the response status to `statusCode` and the body of the * response to the standard description from node's http.STATUS_CODES * or the statusCode number if no description. * * Examples: * * res.sendStatus(200); * * @param {number} statusCode * @public */ res.sendStatus = function sendStatus(statusCode) { var body = statuses[statusCode] || String(statusCode) this.statusCode = statusCode; this.type('txt'); return this.send(body); }; /** * Transfer the file at the given `path`. * * Automatically sets the _Content-Type_ response header field. * The callback `callback(err)` is invoked when the transfer is complete * or when an error occurs. Be sure to check `res.headersSent` * if you wish to attempt responding, as the header and some data * may have already been transferred. * * Options: * * - `maxAge` defaulting to 0 (can be string converted by `ms`) * - `root` root directory for relative filenames * - `headers` object of headers to serve with file * - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them * * Other options are passed along to `send`. * * Examples: * * The following example illustrates how `res.sendFile()` may * be used as an alternative for the `static()` middleware for * dynamic situations. The code backing `res.sendFile()` is actually * the same code, so HTTP cache support etc is identical. * * app.get('/user/:uid/photos/:file', function(req, res){ * var uid = req.params.uid * , file = req.params.file; * * req.user.mayViewFilesFrom(uid, function(yes){ * if (yes) { * res.sendFile('/uploads/' + uid + '/' + file); * } else { * res.send(403, 'Sorry! you cant see that.'); * } * }); * }); * * @public */ res.sendFile = function sendFile(path, options, callback) { var done = callback; var req = this.req; var res = this; var next = req.next; var opts = options || {}; if (!path) { throw new TypeError('path argument is required to res.sendFile'); } if (typeof path !== 'string') { throw new TypeError('path must be a string to res.sendFile') } // support function as second arg if (typeof options === 'function') { done = options; opts = {}; } if (!opts.root && !isAbsolute(path)) { throw new TypeError('path must be absolute or specify root to res.sendFile'); } // create file stream var pathname = encodeURI(path); var file = send(req, pathname, opts); // transfer sendfile(res, file, opts, function (err) { if (done) return done(err); if (err && err.code === 'EISDIR') return next(); // next() all but write errors if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') { next(err); } }); }; /** * Transfer the file at the given `path`. * * Automatically sets the _Content-Type_ response header field. * The callback `callback(err)` is invoked when the transfer is complete * or when an error occurs. Be sure to check `res.headersSent` * if you wish to attempt responding, as the header and some data * may have already been transferred. * * Options: * * - `maxAge` defaulting to 0 (can be string converted by `ms`) * - `root` root directory for relative filenames * - `headers` object of headers to serve with file * - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them * * Other options are passed along to `send`. * * Examples: * * The following example illustrates how `res.sendfile()` may * be used as an alternative for the `static()` middleware for * dynamic situations. The code backing `res.sendfile()` is actually * the same code, so HTTP cache support etc is identical. * * app.get('/user/:uid/photos/:file', function(req, res){ * var uid = req.params.uid * , file = req.params.file; * * req.user.mayViewFilesFrom(uid, function(yes){ * if (yes) { * res.sendfile('/uploads/' + uid + '/' + file); * } else { * res.send(403, 'Sorry! you cant see that.'); * } * }); * }); * * @public */ res.sendfile = function (path, options, callback) { var done = callback; var req = this.req; var res = this; var next = req.next; var opts = options || {}; // support function as second arg if (typeof options === 'function') { done = options; opts = {}; } // create file stream var file = send(req, path, opts); // transfer sendfile(res, file, opts, function (err) { if (done) return done(err); if (err && err.code === 'EISDIR') return next(); // next() all but write errors if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') { next(err); } }); }; res.sendfile = deprecate.function(res.sendfile, 'res.sendfile: Use res.sendFile instead'); /** * Transfer the file at the given `path` as an attachment. * * Optionally providing an alternate attachment `filename`, * and optional callback `callback(err)`. The callback is invoked * when the data transfer is complete, or when an error has * occurred. Be sure to check `res.headersSent` if you plan to respond. * * Optionally providing an `options` object to use with `res.sendFile()`. * This function will set the `Content-Disposition` header, overriding * any `Content-Disposition` header passed as header options in order * to set the attachment and filename. * * This method uses `res.sendFile()`. * * @public */ res.download = function download (path, filename, options, callback) { var done = callback; var name = filename; var opts = options || null // support function as second or third arg if (typeof filename === 'function') { done = filename; name = null; opts = null } else if (typeof options === 'function') { done = options opts = null } // set Content-Disposition when file is sent var headers = { 'Content-Disposition': contentDisposition(name || path) }; // merge user-provided headers if (opts && opts.headers) { var keys = Object.keys(opts.headers) for (var i = 0; i < keys.length; i++) { var key = keys[i] if (key.toLowerCase() !== 'content-disposition') { headers[key] = opts.headers[key] } } } // merge user-provided options opts = Object.create(opts) opts.headers = headers // Resolve the full path for sendFile var fullPath = resolve(path); // send file return this.sendFile(fullPath, opts, done) }; /** * Set _Content-Type_ response header with `type` through `mime.lookup()` * when it does not contain "/", or set the Content-Type to `type` otherwise. * * Examples: * * res.type('.html'); * res.type('html'); * res.type('json'); * res.type('application/json'); * res.type('png'); * * @param {String} type * @return {ServerResponse} for chaining * @public */ res.contentType = res.type = function contentType(type) { var ct = type.indexOf('/') === -1 ? mime.lookup(type) : type; return this.set('Content-Type', ct); }; /** * Respond to the Acceptable formats using an `obj` * of mime-type callbacks. * * This method uses `req.accepted`, an array of * acceptable types ordered by their quality values. * When "Accept" is not present the _first_ callback * is invoked, otherwise the first match is used. When * no match is performed the server responds with * 406 "Not Acceptable". * * Content-Type is set for you, however if you choose * you may alter this within the callback using `res.type()` * or `res.set('Content-Type', ...)`. * * res.format({ * 'text/plain': function(){ * res.send('hey'); * }, * * 'text/html': function(){ * res.send('

    hey

    '); * }, * * 'application/json': function () { * res.send({ message: 'hey' }); * } * }); * * In addition to canonicalized MIME types you may * also use extnames mapped to these types: * * res.format({ * text: function(){ * res.send('hey'); * }, * * html: function(){ * res.send('

    hey

    '); * }, * * json: function(){ * res.send({ message: 'hey' }); * } * }); * * By default Express passes an `Error` * with a `.status` of 406 to `next(err)` * if a match is not made. If you provide * a `.default` callback it will be invoked * instead. * * @param {Object} obj * @return {ServerResponse} for chaining * @public */ res.format = function(obj){ var req = this.req; var next = req.next; var fn = obj.default; if (fn) delete obj.default; var keys = Object.keys(obj); var key = keys.length > 0 ? req.accepts(keys) : false; this.vary("Accept"); if (key) { this.set('Content-Type', normalizeType(key).value); obj[key](req, this, next); } else if (fn) { fn(); } else { var err = new Error('Not Acceptable'); err.status = err.statusCode = 406; err.types = normalizeTypes(keys).map(function(o){ return o.value }); next(err); } return this; }; /** * Set _Content-Disposition_ header to _attachment_ with optional `filename`. * * @param {String} filename * @return {ServerResponse} * @public */ res.attachment = function attachment(filename) { if (filename) { this.type(extname(filename)); } this.set('Content-Disposition', contentDisposition(filename)); return this; }; /** * Append additional header `field` with value `val`. * * Example: * * res.append('Link', ['', '']); * res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); * res.append('Warning', '199 Miscellaneous warning'); * * @param {String} field * @param {String|Array} val * @return {ServerResponse} for chaining * @public */ res.append = function append(field, val) { var prev = this.get(field); var value = val; if (prev) { // concat the new and prev vals value = Array.isArray(prev) ? prev.concat(val) : Array.isArray(val) ? [prev].concat(val) : [prev, val] } return this.set(field, value); }; /** * Set header `field` to `val`, or pass * an object of header fields. * * Examples: * * res.set('Foo', ['bar', 'baz']); * res.set('Accept', 'application/json'); * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); * * Aliased as `res.header()`. * * @param {String|Object} field * @param {String|Array} val * @return {ServerResponse} for chaining * @public */ res.set = res.header = function header(field, val) { if (arguments.length === 2) { var value = Array.isArray(val) ? val.map(String) : String(val); // add charset to content-type if (field.toLowerCase() === 'content-type') { if (Array.isArray(value)) { throw new TypeError('Content-Type cannot be set to an Array'); } if (!charsetRegExp.test(value)) { var charset = mime.charsets.lookup(value.split(';')[0]); if (charset) value += '; charset=' + charset.toLowerCase(); } } this.setHeader(field, value); } else { for (var key in field) { this.set(key, field[key]); } } return this; }; /** * Get value for header `field`. * * @param {String} field * @return {String} * @public */ res.get = function(field){ return this.getHeader(field); }; /** * Clear cookie `name`. * * @param {String} name * @param {Object} [options] * @return {ServerResponse} for chaining * @public */ res.clearCookie = function clearCookie(name, options) { var opts = merge({ expires: new Date(1), path: '/' }, options); return this.cookie(name, '', opts); }; /** * Set cookie `name` to `value`, with the given `options`. * * Options: * * - `maxAge` max-age in milliseconds, converted to `expires` * - `signed` sign the cookie * - `path` defaults to "/" * * Examples: * * // "Remember Me" for 15 minutes * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); * * // same as above * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) * * @param {String} name * @param {String|Object} value * @param {Object} [options] * @return {ServerResponse} for chaining * @public */ res.cookie = function (name, value, options) { var opts = merge({}, options); var secret = this.req.secret; var signed = opts.signed; if (signed && !secret) { throw new Error('cookieParser("secret") required for signed cookies'); } var val = typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value); if (signed) { val = 's:' + sign(val, secret); } if ('maxAge' in opts) { opts.expires = new Date(Date.now() + opts.maxAge); opts.maxAge /= 1000; } if (opts.path == null) { opts.path = '/'; } this.append('Set-Cookie', cookie.serialize(name, String(val), opts)); return this; }; /** * Set the location header to `url`. * * The given `url` can also be "back", which redirects * to the _Referrer_ or _Referer_ headers or "/". * * Examples: * * res.location('/foo/bar').; * res.location('http://example.com'); * res.location('../login'); * * @param {String} url * @return {ServerResponse} for chaining * @public */ res.location = function location(url) { var loc = url; // "back" is an alias for the referrer if (url === 'back') { loc = this.req.get('Referrer') || '/'; } // set location return this.set('Location', encodeUrl(loc)); }; /** * Redirect to the given `url` with optional response `status` * defaulting to 302. * * The resulting `url` is determined by `res.location()`, so * it will play nicely with mounted apps, relative paths, * `"back"` etc. * * Examples: * * res.redirect('/foo/bar'); * res.redirect('http://example.com'); * res.redirect(301, 'http://example.com'); * res.redirect('../login'); // /blog/post/1 -> /blog/login * * @public */ res.redirect = function redirect(url) { var address = url; var body; var status = 302; // allow status / url if (arguments.length === 2) { if (typeof arguments[0] === 'number') { status = arguments[0]; address = arguments[1]; } else { deprecate('res.redirect(url, status): Use res.redirect(status, url) instead'); status = arguments[1]; } } // Set location header address = this.location(address).get('Location'); // Support text/{plain,html} by default this.format({ text: function(){ body = statuses[status] + '. Redirecting to ' + address }, html: function(){ var u = escapeHtml(address); body = '

    ' + statuses[status] + '. Redirecting to ' + u + '

    ' }, default: function(){ body = ''; } }); // Respond this.statusCode = status; this.set('Content-Length', Buffer.byteLength(body)); if (this.req.method === 'HEAD') { this.end(); } else { this.end(body); } }; /** * Add `field` to Vary. If already present in the Vary set, then * this call is simply ignored. * * @param {Array|String} field * @return {ServerResponse} for chaining * @public */ res.vary = function(field){ // checks for back-compat if (!field || (Array.isArray(field) && !field.length)) { deprecate('res.vary(): Provide a field name'); return this; } vary(this, field); return this; }; /** * Render `view` with the given `options` and optional callback `fn`. * When a callback function is given a response will _not_ be made * automatically, otherwise a response of _200_ and _text/html_ is given. * * Options: * * - `cache` boolean hinting to the engine it should cache * - `filename` filename of the view being rendered * * @public */ res.render = function render(view, options, callback) { var app = this.req.app; var done = callback; var opts = options || {}; var req = this.req; var self = this; // support callback function as second arg if (typeof options === 'function') { done = options; opts = {}; } // merge res.locals opts._locals = self.locals; // default callback to respond done = done || function (err, str) { if (err) return req.next(err); self.send(str); }; // render app.render(view, opts, done); }; // pipe the send file stream function sendfile(res, file, options, callback) { var done = false; var streaming; // request aborted function onaborted() { if (done) return; done = true; var err = new Error('Request aborted'); err.code = 'ECONNABORTED'; callback(err); } // directory function ondirectory() { if (done) return; done = true; var err = new Error('EISDIR, read'); err.code = 'EISDIR'; callback(err); } // errors function onerror(err) { if (done) return; done = true; callback(err); } // ended function onend() { if (done) return; done = true; callback(); } // file function onfile() { streaming = false; } // finished function onfinish(err) { if (err && err.code === 'ECONNRESET') return onaborted(); if (err) return onerror(err); if (done) return; setImmediate(function () { if (streaming !== false && !done) { onaborted(); return; } if (done) return; done = true; callback(); }); } // streaming function onstream() { streaming = true; } file.on('directory', ondirectory); file.on('end', onend); file.on('error', onerror); file.on('file', onfile); file.on('stream', onstream); onFinished(res, onfinish); if (options.headers) { // set headers on successful transfer file.on('headers', function headers(res) { var obj = options.headers; var keys = Object.keys(obj); for (var i = 0; i < keys.length; i++) { var k = keys[i]; res.setHeader(k, obj[k]); } }); } // pipe file.pipe(res); } /** * Stringify JSON, like JSON.stringify, but v8 optimized, with the * ability to escape characters that can trigger HTML sniffing. * * @param {*} value * @param {function} replaces * @param {number} spaces * @param {boolean} escape * @returns {string} * @private */ function stringify (value, replacer, spaces, escape) { // v8 checks arguments.length for optimizing simple call // https://bugs.chromium.org/p/v8/issues/detail?id=4730 var json = replacer || spaces ? JSON.stringify(value, replacer, spaces) : JSON.stringify(value); if (escape && typeof json === 'string') { json = json.replace(/[<>&]/g, function (c) { switch (c.charCodeAt(0)) { case 0x3c: return '\\u003c' case 0x3e: return '\\u003e' case 0x26: return '\\u0026' /* istanbul ignore next: unreachable default */ default: return c } }) } return json } express-4.17.3/lib/router/000077500000000000000000000000001420332637600153735ustar00rootroot00000000000000express-4.17.3/lib/router/index.js000066400000000000000000000352711420332637600170500ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var Route = require('./route'); var Layer = require('./layer'); var methods = require('methods'); var mixin = require('utils-merge'); var debug = require('debug')('express:router'); var deprecate = require('depd')('express'); var flatten = require('array-flatten'); var parseUrl = require('parseurl'); var setPrototypeOf = require('setprototypeof') /** * Module variables. * @private */ var objectRegExp = /^\[object (\S+)\]$/; var slice = Array.prototype.slice; var toString = Object.prototype.toString; /** * Initialize a new `Router` with the given `options`. * * @param {Object} [options] * @return {Router} which is an callable function * @public */ var proto = module.exports = function(options) { var opts = options || {}; function router(req, res, next) { router.handle(req, res, next); } // mixin Router class functions setPrototypeOf(router, proto) router.params = {}; router._params = []; router.caseSensitive = opts.caseSensitive; router.mergeParams = opts.mergeParams; router.strict = opts.strict; router.stack = []; return router; }; /** * Map the given param placeholder `name`(s) to the given callback. * * Parameter mapping is used to provide pre-conditions to routes * which use normalized placeholders. For example a _:user_id_ parameter * could automatically load a user's information from the database without * any additional code, * * The callback uses the same signature as middleware, the only difference * being that the value of the placeholder is passed, in this case the _id_ * of the user. Once the `next()` function is invoked, just like middleware * it will continue on to execute the route, or subsequent parameter functions. * * Just like in middleware, you must either respond to the request or call next * to avoid stalling the request. * * app.param('user_id', function(req, res, next, id){ * User.find(id, function(err, user){ * if (err) { * return next(err); * } else if (!user) { * return next(new Error('failed to load user')); * } * req.user = user; * next(); * }); * }); * * @param {String} name * @param {Function} fn * @return {app} for chaining * @public */ proto.param = function param(name, fn) { // param logic if (typeof name === 'function') { deprecate('router.param(fn): Refactor to use path params'); this._params.push(name); return; } // apply param functions var params = this._params; var len = params.length; var ret; if (name[0] === ':') { deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead'); name = name.substr(1); } for (var i = 0; i < len; ++i) { if (ret = params[i](name, fn)) { fn = ret; } } // ensure we end up with a // middleware function if ('function' !== typeof fn) { throw new Error('invalid param() call for ' + name + ', got ' + fn); } (this.params[name] = this.params[name] || []).push(fn); return this; }; /** * Dispatch a req, res into the router. * @private */ proto.handle = function handle(req, res, out) { var self = this; debug('dispatching %s %s', req.method, req.url); var idx = 0; var protohost = getProtohost(req.url) || '' var removed = ''; var slashAdded = false; var paramcalled = {}; // store options for OPTIONS request // only used if OPTIONS request var options = []; // middleware and routes var stack = self.stack; // manage inter-router variables var parentParams = req.params; var parentUrl = req.baseUrl || ''; var done = restore(out, req, 'baseUrl', 'next', 'params'); // setup next layer req.next = next; // for options requests, respond with a default if nothing else responds if (req.method === 'OPTIONS') { done = wrap(done, function(old, err) { if (err || options.length === 0) return old(err); sendOptionsResponse(res, options, old); }); } // setup basic req values req.baseUrl = parentUrl; req.originalUrl = req.originalUrl || req.url; next(); function next(err) { var layerError = err === 'route' ? null : err; // remove added slash if (slashAdded) { req.url = req.url.substr(1); slashAdded = false; } // restore altered req.url if (removed.length !== 0) { req.baseUrl = parentUrl; req.url = protohost + removed + req.url.substr(protohost.length); removed = ''; } // signal to exit router if (layerError === 'router') { setImmediate(done, null) return } // no more matching layers if (idx >= stack.length) { setImmediate(done, layerError); return; } // get pathname of request var path = getPathname(req); if (path == null) { return done(layerError); } // find next matching layer var layer; var match; var route; while (match !== true && idx < stack.length) { layer = stack[idx++]; match = matchLayer(layer, path); route = layer.route; if (typeof match !== 'boolean') { // hold on to layerError layerError = layerError || match; } if (match !== true) { continue; } if (!route) { // process non-route handlers normally continue; } if (layerError) { // routes do not match with a pending error match = false; continue; } var method = req.method; var has_method = route._handles_method(method); // build up automatic options response if (!has_method && method === 'OPTIONS') { appendMethods(options, route._options()); } // don't even bother matching route if (!has_method && method !== 'HEAD') { match = false; continue; } } // no match if (match !== true) { return done(layerError); } // store route for dispatch on change if (route) { req.route = route; } // Capture one-time layer values req.params = self.mergeParams ? mergeParams(layer.params, parentParams) : layer.params; var layerPath = layer.path; // this should be done for the layer self.process_params(layer, paramcalled, req, res, function (err) { if (err) { return next(layerError || err); } if (route) { return layer.handle_request(req, res, next); } trim_prefix(layer, layerError, layerPath, path); }); } function trim_prefix(layer, layerError, layerPath, path) { if (layerPath.length !== 0) { // Validate path is a prefix match if (layerPath !== path.substr(0, layerPath.length)) { next(layerError) return } // Validate path breaks on a path separator var c = path[layerPath.length] if (c && c !== '/' && c !== '.') return next(layerError) // Trim off the part of the url that matches the route // middleware (.use stuff) needs to have the path stripped debug('trim prefix (%s) from url %s', layerPath, req.url); removed = layerPath; req.url = protohost + req.url.substr(protohost.length + removed.length); // Ensure leading slash if (!protohost && req.url[0] !== '/') { req.url = '/' + req.url; slashAdded = true; } // Setup base URL (no trailing slash) req.baseUrl = parentUrl + (removed[removed.length - 1] === '/' ? removed.substring(0, removed.length - 1) : removed); } debug('%s %s : %s', layer.name, layerPath, req.originalUrl); if (layerError) { layer.handle_error(layerError, req, res, next); } else { layer.handle_request(req, res, next); } } }; /** * Process any parameters for the layer. * @private */ proto.process_params = function process_params(layer, called, req, res, done) { var params = this.params; // captured parameters from the layer, keys and values var keys = layer.keys; // fast track if (!keys || keys.length === 0) { return done(); } var i = 0; var name; var paramIndex = 0; var key; var paramVal; var paramCallbacks; var paramCalled; // process params in order // param callbacks can be async function param(err) { if (err) { return done(err); } if (i >= keys.length ) { return done(); } paramIndex = 0; key = keys[i++]; name = key.name; paramVal = req.params[name]; paramCallbacks = params[name]; paramCalled = called[name]; if (paramVal === undefined || !paramCallbacks) { return param(); } // param previously called with same value or error occurred if (paramCalled && (paramCalled.match === paramVal || (paramCalled.error && paramCalled.error !== 'route'))) { // restore value req.params[name] = paramCalled.value; // next param return param(paramCalled.error); } called[name] = paramCalled = { error: null, match: paramVal, value: paramVal }; paramCallback(); } // single param callbacks function paramCallback(err) { var fn = paramCallbacks[paramIndex++]; // store updated value paramCalled.value = req.params[key.name]; if (err) { // store error paramCalled.error = err; param(err); return; } if (!fn) return param(); try { fn(req, res, paramCallback, paramVal, key.name); } catch (e) { paramCallback(e); } } param(); }; /** * Use the given middleware function, with optional path, defaulting to "/". * * Use (like `.all`) will run for any http METHOD, but it will not add * handlers for those methods so OPTIONS requests will not consider `.use` * functions even if they could respond. * * The other difference is that _route_ path is stripped and not visible * to the handler function. The main effect of this feature is that mounted * handlers can operate without any code changes regardless of the "prefix" * pathname. * * @public */ proto.use = function use(fn) { var offset = 0; var path = '/'; // default path to '/' // disambiguate router.use([fn]) if (typeof fn !== 'function') { var arg = fn; while (Array.isArray(arg) && arg.length !== 0) { arg = arg[0]; } // first arg is the path if (typeof arg !== 'function') { offset = 1; path = fn; } } var callbacks = flatten(slice.call(arguments, offset)); if (callbacks.length === 0) { throw new TypeError('Router.use() requires a middleware function') } for (var i = 0; i < callbacks.length; i++) { var fn = callbacks[i]; if (typeof fn !== 'function') { throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn)) } // add the middleware debug('use %o %s', path, fn.name || '') var layer = new Layer(path, { sensitive: this.caseSensitive, strict: false, end: false }, fn); layer.route = undefined; this.stack.push(layer); } return this; }; /** * Create a new Route for the given path. * * Each route contains a separate middleware stack and VERB handlers. * * See the Route api documentation for details on adding handlers * and middleware to routes. * * @param {String} path * @return {Route} * @public */ proto.route = function route(path) { var route = new Route(path); var layer = new Layer(path, { sensitive: this.caseSensitive, strict: this.strict, end: true }, route.dispatch.bind(route)); layer.route = route; this.stack.push(layer); return route; }; // create Router#VERB functions methods.concat('all').forEach(function(method){ proto[method] = function(path){ var route = this.route(path) route[method].apply(route, slice.call(arguments, 1)); return this; }; }); // append methods to a list of methods function appendMethods(list, addition) { for (var i = 0; i < addition.length; i++) { var method = addition[i]; if (list.indexOf(method) === -1) { list.push(method); } } } // get pathname of request function getPathname(req) { try { return parseUrl(req).pathname; } catch (err) { return undefined; } } // Get get protocol + host for a URL function getProtohost(url) { if (typeof url !== 'string' || url.length === 0 || url[0] === '/') { return undefined } var searchIndex = url.indexOf('?') var pathLength = searchIndex !== -1 ? searchIndex : url.length var fqdnIndex = url.substr(0, pathLength).indexOf('://') return fqdnIndex !== -1 ? url.substr(0, url.indexOf('/', 3 + fqdnIndex)) : undefined } // get type for error message function gettype(obj) { var type = typeof obj; if (type !== 'object') { return type; } // inspect [[Class]] for objects return toString.call(obj) .replace(objectRegExp, '$1'); } /** * Match path to a layer. * * @param {Layer} layer * @param {string} path * @private */ function matchLayer(layer, path) { try { return layer.match(path); } catch (err) { return err; } } // merge params with parent params function mergeParams(params, parent) { if (typeof parent !== 'object' || !parent) { return params; } // make copy of parent for base var obj = mixin({}, parent); // simple non-numeric merging if (!(0 in params) || !(0 in parent)) { return mixin(obj, params); } var i = 0; var o = 0; // determine numeric gaps while (i in params) { i++; } while (o in parent) { o++; } // offset numeric indices in params before merge for (i--; i >= 0; i--) { params[i + o] = params[i]; // create holes for the merge when necessary if (i < o) { delete params[i]; } } return mixin(obj, params); } // restore obj props after function function restore(fn, obj) { var props = new Array(arguments.length - 2); var vals = new Array(arguments.length - 2); for (var i = 0; i < props.length; i++) { props[i] = arguments[i + 2]; vals[i] = obj[props[i]]; } return function () { // restore vals for (var i = 0; i < props.length; i++) { obj[props[i]] = vals[i]; } return fn.apply(this, arguments); }; } // send an OPTIONS response function sendOptionsResponse(res, options, next) { try { var body = options.join(','); res.set('Allow', body); res.send(body); } catch (err) { next(err); } } // wrap a function function wrap(old, fn) { return function proxy() { var args = new Array(arguments.length + 1); args[0] = old; for (var i = 0, len = arguments.length; i < len; i++) { args[i + 1] = arguments[i]; } fn.apply(this, args); }; } express-4.17.3/lib/router/layer.js000066400000000000000000000063401420332637600170500ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var pathRegexp = require('path-to-regexp'); var debug = require('debug')('express:router:layer'); /** * Module variables. * @private */ var hasOwnProperty = Object.prototype.hasOwnProperty; /** * Module exports. * @public */ module.exports = Layer; function Layer(path, options, fn) { if (!(this instanceof Layer)) { return new Layer(path, options, fn); } debug('new %o', path) var opts = options || {}; this.handle = fn; this.name = fn.name || ''; this.params = undefined; this.path = undefined; this.regexp = pathRegexp(path, this.keys = [], opts); // set fast path flags this.regexp.fast_star = path === '*' this.regexp.fast_slash = path === '/' && opts.end === false } /** * Handle the error for the layer. * * @param {Error} error * @param {Request} req * @param {Response} res * @param {function} next * @api private */ Layer.prototype.handle_error = function handle_error(error, req, res, next) { var fn = this.handle; if (fn.length !== 4) { // not a standard error handler return next(error); } try { fn(error, req, res, next); } catch (err) { next(err); } }; /** * Handle the request for the layer. * * @param {Request} req * @param {Response} res * @param {function} next * @api private */ Layer.prototype.handle_request = function handle(req, res, next) { var fn = this.handle; if (fn.length > 3) { // not a standard request handler return next(); } try { fn(req, res, next); } catch (err) { next(err); } }; /** * Check if this route matches `path`, if so * populate `.params`. * * @param {String} path * @return {Boolean} * @api private */ Layer.prototype.match = function match(path) { var match if (path != null) { // fast path non-ending match for / (any path matches) if (this.regexp.fast_slash) { this.params = {} this.path = '' return true } // fast path for * (everything matched in a param) if (this.regexp.fast_star) { this.params = {'0': decode_param(path)} this.path = path return true } // match the path match = this.regexp.exec(path) } if (!match) { this.params = undefined; this.path = undefined; return false; } // store values this.params = {}; this.path = match[0] var keys = this.keys; var params = this.params; for (var i = 1; i < match.length; i++) { var key = keys[i - 1]; var prop = key.name; var val = decode_param(match[i]) if (val !== undefined || !(hasOwnProperty.call(params, prop))) { params[prop] = val; } } return true; }; /** * Decode param value. * * @param {string} val * @return {string} * @private */ function decode_param(val) { if (typeof val !== 'string' || val.length === 0) { return val; } try { return decodeURIComponent(val); } catch (err) { if (err instanceof URIError) { err.message = 'Failed to decode param \'' + val + '\''; err.status = err.statusCode = 400; } throw err; } } express-4.17.3/lib/router/route.js000066400000000000000000000100651420332637600170710ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var debug = require('debug')('express:router:route'); var flatten = require('array-flatten'); var Layer = require('./layer'); var methods = require('methods'); /** * Module variables. * @private */ var slice = Array.prototype.slice; var toString = Object.prototype.toString; /** * Module exports. * @public */ module.exports = Route; /** * Initialize `Route` with the given `path`, * * @param {String} path * @public */ function Route(path) { this.path = path; this.stack = []; debug('new %o', path) // route handlers for various http methods this.methods = {}; } /** * Determine if the route handles a given method. * @private */ Route.prototype._handles_method = function _handles_method(method) { if (this.methods._all) { return true; } var name = method.toLowerCase(); if (name === 'head' && !this.methods['head']) { name = 'get'; } return Boolean(this.methods[name]); }; /** * @return {Array} supported HTTP methods * @private */ Route.prototype._options = function _options() { var methods = Object.keys(this.methods); // append automatic head if (this.methods.get && !this.methods.head) { methods.push('head'); } for (var i = 0; i < methods.length; i++) { // make upper case methods[i] = methods[i].toUpperCase(); } return methods; }; /** * dispatch req, res into this route * @private */ Route.prototype.dispatch = function dispatch(req, res, done) { var idx = 0; var stack = this.stack; if (stack.length === 0) { return done(); } var method = req.method.toLowerCase(); if (method === 'head' && !this.methods['head']) { method = 'get'; } req.route = this; next(); function next(err) { // signal to exit route if (err && err === 'route') { return done(); } // signal to exit router if (err && err === 'router') { return done(err) } var layer = stack[idx++]; if (!layer) { return done(err); } if (layer.method && layer.method !== method) { return next(err); } if (err) { layer.handle_error(err, req, res, next); } else { layer.handle_request(req, res, next); } } }; /** * Add a handler for all HTTP verbs to this route. * * Behaves just like middleware and can respond or call `next` * to continue processing. * * You can use multiple `.all` call to add multiple handlers. * * function check_something(req, res, next){ * next(); * }; * * function validate_user(req, res, next){ * next(); * }; * * route * .all(validate_user) * .all(check_something) * .get(function(req, res, next){ * res.send('hello world'); * }); * * @param {function} handler * @return {Route} for chaining * @api public */ Route.prototype.all = function all() { var handles = flatten(slice.call(arguments)); for (var i = 0; i < handles.length; i++) { var handle = handles[i]; if (typeof handle !== 'function') { var type = toString.call(handle); var msg = 'Route.all() requires a callback function but got a ' + type throw new TypeError(msg); } var layer = Layer('/', {}, handle); layer.method = undefined; this.methods._all = true; this.stack.push(layer); } return this; }; methods.forEach(function(method){ Route.prototype[method] = function(){ var handles = flatten(slice.call(arguments)); for (var i = 0; i < handles.length; i++) { var handle = handles[i]; if (typeof handle !== 'function') { var type = toString.call(handle); var msg = 'Route.' + method + '() requires a callback function but got a ' + type throw new Error(msg); } debug('%s %o', method, this.path) var layer = Layer('/', {}, handle); layer.method = method; this.methods[method] = true; this.stack.push(layer); } return this; }; }); express-4.17.3/lib/utils.js000066400000000000000000000134521420332637600155560ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @api private */ var Buffer = require('safe-buffer').Buffer var contentDisposition = require('content-disposition'); var contentType = require('content-type'); var deprecate = require('depd')('express'); var flatten = require('array-flatten'); var mime = require('send').mime; var etag = require('etag'); var proxyaddr = require('proxy-addr'); var qs = require('qs'); var querystring = require('querystring'); /** * Return strong ETag for `body`. * * @param {String|Buffer} body * @param {String} [encoding] * @return {String} * @api private */ exports.etag = createETagGenerator({ weak: false }) /** * Return weak ETag for `body`. * * @param {String|Buffer} body * @param {String} [encoding] * @return {String} * @api private */ exports.wetag = createETagGenerator({ weak: true }) /** * Check if `path` looks absolute. * * @param {String} path * @return {Boolean} * @api private */ exports.isAbsolute = function(path){ if ('/' === path[0]) return true; if (':' === path[1] && ('\\' === path[2] || '/' === path[2])) return true; // Windows device path if ('\\\\' === path.substring(0, 2)) return true; // Microsoft Azure absolute path }; /** * Flatten the given `arr`. * * @param {Array} arr * @return {Array} * @api private */ exports.flatten = deprecate.function(flatten, 'utils.flatten: use array-flatten npm module instead'); /** * Normalize the given `type`, for example "html" becomes "text/html". * * @param {String} type * @return {Object} * @api private */ exports.normalizeType = function(type){ return ~type.indexOf('/') ? acceptParams(type) : { value: mime.lookup(type), params: {} }; }; /** * Normalize `types`, for example "html" becomes "text/html". * * @param {Array} types * @return {Array} * @api private */ exports.normalizeTypes = function(types){ var ret = []; for (var i = 0; i < types.length; ++i) { ret.push(exports.normalizeType(types[i])); } return ret; }; /** * Generate Content-Disposition header appropriate for the filename. * non-ascii filenames are urlencoded and a filename* parameter is added * * @param {String} filename * @return {String} * @api private */ exports.contentDisposition = deprecate.function(contentDisposition, 'utils.contentDisposition: use content-disposition npm module instead'); /** * Parse accept params `str` returning an * object with `.value`, `.quality` and `.params`. * also includes `.originalIndex` for stable sorting * * @param {String} str * @return {Object} * @api private */ function acceptParams(str, index) { var parts = str.split(/ *; */); var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index }; for (var i = 1; i < parts.length; ++i) { var pms = parts[i].split(/ *= */); if ('q' === pms[0]) { ret.quality = parseFloat(pms[1]); } else { ret.params[pms[0]] = pms[1]; } } return ret; } /** * Compile "etag" value to function. * * @param {Boolean|String|Function} val * @return {Function} * @api private */ exports.compileETag = function(val) { var fn; if (typeof val === 'function') { return val; } switch (val) { case true: case 'weak': fn = exports.wetag; break; case false: break; case 'strong': fn = exports.etag; break; default: throw new TypeError('unknown value for etag function: ' + val); } return fn; } /** * Compile "query parser" value to function. * * @param {String|Function} val * @return {Function} * @api private */ exports.compileQueryParser = function compileQueryParser(val) { var fn; if (typeof val === 'function') { return val; } switch (val) { case true: case 'simple': fn = querystring.parse; break; case false: fn = newObject; break; case 'extended': fn = parseExtendedQueryString; break; default: throw new TypeError('unknown value for query parser function: ' + val); } return fn; } /** * Compile "proxy trust" value to function. * * @param {Boolean|String|Number|Array|Function} val * @return {Function} * @api private */ exports.compileTrust = function(val) { if (typeof val === 'function') return val; if (val === true) { // Support plain true/false return function(){ return true }; } if (typeof val === 'number') { // Support trusting hop count return function(a, i){ return i < val }; } if (typeof val === 'string') { // Support comma-separated values val = val.split(',') .map(function (v) { return v.trim() }) } return proxyaddr.compile(val || []); } /** * Set the charset in a given Content-Type string. * * @param {String} type * @param {String} charset * @return {String} * @api private */ exports.setCharset = function setCharset(type, charset) { if (!type || !charset) { return type; } // parse type var parsed = contentType.parse(type); // set charset parsed.parameters.charset = charset; // format type return contentType.format(parsed); }; /** * Create an ETag generator function, generating ETags with * the given options. * * @param {object} options * @return {function} * @private */ function createETagGenerator (options) { return function generateETag (body, encoding) { var buf = !Buffer.isBuffer(body) ? Buffer.from(body, encoding) : body return etag(buf, options) } } /** * Parse an extended query string with qs. * * @return {Object} * @private */ function parseExtendedQueryString(str) { return qs.parse(str, { allowPrototypes: true }); } /** * Return new empty object. * * @return {Object} * @api private */ function newObject() { return {}; } express-4.17.3/lib/view.js000066400000000000000000000063761420332637600153770ustar00rootroot00000000000000/*! * express * Copyright(c) 2009-2013 TJ Holowaychuk * Copyright(c) 2013 Roman Shtylman * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ 'use strict'; /** * Module dependencies. * @private */ var debug = require('debug')('express:view'); var path = require('path'); var fs = require('fs'); /** * Module variables. * @private */ var dirname = path.dirname; var basename = path.basename; var extname = path.extname; var join = path.join; var resolve = path.resolve; /** * Module exports. * @public */ module.exports = View; /** * Initialize a new `View` with the given `name`. * * Options: * * - `defaultEngine` the default template engine name * - `engines` template engine require() cache * - `root` root path for view lookup * * @param {string} name * @param {object} options * @public */ function View(name, options) { var opts = options || {}; this.defaultEngine = opts.defaultEngine; this.ext = extname(name); this.name = name; this.root = opts.root; if (!this.ext && !this.defaultEngine) { throw new Error('No default engine was specified and no extension was provided.'); } var fileName = name; if (!this.ext) { // get extension from default engine name this.ext = this.defaultEngine[0] !== '.' ? '.' + this.defaultEngine : this.defaultEngine; fileName += this.ext; } if (!opts.engines[this.ext]) { // load engine var mod = this.ext.substr(1) debug('require "%s"', mod) // default engine export var fn = require(mod).__express if (typeof fn !== 'function') { throw new Error('Module "' + mod + '" does not provide a view engine.') } opts.engines[this.ext] = fn } // store loaded engine this.engine = opts.engines[this.ext]; // lookup path this.path = this.lookup(fileName); } /** * Lookup view by the given `name` * * @param {string} name * @private */ View.prototype.lookup = function lookup(name) { var path; var roots = [].concat(this.root); debug('lookup "%s"', name); for (var i = 0; i < roots.length && !path; i++) { var root = roots[i]; // resolve the path var loc = resolve(root, name); var dir = dirname(loc); var file = basename(loc); // resolve the file path = this.resolve(dir, file); } return path; }; /** * Render with the given options. * * @param {object} options * @param {function} callback * @private */ View.prototype.render = function render(options, callback) { debug('render "%s"', this.path); this.engine(this.path, options, callback); }; /** * Resolve the file within the given directory. * * @param {string} dir * @param {string} file * @private */ View.prototype.resolve = function resolve(dir, file) { var ext = this.ext; // . var path = join(dir, file); var stat = tryStat(path); if (stat && stat.isFile()) { return path; } // /index. path = join(dir, basename(file, ext), 'index' + ext); stat = tryStat(path); if (stat && stat.isFile()) { return path; } }; /** * Return a stat, maybe. * * @param {string} path * @return {fs.Stats} * @private */ function tryStat(path) { debug('stat "%s"', path); try { return fs.statSync(path); } catch (e) { return undefined; } } express-4.17.3/package.json000066400000000000000000000051331420332637600155750ustar00rootroot00000000000000{ "name": "express", "description": "Fast, unopinionated, minimalist web framework", "version": "4.17.3", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", "Ciaran Jessup ", "Douglas Christopher Wilson ", "Guillermo Rauch ", "Jonathan Ong ", "Roman Shtylman ", "Young Jae Sim " ], "license": "MIT", "repository": "expressjs/express", "homepage": "http://expressjs.com/", "keywords": [ "express", "framework", "sinatra", "web", "http", "rest", "restful", "router", "app", "api" ], "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.19.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "~1.1.2", "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", "qs": "6.9.7", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.17.2", "serve-static": "1.14.2", "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "devDependencies": { "after": "0.8.2", "connect-redis": "3.4.2", "cookie-parser": "1.4.6", "cookie-session": "2.0.0", "ejs": "3.1.6", "eslint": "7.32.0", "express-session": "1.17.2", "hbs": "4.2.0", "marked": "0.7.0", "method-override": "3.0.0", "mocha": "9.2.0", "morgan": "1.10.0", "multiparty": "4.2.3", "nyc": "15.1.0", "pbkdf2-password": "1.2.1", "resolve-path": "1.4.0", "should": "13.2.3", "supertest": "6.2.2", "vhost": "~3.0.2" }, "engines": { "node": ">= 0.10.0" }, "files": [ "LICENSE", "History.md", "Readme.md", "index.js", "lib/" ], "scripts": { "lint": "eslint .", "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/", "test-ci": "nyc --reporter=lcovonly --reporter=text npm test", "test-cov": "nyc --reporter=html --reporter=text npm test", "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/" } } express-4.17.3/test/000077500000000000000000000000001420332637600142645ustar00rootroot00000000000000express-4.17.3/test/Route.js000066400000000000000000000132311420332637600157200ustar00rootroot00000000000000'use strict' var after = require('after'); var should = require('should'); var express = require('../') , Route = express.Route , methods = require('methods') describe('Route', function(){ it('should work without handlers', function(done) { var req = { method: 'GET', url: '/' } var route = new Route('/foo') route.dispatch(req, {}, done) }) describe('.all', function(){ it('should add handler', function(done){ var req = { method: 'GET', url: '/' }; var route = new Route('/foo'); route.all(function(req, res, next) { req.called = true; next(); }); route.dispatch(req, {}, function (err) { if (err) return done(err); should(req.called).be.ok() done(); }); }) it('should handle VERBS', function(done) { var count = 0; var route = new Route('/foo'); var cb = after(methods.length, function (err) { if (err) return done(err); count.should.equal(methods.length); done(); }); route.all(function(req, res, next) { count++; next(); }); methods.forEach(function testMethod(method) { var req = { method: method, url: '/' }; route.dispatch(req, {}, cb); }); }) it('should stack', function(done) { var req = { count: 0, method: 'GET', url: '/' }; var route = new Route('/foo'); route.all(function(req, res, next) { req.count++; next(); }); route.all(function(req, res, next) { req.count++; next(); }); route.dispatch(req, {}, function (err) { if (err) return done(err); req.count.should.equal(2); done(); }); }) }) describe('.VERB', function(){ it('should support .get', function(done){ var req = { method: 'GET', url: '/' }; var route = new Route(''); route.get(function(req, res, next) { req.called = true; next(); }) route.dispatch(req, {}, function (err) { if (err) return done(err); should(req.called).be.ok() done(); }); }) it('should limit to just .VERB', function(done){ var req = { method: 'POST', url: '/' }; var route = new Route(''); route.get(function(req, res, next) { throw new Error('not me!'); }) route.post(function(req, res, next) { req.called = true; next(); }) route.dispatch(req, {}, function (err) { if (err) return done(err); should(req.called).be.true() done(); }); }) it('should allow fallthrough', function(done){ var req = { order: '', method: 'GET', url: '/' }; var route = new Route(''); route.get(function(req, res, next) { req.order += 'a'; next(); }) route.all(function(req, res, next) { req.order += 'b'; next(); }); route.get(function(req, res, next) { req.order += 'c'; next(); }) route.dispatch(req, {}, function (err) { if (err) return done(err); req.order.should.equal('abc'); done(); }); }) }) describe('errors', function(){ it('should handle errors via arity 4 functions', function(done){ var req = { order: '', method: 'GET', url: '/' }; var route = new Route(''); route.all(function(req, res, next){ next(new Error('foobar')); }); route.all(function(req, res, next){ req.order += '0'; next(); }); route.all(function(err, req, res, next){ req.order += 'a'; next(err); }); route.dispatch(req, {}, function (err) { should(err).be.ok() should(err.message).equal('foobar'); req.order.should.equal('a'); done(); }); }) it('should handle throw', function(done) { var req = { order: '', method: 'GET', url: '/' }; var route = new Route(''); route.all(function(req, res, next){ throw new Error('foobar'); }); route.all(function(req, res, next){ req.order += '0'; next(); }); route.all(function(err, req, res, next){ req.order += 'a'; next(err); }); route.dispatch(req, {}, function (err) { should(err).be.ok() should(err.message).equal('foobar'); req.order.should.equal('a'); done(); }); }); it('should handle throwing inside error handlers', function(done) { var req = { method: 'GET', url: '/' }; var route = new Route(''); route.get(function(req, res, next){ throw new Error('boom!'); }); route.get(function(err, req, res, next){ throw new Error('oops'); }); route.get(function(err, req, res, next){ req.message = err.message; next(); }); route.dispatch(req, {}, function (err) { if (err) return done(err); should(req.message).equal('oops'); done(); }); }); it('should handle throw in .all', function(done) { var req = { method: 'GET', url: '/' }; var route = new Route(''); route.all(function(req, res, next){ throw new Error('boom!'); }); route.dispatch(req, {}, function(err){ should(err).be.ok() err.message.should.equal('boom!'); done(); }); }); it('should handle single error handler', function(done) { var req = { method: 'GET', url: '/' }; var route = new Route(''); route.all(function(err, req, res, next){ // this should not execute true.should.be.false() }); route.dispatch(req, {}, done); }); }) }) express-4.17.3/test/Router.js000066400000000000000000000361151420332637600161100ustar00rootroot00000000000000'use strict' var after = require('after'); var express = require('../') , Router = express.Router , methods = require('methods') , assert = require('assert'); describe('Router', function(){ it('should return a function with router methods', function() { var router = new Router(); assert(typeof router === 'function') assert(typeof router.get === 'function') assert(typeof router.handle === 'function') assert(typeof router.use === 'function') }); it('should support .use of other routers', function(done){ var router = new Router(); var another = new Router(); another.get('/bar', function(req, res){ res.end(); }); router.use('/foo', another); router.handle({ url: '/foo/bar', method: 'GET' }, { end: done }); }); it('should support dynamic routes', function(done){ var router = new Router(); var another = new Router(); another.get('/:bar', function(req, res){ assert.strictEqual(req.params.bar, 'route') res.end(); }); router.use('/:foo', another); router.handle({ url: '/test/route', method: 'GET' }, { end: done }); }); it('should handle blank URL', function(done){ var router = new Router(); router.use(function (req, res) { throw new Error('should not be called') }); router.handle({ url: '', method: 'GET' }, {}, done); }); it('should handle missing URL', function (done) { var router = new Router() router.use(function (req, res) { throw new Error('should not be called') }) router.handle({ method: 'GET' }, {}, done) }) it('should not stack overflow with many registered routes', function(done){ var handler = function(req, res){ res.end(new Error('wrong handler')) }; var router = new Router(); for (var i = 0; i < 6000; i++) { router.get('/thing' + i, handler) } router.get('/', function (req, res) { res.end(); }); router.handle({ url: '/', method: 'GET' }, { end: done }); }); describe('.handle', function(){ it('should dispatch', function(done){ var router = new Router(); router.route('/foo').get(function(req, res){ res.send('foo'); }); var res = { send: function(val) { assert.strictEqual(val, 'foo') done(); } } router.handle({ url: '/foo', method: 'GET' }, res); }) }) describe('.multiple callbacks', function(){ it('should throw if a callback is null', function(){ assert.throws(function () { var router = new Router(); router.route('/foo').all(null); }) }) it('should throw if a callback is undefined', function(){ assert.throws(function () { var router = new Router(); router.route('/foo').all(undefined); }) }) it('should throw if a callback is not a function', function(){ assert.throws(function () { var router = new Router(); router.route('/foo').all('not a function'); }) }) it('should not throw if all callbacks are functions', function(){ var router = new Router(); router.route('/foo').all(function(){}).all(function(){}); }) }) describe('error', function(){ it('should skip non error middleware', function(done){ var router = new Router(); router.get('/foo', function(req, res, next){ next(new Error('foo')); }); router.get('/bar', function(req, res, next){ next(new Error('bar')); }); router.use(function(req, res, next){ assert(false); }); router.use(function(err, req, res, next){ assert.equal(err.message, 'foo'); done(); }); router.handle({ url: '/foo', method: 'GET' }, {}, done); }); it('should handle throwing inside routes with params', function(done) { var router = new Router(); router.get('/foo/:id', function(req, res, next){ throw new Error('foo'); }); router.use(function(req, res, next){ assert(false); }); router.use(function(err, req, res, next){ assert.equal(err.message, 'foo'); done(); }); router.handle({ url: '/foo/2', method: 'GET' }, {}, function() {}); }); it('should handle throwing in handler after async param', function(done) { var router = new Router(); router.param('user', function(req, res, next, val){ process.nextTick(function(){ req.user = val; next(); }); }); router.use('/:user', function(req, res, next){ throw new Error('oh no!'); }); router.use(function(err, req, res, next){ assert.equal(err.message, 'oh no!'); done(); }); router.handle({ url: '/bob', method: 'GET' }, {}, function() {}); }); it('should handle throwing inside error handlers', function(done) { var router = new Router(); router.use(function(req, res, next){ throw new Error('boom!'); }); router.use(function(err, req, res, next){ throw new Error('oops'); }); router.use(function(err, req, res, next){ assert.equal(err.message, 'oops'); done(); }); router.handle({ url: '/', method: 'GET' }, {}, done); }); }) describe('FQDN', function () { it('should not obscure FQDNs', function (done) { var request = { hit: 0, url: 'http://example.com/foo', method: 'GET' }; var router = new Router(); router.use(function (req, res, next) { assert.equal(req.hit++, 0); assert.equal(req.url, 'http://example.com/foo'); next(); }); router.handle(request, {}, function (err) { if (err) return done(err); assert.equal(request.hit, 1); done(); }); }); it('should ignore FQDN in search', function (done) { var request = { hit: 0, url: '/proxy?url=http://example.com/blog/post/1', method: 'GET' }; var router = new Router(); router.use('/proxy', function (req, res, next) { assert.equal(req.hit++, 0); assert.equal(req.url, '/?url=http://example.com/blog/post/1'); next(); }); router.handle(request, {}, function (err) { if (err) return done(err); assert.equal(request.hit, 1); done(); }); }); it('should ignore FQDN in path', function (done) { var request = { hit: 0, url: '/proxy/http://example.com/blog/post/1', method: 'GET' }; var router = new Router(); router.use('/proxy', function (req, res, next) { assert.equal(req.hit++, 0); assert.equal(req.url, '/http://example.com/blog/post/1'); next(); }); router.handle(request, {}, function (err) { if (err) return done(err); assert.equal(request.hit, 1); done(); }); }); it('should adjust FQDN req.url', function (done) { var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' }; var router = new Router(); router.use('/blog', function (req, res, next) { assert.equal(req.hit++, 0); assert.equal(req.url, 'http://example.com/post/1'); next(); }); router.handle(request, {}, function (err) { if (err) return done(err); assert.equal(request.hit, 1); done(); }); }); it('should adjust FQDN req.url with multiple handlers', function (done) { var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' }; var router = new Router(); router.use(function (req, res, next) { assert.equal(req.hit++, 0); assert.equal(req.url, 'http://example.com/blog/post/1'); next(); }); router.use('/blog', function (req, res, next) { assert.equal(req.hit++, 1); assert.equal(req.url, 'http://example.com/post/1'); next(); }); router.handle(request, {}, function (err) { if (err) return done(err); assert.equal(request.hit, 2); done(); }); }); it('should adjust FQDN req.url with multiple routed handlers', function (done) { var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' }; var router = new Router(); router.use('/blog', function (req, res, next) { assert.equal(req.hit++, 0); assert.equal(req.url, 'http://example.com/post/1'); next(); }); router.use('/blog', function (req, res, next) { assert.equal(req.hit++, 1); assert.equal(req.url, 'http://example.com/post/1'); next(); }); router.use(function (req, res, next) { assert.equal(req.hit++, 2); assert.equal(req.url, 'http://example.com/blog/post/1'); next(); }); router.handle(request, {}, function (err) { if (err) return done(err); assert.equal(request.hit, 3); done(); }); }); }) describe('.all', function() { it('should support using .all to capture all http verbs', function(done){ var router = new Router(); var count = 0; router.all('/foo', function(){ count++; }); var url = '/foo?bar=baz'; methods.forEach(function testMethod(method) { router.handle({ url: url, method: method }, {}, function() {}); }); assert.equal(count, methods.length); done(); }) it('should be called for any URL when "*"', function (done) { var cb = after(4, done) var router = new Router() function no () { throw new Error('should not be called') } router.all('*', function (req, res) { res.end() }) router.handle({ url: '/', method: 'GET' }, { end: cb }, no) router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no) router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no) router.handle({ url: '*', method: 'GET' }, { end: cb }, no) }) }) describe('.use', function() { it('should require middleware', function () { var router = new Router() assert.throws(function () { router.use('/') }, /requires a middleware function/) }) it('should reject string as middleware', function () { var router = new Router() assert.throws(function () { router.use('/', 'foo') }, /requires a middleware function but got a string/) }) it('should reject number as middleware', function () { var router = new Router() assert.throws(function () { router.use('/', 42) }, /requires a middleware function but got a number/) }) it('should reject null as middleware', function () { var router = new Router() assert.throws(function () { router.use('/', null) }, /requires a middleware function but got a Null/) }) it('should reject Date as middleware', function () { var router = new Router() assert.throws(function () { router.use('/', new Date()) }, /requires a middleware function but got a Date/) }) it('should be called for any URL', function (done) { var cb = after(4, done) var router = new Router() function no () { throw new Error('should not be called') } router.use(function (req, res) { res.end() }) router.handle({ url: '/', method: 'GET' }, { end: cb }, no) router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no) router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no) router.handle({ url: '*', method: 'GET' }, { end: cb }, no) }) it('should accept array of middleware', function(done){ var count = 0; var router = new Router(); function fn1(req, res, next){ assert.equal(++count, 1); next(); } function fn2(req, res, next){ assert.equal(++count, 2); next(); } router.use([fn1, fn2], function(req, res){ assert.equal(++count, 3); done(); }); router.handle({ url: '/foo', method: 'GET' }, {}, function(){}); }) }) describe('.param', function() { it('should call param function when routing VERBS', function(done) { var router = new Router(); router.param('id', function(req, res, next, id) { assert.equal(id, '123'); next(); }); router.get('/foo/:id/bar', function(req, res, next) { assert.equal(req.params.id, '123'); next(); }); router.handle({ url: '/foo/123/bar', method: 'get' }, {}, done); }); it('should call param function when routing middleware', function(done) { var router = new Router(); router.param('id', function(req, res, next, id) { assert.equal(id, '123'); next(); }); router.use('/foo/:id/bar', function(req, res, next) { assert.equal(req.params.id, '123'); assert.equal(req.url, '/baz'); next(); }); router.handle({ url: '/foo/123/bar/baz', method: 'get' }, {}, done); }); it('should only call once per request', function(done) { var count = 0; var req = { url: '/foo/bob/bar', method: 'get' }; var router = new Router(); var sub = new Router(); sub.get('/bar', function(req, res, next) { next(); }); router.param('user', function(req, res, next, user) { count++; req.user = user; next(); }); router.use('/foo/:user/', new Router()); router.use('/foo/:user/', sub); router.handle(req, {}, function(err) { if (err) return done(err); assert.equal(count, 1); assert.equal(req.user, 'bob'); done(); }); }); it('should call when values differ', function(done) { var count = 0; var req = { url: '/foo/bob/bar', method: 'get' }; var router = new Router(); var sub = new Router(); sub.get('/bar', function(req, res, next) { next(); }); router.param('user', function(req, res, next, user) { count++; req.user = user; next(); }); router.use('/foo/:user/', new Router()); router.use('/:user/bob/', sub); router.handle(req, {}, function(err) { if (err) return done(err); assert.equal(count, 2); assert.equal(req.user, 'foo'); done(); }); }); }); describe('parallel requests', function() { it('should not mix requests', function(done) { var req1 = { url: '/foo/50/bar', method: 'get' }; var req2 = { url: '/foo/10/bar', method: 'get' }; var router = new Router(); var sub = new Router(); done = after(2, done); sub.get('/bar', function(req, res, next) { next(); }); router.param('ms', function(req, res, next, ms) { ms = parseInt(ms, 10); req.ms = ms; setTimeout(next, ms); }); router.use('/foo/:ms/', new Router()); router.use('/foo/:ms/', sub); router.handle(req1, {}, function(err) { assert.ifError(err); assert.equal(req1.ms, 50); assert.equal(req1.originalUrl, '/foo/50/bar'); done(); }); router.handle(req2, {}, function(err) { assert.ifError(err); assert.equal(req2.ms, 10); assert.equal(req2.originalUrl, '/foo/10/bar'); done(); }); }); }); }) express-4.17.3/test/acceptance/000077500000000000000000000000001420332637600163525ustar00rootroot00000000000000express-4.17.3/test/acceptance/auth.js000066400000000000000000000057701420332637600176620ustar00rootroot00000000000000var app = require('../../examples/auth') var request = require('supertest') function getCookie(res) { return res.headers['set-cookie'][0].split(';')[0]; } describe('auth', function(){ describe('GET /',function(){ it('should redirect to /login', function(done){ request(app) .get('/') .expect('Location', '/login') .expect(302, done) }) }) describe('GET /login',function(){ it('should render login form', function(done){ request(app) .get('/login') .expect(200, /
  • Tobi
  • Loki
  • Jane
  • ', done) }) it('should accept to text/plain', function(done){ request(app) .get('/') .set('Accept', 'text/plain') .expect(200, ' - Tobi\n - Loki\n - Jane\n', done) }) it('should accept to application/json', function(done){ request(app) .get('/') .set('Accept', 'application/json') .expect(200, '[{"name":"Tobi"},{"name":"Loki"},{"name":"Jane"}]', done) }) }) describe('GET /users', function(){ it('should default to text/html', function(done){ request(app) .get('/users') .expect(200, '
    • Tobi
    • Loki
    • Jane
    ', done) }) it('should accept to text/plain', function(done){ request(app) .get('/users') .set('Accept', 'text/plain') .expect(200, ' - Tobi\n - Loki\n - Jane\n', done) }) it('should accept to application/json', function(done){ request(app) .get('/users') .set('Accept', 'application/json') .expect(200, '[{"name":"Tobi"},{"name":"Loki"},{"name":"Jane"}]', done) }) }) }) express-4.17.3/test/acceptance/cookie-sessions.js000066400000000000000000000016561420332637600220350ustar00rootroot00000000000000 var app = require('../../examples/cookie-sessions') var request = require('supertest') describe('cookie-sessions', function () { describe('GET /', function () { it('should display no views', function (done) { request(app) .get('/') .expect(200, 'viewed 1 times\n', done) }) it('should set a session cookie', function (done) { request(app) .get('/') .expect('Set-Cookie', /session=/) .expect(200, done) }) it('should display 1 view on revisit', function (done) { request(app) .get('/') .expect(200, 'viewed 1 times\n', function (err, res) { if (err) return done(err) request(app) .get('/') .set('Cookie', getCookies(res)) .expect(200, 'viewed 2 times\n', done) }) }) }) }) function getCookies(res) { return res.headers['set-cookie'].map(function (val) { return val.split(';')[0] }).join('; '); } express-4.17.3/test/acceptance/cookies.js000066400000000000000000000033221420332637600203440ustar00rootroot00000000000000 var app = require('../../examples/cookies') , request = require('supertest'); var utils = require('../support/utils'); describe('cookies', function(){ describe('GET /', function(){ it('should have a form', function(done){ request(app) .get('/') .expect(/tobi <tobi@learnboost\.com><\/li>/) .expect(/
  • loki <loki@learnboost\.com><\/li>/) .expect(/
  • jane <jane@learnboost\.com><\/li>/) .expect(200, done) }) }) }) express-4.17.3/test/acceptance/error-pages.js000066400000000000000000000044131420332637600211400ustar00rootroot00000000000000 var app = require('../../examples/error-pages') , request = require('supertest'); describe('error-pages', function(){ describe('GET /', function(){ it('should respond with page list', function(done){ request(app) .get('/') .expect(/Pages Example/, done) }) }) describe('Accept: text/html',function(){ describe('GET /403', function(){ it('should respond with 403', function(done){ request(app) .get('/403') .expect(403, done) }) }) describe('GET /404', function(){ it('should respond with 404', function(done){ request(app) .get('/404') .expect(404, done) }) }) describe('GET /500', function(){ it('should respond with 500', function(done){ request(app) .get('/500') .expect(500, done) }) }) }) describe('Accept: application/json',function(){ describe('GET /403', function(){ it('should respond with 403', function(done){ request(app) .get('/403') .set('Accept','application/json') .expect(403, done) }) }) describe('GET /404', function(){ it('should respond with 404', function(done){ request(app) .get('/404') .set('Accept','application/json') .expect(404, { error: 'Not found' }, done) }) }) describe('GET /500', function(){ it('should respond with 500', function(done){ request(app) .get('/500') .set('Accept', 'application/json') .expect(500, done) }) }) }) describe('Accept: text/plain',function(){ describe('GET /403', function(){ it('should respond with 403', function(done){ request(app) .get('/403') .set('Accept','text/plain') .expect(403, done) }) }) describe('GET /404', function(){ it('should respond with 404', function(done){ request(app) .get('/404') .set('Accept', 'text/plain') .expect(404) .expect('Not found', done); }) }) describe('GET /500', function(){ it('should respond with 500', function(done){ request(app) .get('/500') .set('Accept','text/plain') .expect(500, done) }) }) }) }) express-4.17.3/test/acceptance/error.js000066400000000000000000000011401420332637600200350ustar00rootroot00000000000000 var app = require('../../examples/error') , request = require('supertest'); describe('error', function(){ describe('GET /', function(){ it('should respond with 500', function(done){ request(app) .get('/') .expect(500,done) }) }) describe('GET /next', function(){ it('should respond with 500', function(done){ request(app) .get('/next') .expect(500,done) }) }) describe('GET /missing', function(){ it('should respond with 404', function(done){ request(app) .get('/missing') .expect(404,done) }) }) }) express-4.17.3/test/acceptance/hello-world.js000066400000000000000000000007501420332637600211420ustar00rootroot00000000000000 var app = require('../../examples/hello-world') var request = require('supertest') describe('hello-world', function () { describe('GET /', function () { it('should respond with hello world', function (done) { request(app) .get('/') .expect(200, 'Hello World', done) }) }) describe('GET /missing', function () { it('should respond with 404', function (done) { request(app) .get('/missing') .expect(404, done) }) }) }) express-4.17.3/test/acceptance/markdown.js000066400000000000000000000007341420332637600205360ustar00rootroot00000000000000 var app = require('../../examples/markdown') var request = require('supertest') describe('markdown', function(){ describe('GET /', function(){ it('should respond with html', function(done){ request(app) .get('/') .expect(/]*>Markdown Example<\/h1>/,done) }) }) describe('GET /fail',function(){ it('should respond with an error', function(done){ request(app) .get('/fail') .expect(500,done) }) }) }) express-4.17.3/test/acceptance/multi-router.js000066400000000000000000000022251420332637600213610ustar00rootroot00000000000000var app = require('../../examples/multi-router') var request = require('supertest') describe('multi-router', function(){ describe('GET /',function(){ it('should respond with root handler', function(done){ request(app) .get('/') .expect(200, 'Hello from root route.', done) }) }) describe('GET /api/v1/',function(){ it('should respond with APIv1 root handler', function(done){ request(app) .get('/api/v1/') .expect(200, 'Hello from APIv1 root route.', done) }) }) describe('GET /api/v1/users',function(){ it('should respond with users from APIv1', function(done){ request(app) .get('/api/v1/users') .expect(200, 'List of APIv1 users.', done) }) }) describe('GET /api/v2/',function(){ it('should respond with APIv2 root handler', function(done){ request(app) .get('/api/v2/') .expect(200, 'Hello from APIv2 root route.', done) }) }) describe('GET /api/v2/users',function(){ it('should respond with users from APIv2', function(done){ request(app) .get('/api/v2/users') .expect(200, 'List of APIv2 users.', done) }) }) }) express-4.17.3/test/acceptance/mvc.js000066400000000000000000000063341420332637600175030ustar00rootroot00000000000000 var request = require('supertest') , app = require('../../examples/mvc'); describe('mvc', function(){ describe('GET /', function(){ it('should redirect to /users', function(done){ request(app) .get('/') .expect('Location', '/users') .expect(302, done) }) }) describe('GET /pet/0', function(){ it('should get pet', function(done){ request(app) .get('/pet/0') .expect(200, /Tobi/, done) }) }) describe('GET /pet/0/edit', function(){ it('should get pet edit page', function(done){ request(app) .get('/pet/0/edit') .expect(/Users<\/h1>/) .expect(/>TJGuillermoNathanTJ edit/, done) }) it('should display the users pets', function(done){ request(app) .get('/user/0') .expect(/\/pet\/0">Tobi/) .expect(/\/pet\/1">Loki/) .expect(/\/pet\/2">Jane/) .expect(200, done) }) }) describe('when not present', function(){ it('should 404', function(done){ request(app) .get('/user/123') .expect(404, done); }) }) }) describe('GET /user/:id/edit', function(){ it('should display the edit form', function(done){ request(app) .get('/user/1/edit') .expect(/Guillermo/) .expect(200, /Examples:<\/h1>/,done) }) }) describe('GET /users', function(){ it('should respond with all users', function(done){ request(app) .get('/users') .expect(/^\[{"name":"tj"},{"name":"ciaran"},{"name":"aaron"},{"name":"guillermo"},{"name":"simon"},{"name":"tobi"}\]/,done) }) }) describe('GET /users/1', function(){ it('should respond with user 1', function(done){ request(app) .get('/users/1') .expect(/^{"name":"ciaran"}/,done) }) }) describe('GET /users/9', function(){ it('should respond with error', function(done){ request(app) .get('/users/9') .expect('{"error":"Cannot find user"}', done) }) }) describe('GET /users/1..3', function(){ it('should respond with users 1 through 3', function(done){ request(app) .get('/users/1..3') .expect(/^