├── .gitattributes ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── CONTRIBUTING.asciidoc ├── LICENSE ├── Makefile ├── README.asciidoc ├── doc └── src │ ├── guide │ ├── book.asciidoc │ ├── constraints.asciidoc │ ├── cookies.asciidoc │ ├── cowboy.sty │ ├── erlang_web.asciidoc │ ├── flow_diagram.asciidoc │ ├── getting_started.asciidoc │ ├── handlers.asciidoc │ ├── http_req_resp.png │ ├── http_req_resp.svg │ ├── introduction.asciidoc │ ├── listeners.asciidoc │ ├── loop_handlers.asciidoc │ ├── middlewares.asciidoc │ ├── migrating_from_1.0.asciidoc │ ├── migrating_from_2.0.asciidoc │ ├── migrating_from_2.1.asciidoc │ ├── migrating_from_2.10.asciidoc │ ├── migrating_from_2.11.asciidoc │ ├── migrating_from_2.12.asciidoc │ ├── migrating_from_2.2.asciidoc │ ├── migrating_from_2.3.asciidoc │ ├── migrating_from_2.4.asciidoc │ ├── migrating_from_2.5.asciidoc │ ├── migrating_from_2.6.asciidoc │ ├── migrating_from_2.7.asciidoc │ ├── migrating_from_2.8.asciidoc │ ├── migrating_from_2.9.asciidoc │ ├── modern_web.asciidoc │ ├── multipart.asciidoc │ ├── performance.asciidoc │ ├── req.asciidoc │ ├── req_body.asciidoc │ ├── resource_design.asciidoc │ ├── resp.asciidoc │ ├── rest_cond.png │ ├── rest_cond.svg │ ├── rest_conneg.png │ ├── rest_conneg.svg │ ├── rest_delete.png │ ├── rest_delete.svg │ ├── rest_flowcharts.asciidoc │ ├── rest_get_head.png │ ├── rest_get_head.svg │ ├── rest_handlers.asciidoc │ ├── rest_options.png │ ├── rest_options.svg │ ├── rest_principles.asciidoc │ ├── rest_put_post_patch.png │ ├── rest_put_post_patch.svg │ ├── rest_start.png │ ├── rest_start.svg │ ├── routing.asciidoc │ ├── specs.asciidoc │ ├── static_files.asciidoc │ ├── streams.asciidoc │ ├── ws_handlers.asciidoc │ └── ws_protocol.asciidoc │ ├── manual │ ├── cowboy.asciidoc │ ├── cowboy.get_env.asciidoc │ ├── cowboy.set_env.asciidoc │ ├── cowboy.start_clear.asciidoc │ ├── cowboy.start_tls.asciidoc │ ├── cowboy.stop_listener.asciidoc │ ├── cowboy_app.asciidoc │ ├── cowboy_compress_h.asciidoc │ ├── cowboy_constraints.asciidoc │ ├── cowboy_constraints.int.asciidoc │ ├── cowboy_constraints.nonempty.asciidoc │ ├── cowboy_decompress_h.asciidoc │ ├── cowboy_handler.asciidoc │ ├── cowboy_handler.terminate.asciidoc │ ├── cowboy_http.asciidoc │ ├── cowboy_http2.asciidoc │ ├── cowboy_loop.asciidoc │ ├── cowboy_metrics_h.asciidoc │ ├── cowboy_middleware.asciidoc │ ├── cowboy_req.asciidoc │ ├── cowboy_req.binding.asciidoc │ ├── cowboy_req.bindings.asciidoc │ ├── cowboy_req.body_length.asciidoc │ ├── cowboy_req.cast.asciidoc │ ├── cowboy_req.cert.asciidoc │ ├── cowboy_req.delete_resp_header.asciidoc │ ├── cowboy_req.filter_cookies.asciidoc │ ├── cowboy_req.has_body.asciidoc │ ├── cowboy_req.has_resp_body.asciidoc │ ├── cowboy_req.has_resp_header.asciidoc │ ├── cowboy_req.header.asciidoc │ ├── cowboy_req.headers.asciidoc │ ├── cowboy_req.host.asciidoc │ ├── cowboy_req.host_info.asciidoc │ ├── cowboy_req.inform.asciidoc │ ├── cowboy_req.match_cookies.asciidoc │ ├── cowboy_req.match_qs.asciidoc │ ├── cowboy_req.method.asciidoc │ ├── cowboy_req.parse_cookies.asciidoc │ ├── cowboy_req.parse_header.asciidoc │ ├── cowboy_req.parse_qs.asciidoc │ ├── cowboy_req.path.asciidoc │ ├── cowboy_req.path_info.asciidoc │ ├── cowboy_req.peer.asciidoc │ ├── cowboy_req.port.asciidoc │ ├── cowboy_req.push.asciidoc │ ├── cowboy_req.qs.asciidoc │ ├── cowboy_req.read_and_match_urlencoded_body.asciidoc │ ├── cowboy_req.read_body.asciidoc │ ├── cowboy_req.read_part.asciidoc │ ├── cowboy_req.read_part_body.asciidoc │ ├── cowboy_req.read_urlencoded_body.asciidoc │ ├── cowboy_req.reply.asciidoc │ ├── cowboy_req.resp_header.asciidoc │ ├── cowboy_req.resp_headers.asciidoc │ ├── cowboy_req.scheme.asciidoc │ ├── cowboy_req.set_resp_body.asciidoc │ ├── cowboy_req.set_resp_cookie.asciidoc │ ├── cowboy_req.set_resp_header.asciidoc │ ├── cowboy_req.set_resp_headers.asciidoc │ ├── cowboy_req.sock.asciidoc │ ├── cowboy_req.stream_body.asciidoc │ ├── cowboy_req.stream_events.asciidoc │ ├── cowboy_req.stream_reply.asciidoc │ ├── cowboy_req.stream_trailers.asciidoc │ ├── cowboy_req.uri.asciidoc │ ├── cowboy_req.version.asciidoc │ ├── cowboy_rest.asciidoc │ ├── cowboy_router.asciidoc │ ├── cowboy_router.compile.asciidoc │ ├── cowboy_static.asciidoc │ ├── cowboy_stream.asciidoc │ ├── cowboy_stream.data.asciidoc │ ├── cowboy_stream.early_error.asciidoc │ ├── cowboy_stream.info.asciidoc │ ├── cowboy_stream.init.asciidoc │ ├── cowboy_stream.terminate.asciidoc │ ├── cowboy_stream_h.asciidoc │ ├── cowboy_tracer_h.asciidoc │ ├── cowboy_websocket.asciidoc │ └── http_status_codes.asciidoc │ └── specs │ ├── index.ezdoc │ ├── rfc6585.ezdoc │ └── rfc7230_server.ezdoc ├── ebin └── cowboy.app ├── erlang.mk ├── examples ├── README.asciidoc ├── chunked_hello_world │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── chunked_hello_world_app.erl │ │ ├── chunked_hello_world_sup.erl │ │ └── toppage_h.erl ├── compress_response │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── compress_response_app.erl │ │ ├── compress_response_sup.erl │ │ └── toppage_h.erl ├── cookie │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ ├── src │ │ ├── cookie_app.erl │ │ ├── cookie_sup.erl │ │ └── toppage_h.erl │ └── templates │ │ └── toppage.dtl ├── echo_get │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── echo_get_app.erl │ │ ├── echo_get_sup.erl │ │ └── toppage_h.erl ├── echo_post │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── echo_post_app.erl │ │ ├── echo_post_sup.erl │ │ └── toppage_h.erl ├── eventsource │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ │ └── index.html │ ├── relx.config │ └── src │ │ ├── eventsource_app.erl │ │ ├── eventsource_h.erl │ │ └── eventsource_sup.erl ├── file_server │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ │ ├── small.mp4 │ │ ├── small.ogv │ │ ├── test.txt │ │ ├── video.html │ │ └── 中文 │ │ │ └── 中文.html │ ├── relx.config │ └── src │ │ ├── directory_h.erl │ │ ├── directory_lister.erl │ │ ├── file_server_app.erl │ │ └── file_server_sup.erl ├── hello_world │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── hello_world_app.erl │ │ ├── hello_world_sup.erl │ │ └── toppage_h.erl ├── markdown_middleware │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ │ ├── small.mp4 │ │ ├── small.ogv │ │ └── video.md │ ├── relx.config │ └── src │ │ ├── markdown_converter.erl │ │ ├── markdown_middleware_app.erl │ │ └── markdown_middleware_sup.erl ├── rest_basic_auth │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── rest_basic_auth_app.erl │ │ ├── rest_basic_auth_sup.erl │ │ └── toppage_h.erl ├── rest_hello_world │ ├── Makefile │ ├── README.asciidoc │ ├── relx.config │ └── src │ │ ├── rest_hello_world_app.erl │ │ ├── rest_hello_world_sup.erl │ │ └── toppage_h.erl ├── rest_pastebin │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ │ ├── index.html │ │ └── index.txt │ ├── relx.config │ └── src │ │ ├── rest_pastebin_app.erl │ │ ├── rest_pastebin_sup.erl │ │ └── toppage_h.erl ├── ssl_hello_world │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ │ └── ssl │ │ │ ├── cert.pem │ │ │ └── key.pem │ ├── relx.config │ └── src │ │ ├── ssl_hello_world_app.erl │ │ ├── ssl_hello_world_sup.erl │ │ └── toppage_h.erl ├── upload │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ │ └── index.html │ ├── relx.config │ └── src │ │ ├── upload_app.erl │ │ ├── upload_h.erl │ │ └── upload_sup.erl └── websocket │ ├── Makefile │ ├── README.asciidoc │ ├── priv │ └── index.html │ ├── relx.config │ └── src │ ├── websocket_app.erl │ ├── websocket_sup.erl │ └── ws_h.erl ├── plugins.mk ├── rebar.config ├── src ├── cowboy.erl ├── cowboy_app.erl ├── cowboy_bstr.erl ├── cowboy_children.erl ├── cowboy_clear.erl ├── cowboy_clock.erl ├── cowboy_compress_h.erl ├── cowboy_constraints.erl ├── cowboy_decompress_h.erl ├── cowboy_dynamic_buffer.hrl ├── cowboy_handler.erl ├── cowboy_http.erl ├── cowboy_http2.erl ├── cowboy_http3.erl ├── cowboy_loop.erl ├── cowboy_metrics_h.erl ├── cowboy_middleware.erl ├── cowboy_quicer.erl ├── cowboy_req.erl ├── cowboy_rest.erl ├── cowboy_router.erl ├── cowboy_static.erl ├── cowboy_stream.erl ├── cowboy_stream_h.erl ├── cowboy_sub_protocol.erl ├── cowboy_sup.erl ├── cowboy_tls.erl ├── cowboy_tracer_h.erl └── cowboy_websocket.erl └── test ├── compress_SUITE.erl ├── cover.spec ├── cowboy_ct_hook.erl ├── cowboy_test.erl ├── decompress_SUITE.erl ├── examples_SUITE.erl ├── h2spec_SUITE.erl ├── handlers ├── accept_callback_h.erl ├── accept_callback_missing_h.erl ├── asterisk_h.erl ├── charset_in_content_types_provided_h.erl ├── charset_in_content_types_provided_implicit_h.erl ├── charset_in_content_types_provided_implicit_no_callback_h.erl ├── charsets_provided_empty_h.erl ├── charsets_provided_h.erl ├── compress_h.erl ├── content_types_accepted_h.erl ├── content_types_provided_h.erl ├── crash_h.erl ├── create_resource_h.erl ├── custom_req_fields_h.erl ├── decompress_h.erl ├── default_h.erl ├── delay_hello_h.erl ├── delete_resource_h.erl ├── echo_h.erl ├── expires_h.erl ├── generate_etag_h.erl ├── hello_h.erl ├── if_range_h.erl ├── last_modified_h.erl ├── long_polling_h.erl ├── long_polling_sys_h.erl ├── loop_handler_abort_h.erl ├── loop_handler_body_h.erl ├── loop_handler_endless_h.erl ├── loop_handler_timeout_h.erl ├── loop_handler_timeout_hibernate_h.erl ├── loop_handler_timeout_info_h.erl ├── loop_handler_timeout_init_h.erl ├── multipart_h.erl ├── provide_callback_missing_h.erl ├── provide_range_callback_h.erl ├── range_satisfiable_h.erl ├── ranges_provided_auto_h.erl ├── ranges_provided_h.erl ├── rate_limited_h.erl ├── read_body_h.erl ├── resp_h.erl ├── resp_iolist_body_h.erl ├── rest_hello_h.erl ├── send_message_h.erl ├── set_options_h.erl ├── stop_handler_h.erl ├── stream_handler_h.erl ├── stream_hello_h.erl ├── streamed_result_h.erl ├── switch_handler_h.erl ├── switch_protocol_flush_h.erl ├── ws_active_commands_h.erl ├── ws_deflate_commands_h.erl ├── ws_deflate_opts_h.erl ├── ws_dont_validate_utf8_h.erl ├── ws_handle_commands_h.erl ├── ws_ignore.erl ├── ws_info_commands_h.erl ├── ws_init_commands_h.erl ├── ws_init_h.erl ├── ws_ping_h.erl ├── ws_set_options_commands_h.erl ├── ws_shutdown_reason_commands_h.erl └── ws_terminate_h.erl ├── http2_SUITE.erl ├── http_SUITE.erl ├── http_perf_SUITE.erl ├── loop_handler_SUITE.erl ├── metrics_SUITE.erl ├── misc_SUITE.erl ├── plain_handler_SUITE.erl ├── proxy_header_SUITE.erl ├── req_SUITE.erl ├── rest_handler_SUITE.erl ├── rfc6585_SUITE.erl ├── rfc7230_SUITE.erl ├── rfc7231_SUITE.erl ├── rfc7538_SUITE.erl ├── rfc7540_SUITE.erl ├── rfc8297_SUITE.erl ├── rfc8441_SUITE.erl ├── rfc9114_SUITE.erl ├── rfc9114_SUITE_data ├── client.key ├── client.pem ├── server.key └── server.pem ├── rfc9204_SUITE.erl ├── rfc9220_SUITE.erl ├── security_SUITE.erl ├── static_handler_SUITE.erl ├── static_handler_SUITE_data └── static_files_app.ez ├── stream_handler_SUITE.erl ├── sys_SUITE.erl ├── tracer_SUITE.erl ├── ws_SUITE.erl ├── ws_SUITE_data ├── ws_echo.erl ├── ws_echo_timer.erl ├── ws_init_shutdown.erl ├── ws_max_frame_size.erl ├── ws_send_many.erl ├── ws_subprotocol.erl ├── ws_timeout_cancel.erl └── ws_timeout_hibernate.erl ├── ws_autobahn_SUITE.erl ├── ws_autobahn_SUITE_data └── client.json ├── ws_handler_SUITE.erl ├── ws_perf_SUITE.erl └── ws_perf_SUITE_data ├── ascii.txt ├── grok_segond.txt └── japanese.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Don't include Erlang.mk in diffs. 2 | erlang.mk -diff 3 | 4 | # Don't change line endings in our test data on Windows. 5 | test/ws_perf_SUITE_data/*.txt -text 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | ## Use workflows from ninenines/ci.erlang.mk to test Cowboy. 2 | 3 | name: Check Cowboy 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | schedule: 11 | ## Every Monday at 2am. 12 | - cron: 0 2 * * 1 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | cleanup-master: 20 | name: Cleanup master build 21 | runs-on: ubuntu-latest 22 | if: ${{ github.event_name == 'schedule' }} 23 | permissions: 24 | actions: write 25 | steps: 26 | 27 | - name: Cleanup master build if necessary 28 | run: | 29 | gh cache delete Linux-X64-Erlang-master -R $REPO || true 30 | gh cache delete macOS-ARM64-Erlang-master -R $REPO || true 31 | env: 32 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | REPO: ${{ github.repository }} 34 | 35 | check: 36 | name: Cowboy 37 | needs: cleanup-master 38 | if: ${{ !cancelled() }} 39 | uses: ninenines/ci.erlang.mk/.github/workflows/ci.yaml@master 40 | 41 | # The examples test suite is nice to run but typically not 42 | # important. So we run them after we are done with the other 43 | # test suites. At this point we know that Erlang was built 44 | # so we can just use the latest version. 45 | 46 | examples: 47 | name: Check examples 48 | runs-on: 'ubuntu-latest' 49 | steps: 50 | 51 | - name: Checkout repository 52 | uses: actions/checkout@v4 53 | 54 | - name: Install latest Erlang/OTP 55 | uses: erlef/setup-beam@v1 56 | with: 57 | otp-version: latest 58 | 59 | - name: Run ct-examples 60 | run: make ct-examples 61 | 62 | - name: Upload logs 63 | uses: actions/upload-artifact@v4 64 | if: always() 65 | with: 66 | name: Common Test logs (examples) 67 | path: | 68 | logs/ 69 | !logs/**/log_private 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cowboy.plt 2 | .erlang.mk 3 | _rel 4 | cowboy.d 5 | deps 6 | doc/guide.pdf 7 | doc/html 8 | doc/man3 9 | doc/man7 10 | ebin/*.beam 11 | ebin/test 12 | examples/*/ebin 13 | examples/*/*.d 14 | logs 15 | relx 16 | test/*.beam 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2025, Loïc Hoguin 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.asciidoc: -------------------------------------------------------------------------------- 1 | = Cowboy 2 | 3 | Cowboy is a small, fast and modern HTTP server for Erlang/OTP. 4 | 5 | == Goals 6 | 7 | Cowboy aims to provide a *complete* HTTP stack in a *small* code base. 8 | It is optimized for *low latency* and *low memory usage*, in part 9 | because it uses *binary strings*. 10 | 11 | Cowboy provides *routing* capabilities, selectively dispatching requests 12 | to handlers written in Erlang. 13 | 14 | Because it uses Ranch for managing connections, Cowboy can easily be 15 | *embedded* in any other application. 16 | 17 | Cowboy is *clean* and *well tested* Erlang code. 18 | 19 | == Online documentation 20 | 21 | * https://ninenines.eu/docs/en/cowboy/2.13/guide[User guide] 22 | * https://ninenines.eu/docs/en/cowboy/2.13/manual[Function reference] 23 | 24 | == Offline documentation 25 | 26 | * While still online, run `make docs` 27 | * User guide available in `doc/` in PDF and HTML formats 28 | * Function reference man pages available in `doc/man3/` and `doc/man7/` 29 | * Run `make install-docs` to install man pages on your system 30 | * Full documentation in Asciidoc available in `doc/src/` 31 | * Examples available in `examples/` 32 | 33 | == Getting help 34 | 35 | * https://discord.gg/x25nNq2fFE[Discord server] 36 | * https://github.com/ninenines/cowboy/issues[Issues tracker] 37 | * https://ninenines.eu/services[Commercial Support] 38 | * https://github.com/sponsors/essen[Sponsor me!] 39 | -------------------------------------------------------------------------------- /doc/src/guide/cowboy.sty: -------------------------------------------------------------------------------- 1 | \NeedsTeXFormat{LaTeX2e} 2 | \ProvidesPackage{asciidoc-dblatex}[2012/10/24 AsciiDoc DocBook Style] 3 | 4 | %% Just use the original package and pass the options. 5 | \RequirePackageWithOptions{docbook} 6 | 7 | %% Define an alias for make snippets to be compatible with source-highlighter. 8 | \lstalias{makefile}{make} 9 | -------------------------------------------------------------------------------- /doc/src/guide/http_req_resp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/http_req_resp.png -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_2.11.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Cowboy 2.11 to 2.12 3 | 4 | Cowboy 2.12 contains a small security improvement for 5 | the HTTP/2 protocol. 6 | 7 | Cowboy 2.12 requires Erlang/OTP 24.0 or greater. 8 | 9 | === Features added 10 | 11 | * A new HTTP/2 option `max_fragmented_header_block_size` has 12 | been added to limit the size of header blocks that are 13 | sent over multiple HEADERS and CONTINUATION frames. 14 | 15 | * Update Cowlib to 2.13.0. 16 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_2.8.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Cowboy 2.8 to 2.9 3 | 4 | Cowboy 2.9 implements graceful shutdown of connection 5 | processes for both HTTP/1.1 and HTTP/2 connections. 6 | 7 | Cowboy 2.9 is the first release to support the much 8 | awaited Erlang/OTP 24 out of the box. While users that 9 | were using Ranch 2.0 already were ready for OTP 24, 10 | the Ranch version used by Cowboy out of the box was 11 | not compatible and had to be updated. 12 | 13 | Cowboy 2.9 also contains a small number of tweaks 14 | and bug fixes. 15 | 16 | Cowboy 2.9 requires Erlang/OTP 22.0 or greater. 17 | 18 | === Features added 19 | 20 | * Cowboy will now gracefully shutdown HTTP/1.1 and HTTP/2 21 | connections when the supervisor asks the connection 22 | process to exit, or when `sys:terminate/2,3` is used. 23 | Two new configuration options were added for HTTP/2 24 | to determine the timeouts for the graceful shutdown 25 | steps. 26 | 27 | * REST handler `AcceptCallback` can now return `{created, URI}` 28 | or `{see_other, URI}` to determine what response status code 29 | should be sent (typically to differentiate between a new 30 | resource and an update). The return value `{true, URI}` is 31 | now deprecated. 32 | 33 | * Update Ranch to 1.8.0. 34 | 35 | * Update Cowlib to 2.11.0. 36 | 37 | === Bugs fixed 38 | 39 | * Fix concurrent body streaming getting stuck with HTTP/2. 40 | The alarm could get into blocking state indefinitely 41 | when two or more request processes were streaming bodies. 42 | 43 | * Fix HTTP/2 rate limiting using the wrong default values 44 | in some cases. 45 | 46 | * Don't produce an error report when the request process 47 | exited normally (`normal` or `shutdown` exit reasons). 48 | 49 | * Fix `cowboy_tracer_h` to support trace messages without 50 | timestamps. 51 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_2.9.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Cowboy 2.9 to 2.10 3 | 4 | Cowboy 2.10 is a maintenance release adding support 5 | for Erlang/OTP 26. The main change is a Cowlib update 6 | to fix a compilation error that only occurs starting 7 | from OTP 26. 8 | 9 | Cowboy 2.10 requires Erlang/OTP 22.0 or greater. 10 | 11 | === Features added 12 | 13 | * Add support for `Default` value of SameSite 14 | cookie attribute. 15 | 16 | * Add support for the `stale-*` cache-control directives 17 | from RFC 5861. 18 | 19 | * Update Cowlib to 2.12.1. 20 | 21 | === Bugs fixed 22 | 23 | * Fix a compilation error in Cowlib when using Erlang/OTP 26. 24 | 25 | * Fix data sent after RST_STREAM in HTTP/2 in rare cases. 26 | 27 | * Fix parsing of RST_STREAM frames to properly handle 28 | frames that have a valid length but were not fully 29 | received yet. 30 | 31 | * Remove the obsolete `Version` cookie attribute. 32 | 33 | * Handle more edge cases for cookie parsing based on updates 34 | to the RFC 6265bis draft. 35 | 36 | * Make Basic auth parsing ignore unknown authentication 37 | parameters and generally update the code to conform 38 | to RFC 7617. 39 | 40 | * Fix URI template reserved expansion of %-encoded. 41 | 42 | * Update structured headers implementation to RFC 8941. 43 | -------------------------------------------------------------------------------- /doc/src/guide/performance.asciidoc: -------------------------------------------------------------------------------- 1 | [[performance]] 2 | == Performance 3 | 4 | This chapter describes the performance characteristics 5 | of Cowboy and offers suggestions to get the most 6 | performance out of your application. 7 | 8 | === One process per connection 9 | 10 | The first version of Cowboy featured a single process 11 | per connection, whereas the current version of Cowboy 12 | features one process per connection plus one process 13 | per request. This has a negative impact on performance, 14 | but is necessary in order to provide a common interface 15 | for both HTTP/1.1 and HTTP/2 (as well as future HTTP 16 | versions). 17 | 18 | It is still possible to use a single process per 19 | connection, and avoid the creation of additional 20 | processes for each request, by implementing a 21 | stream handler to process the requests. This can 22 | be done for all requests, or just for a single 23 | endpoint depending on the application's needs. 24 | 25 | Stream handlers provide an asynchronous interface 26 | and must not block, so the implementation will 27 | be very different from normal Cowboy handlers, 28 | but the performance gains are important enough 29 | to justify it in some cases. 30 | -------------------------------------------------------------------------------- /doc/src/guide/rest_cond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_cond.png -------------------------------------------------------------------------------- /doc/src/guide/rest_conneg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_conneg.png -------------------------------------------------------------------------------- /doc/src/guide/rest_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_delete.png -------------------------------------------------------------------------------- /doc/src/guide/rest_get_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_get_head.png -------------------------------------------------------------------------------- /doc/src/guide/rest_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_options.png -------------------------------------------------------------------------------- /doc/src/guide/rest_put_post_patch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_put_post_patch.png -------------------------------------------------------------------------------- /doc/src/guide/rest_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/doc/src/guide/rest_start.png -------------------------------------------------------------------------------- /doc/src/manual/cowboy.get_env.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy:get_env(3) 2 | 3 | == Name 4 | 5 | cowboy:get_env - Retrieve a listener's environment value 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_env(Name :: ranch:ref(), 12 | Key :: atom()) 13 | -> any() 14 | 15 | get_env(Name :: ranch:ref(), 16 | Key :: atom(), 17 | Default :: any()) 18 | -> any() 19 | ---- 20 | 21 | Retrieve an environment value for a previously started 22 | listener. 23 | 24 | This function may crash when the key is missing from the 25 | environment and a default value is not provided. 26 | 27 | == Arguments 28 | 29 | Name:: 30 | 31 | The name of the listener to access. 32 | + 33 | The name of the listener is the first argument given to the 34 | link:man:cowboy:start_clear(3)[cowboy:start_clear(3)], 35 | link:man:cowboy:start_tls(3)[cowboy:start_tls(3)] or 36 | link:man:ranch:start_listener(3)[ranch:start_listener(3)] function. 37 | 38 | Key:: 39 | 40 | The key in the environment map. Common keys include `dispatch` 41 | and `middlewares`. 42 | 43 | Default:: 44 | 45 | The default value if the key is missing. 46 | 47 | == Return value 48 | 49 | The environment value is returned on success. 50 | 51 | If a default was provided and the key is missing, then the 52 | default value is returned. 53 | 54 | An `exit:badarg` exception is thrown when the listener does 55 | not exist. 56 | 57 | An `exit:{badkey, Key}` exception is thrown when the key 58 | requested is missing and no default was provided. 59 | 60 | == Changelog 61 | 62 | * *2.11*: Function introduced. 63 | 64 | == Examples 65 | 66 | .Retrieve a listener's routes 67 | [source,erlang] 68 | ---- 69 | Dispatch = cowboy:get_env(example, dispatch). 70 | ---- 71 | 72 | == See also 73 | 74 | link:man:cowboy(3)[cowboy(3)], 75 | link:man:cowboy:start_clear(3)[cowboy:start_clear(3)], 76 | link:man:cowboy:start_tls(3)[cowboy:start_tls(3)], 77 | link:man:cowboy:set_env(3)[cowboy:set_env(3)], 78 | link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)] 79 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy.set_env.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy:set_env(3) 2 | 3 | == Name 4 | 5 | cowboy:set_env - Update a listener's environment value 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | set_env(Name :: ranch:ref(), 12 | Key :: atom(), 13 | Value :: any()) 14 | -> ok 15 | ---- 16 | 17 | Set or update an environment value for a previously started 18 | listener. 19 | 20 | This is most useful for updating the routes dynamically, 21 | without having to restart the listener. 22 | 23 | The new value will only be available to new connections. 24 | Pre-existing connections will still use the old value. 25 | 26 | == Arguments 27 | 28 | Name:: 29 | 30 | The name of the listener to update. 31 | + 32 | The name of the listener is the first argument given to the 33 | link:man:cowboy:start_clear(3)[cowboy:start_clear(3)], 34 | link:man:cowboy:start_tls(3)[cowboy:start_tls(3)] or 35 | link:man:ranch:start_listener(3)[ranch:start_listener(3)] function. 36 | 37 | Key:: 38 | 39 | The key in the environment map. Common keys include `dispatch` 40 | and `middlewares`. 41 | 42 | Value:: 43 | 44 | The new value. 45 | + 46 | The type of the value differs depending on the key. 47 | 48 | == Return value 49 | 50 | The atom `ok` is returned on success. 51 | 52 | An `exit:badarg` exception is thrown when the listener does 53 | not exist. 54 | 55 | == Changelog 56 | 57 | * *1.0*: Function introduced. 58 | 59 | == Examples 60 | 61 | .Update a listener's routes 62 | [source,erlang] 63 | ---- 64 | Dispatch = cowboy_router:compile([ 65 | {'_', [ 66 | {"/", toppage_h, []}, 67 | {"/ws", websocket_h, []} 68 | ]} 69 | ]), 70 | 71 | cowboy:set_env(example, dispatch, Dispatch). 72 | ---- 73 | 74 | == See also 75 | 76 | link:man:cowboy(3)[cowboy(3)], 77 | link:man:cowboy:start_clear(3)[cowboy:start_clear(3)], 78 | link:man:cowboy:start_tls(3)[cowboy:start_tls(3)], 79 | link:man:cowboy:get_env(3)[cowboy:get_env(3)], 80 | link:man:ranch:set_protocol_options(3)[ranch:set_protocol_options(3)] 81 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy.stop_listener.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy:stop_listener(3) 2 | 3 | == Name 4 | 5 | cowboy:stop_listener - Stop the given listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | stop_listener(Name :: ranch:ref()) 12 | -> ok | {error, not_found}. 13 | ---- 14 | 15 | Stop a previously started listener. 16 | 17 | Alias of link:man:ranch:stop_listener(3)[ranch:stop_listener(3)]. 18 | 19 | == Arguments 20 | 21 | Name:: 22 | 23 | The name of the listener to be stopped. 24 | + 25 | The name of the listener is the first argument given to the 26 | link:man:cowboy:start_clear(3)[cowboy:start_clear(3)], 27 | link:man:cowboy:start_tls(3)[cowboy:start_tls(3)] or 28 | link:man:ranch:start_listener(3)[ranch:start_listener(3)] function. 29 | 30 | == Return value 31 | 32 | The atom `ok` is returned on success. 33 | 34 | The `{error, not_found}` tuple is returned when the listener 35 | does not exist. 36 | 37 | == Changelog 38 | 39 | * *1.0*: Function introduced. 40 | 41 | == Examples 42 | 43 | .Stop a listener 44 | [source,erlang] 45 | ---- 46 | ok = cowboy:stop_listener(example). 47 | ---- 48 | 49 | == See also 50 | 51 | link:man:cowboy(3)[cowboy(3)], 52 | link:man:cowboy:start_clear(3)[cowboy:start_clear(3)], 53 | link:man:cowboy:start_tls(3)[cowboy:start_tls(3)], 54 | link:man:ranch(3)[ranch(3)], 55 | link:man:ranch:start_listener(3)[ranch:start_listener(3)] 56 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_constraints.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_constraints(3) 2 | 3 | == Name 4 | 5 | cowboy_constraints - Constraints 6 | 7 | == Description 8 | 9 | The module `cowboy_constraints` defines the built-in 10 | constraints in Cowboy and provides an interface for 11 | manipulating these constraints. 12 | 13 | Constraints are functions that define what type of 14 | input is allowed. They are used throughout Cowboy, 15 | from the router to query strings to cookies. 16 | 17 | == Exports 18 | 19 | Built-in constraints: 20 | 21 | * link:man:cowboy_constraints:int(3)[cowboy_constraints:int(3)] - Integer constraint 22 | * link:man:cowboy_constraints:nonempty(3)[cowboy_constraints:nonempty(3)] - Non-empty constraint 23 | 24 | == Types 25 | 26 | === constraint() 27 | 28 | [source,erlang] 29 | ---- 30 | constraint() :: int | nonempty | fun() 31 | ---- 32 | 33 | A constraint function. 34 | 35 | The atom constraints are built-in, see the corresponding 36 | function in the exports list above. 37 | 38 | === reason() 39 | 40 | [source,erlang] 41 | ---- 42 | reason() :: {constraint(), Reason, Value} 43 | 44 | Reason :: any() 45 | Value :: any() 46 | ---- 47 | 48 | Reason for the constraint failure. 49 | 50 | It includes the constraint function in question, 51 | a machine-readable error reason and the value that 52 | made the constraint fail. 53 | 54 | == See also 55 | 56 | link:man:cowboy(7)[cowboy(7)], 57 | link:man:cowboy(3)[cowboy(3)], 58 | link:man:cowboy_router(3)[cowboy_router(3)], 59 | link:man:cowboy_req:match_cookies(3)[cowboy_req:match_cookies(3)], 60 | link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] 61 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_constraints.int.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_constraints:int(3) 2 | 3 | == Name 4 | 5 | cowboy_constraints:int - Integer constraint 6 | 7 | == Description 8 | 9 | Constraint functions implement a number of different operations. 10 | 11 | [source,erlang] 12 | ---- 13 | int(forward, Bin) -> {ok, Int} | {error, not_an_integer} 14 | 15 | Bin :: binary() 16 | Int :: integer() 17 | ---- 18 | 19 | Validate and convert the text representation of an integer. 20 | 21 | [source,erlang] 22 | ---- 23 | int(reverse, Int) -> {ok, Bin} | {error, not_an_integer} 24 | ---- 25 | 26 | Convert an integer back to its text representation. 27 | 28 | [source,erlang] 29 | ---- 30 | int(format_error, Error) -> HumanReadable 31 | 32 | Error :: {not_an_integer, Bin | Int} 33 | HumanReadable :: iolist() 34 | ---- 35 | 36 | Generate a human-readable error message. 37 | 38 | == Arguments 39 | 40 | Arguments vary depending on the operation. Constraint 41 | functions always take the operation type as first argument, 42 | and the value as second argument. 43 | 44 | == Return value 45 | 46 | The return value varies depending on the operation. 47 | 48 | == Changelog 49 | 50 | * *2.0*: Interface modified to allow for a variety of operations. 51 | * *1.0*: Constraint introduced. 52 | 53 | == Examples 54 | 55 | This function is not meant to be called directly. 56 | 57 | == See also 58 | 59 | link:man:cowboy_constraints(3)[cowboy_constraints(3)], 60 | link:man:cowboy_constraints:nonempty(3)[cowboy_constraints:nonempty(3)], 61 | link:man:cowboy_router(3)[cowboy_router(3)], 62 | link:man:cowboy_req:match_cookies(3)[cowboy_req:match_cookies(3)], 63 | link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] 64 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_constraints.nonempty.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_constraints:nonempty(3) 2 | 3 | == Name 4 | 5 | cowboy_constraints:nonempty - Non-empty constraint 6 | 7 | == Description 8 | 9 | Constraint functions implement a number of different operations. 10 | 11 | [source,erlang] 12 | ---- 13 | nonempty(forward | reverse, <<>>) -> {error, empty} 14 | ---- 15 | 16 | Reject empty values. 17 | 18 | [source,erlang] 19 | ---- 20 | nonempty(forward | reverse, Bin) -> {ok, Bin} 21 | 22 | Bin :: binary() 23 | ---- 24 | 25 | Accept any other binary values. 26 | 27 | [source,erlang] 28 | ---- 29 | nonempty(format_error, Error) -> HumanReadable 30 | 31 | Error :: {empty, Bin} 32 | HumanReadable :: iolist() 33 | ---- 34 | 35 | Generate a human-readable error message. 36 | 37 | == Arguments 38 | 39 | Arguments vary depending on the operation. Constraint 40 | functions always take the operation type as first argument, 41 | and the value as second argument. 42 | 43 | == Return value 44 | 45 | The return value varies depending on the operation. 46 | 47 | == Changelog 48 | 49 | * *2.0*: Interface modified to allow for a variety of operations. 50 | * *1.0*: Constraint introduced. 51 | 52 | == Examples 53 | 54 | This function is not meant to be called directly. 55 | 56 | == See also 57 | 58 | link:man:cowboy_constraints(3)[cowboy_constraints(3)], 59 | link:man:cowboy_constraints:int(3)[cowboy_constraints:int(3)], 60 | link:man:cowboy_router(3)[cowboy_router(3)], 61 | link:man:cowboy_req:match_cookies(3)[cowboy_req:match_cookies(3)], 62 | link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] 63 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_decompress_h.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_decompress_h(3) 2 | 3 | == Name 4 | 5 | cowboy_decompress_h - Decompress stream handler 6 | 7 | == Description 8 | 9 | The module `cowboy_decompress_h` decompresses request bodies 10 | automatically when the server supports it. 11 | 12 | The only compression algorithm currently supported is the 13 | gzip algorithm. Another limitation is that decompression 14 | is only attempted when gzip is the only content-encoding 15 | in the request. 16 | 17 | This stream handler always adds a field to the Req object 18 | with the name `content_decoded` which is treated as a 19 | list of decoded content-encoding values. Currently this 20 | list may only contain the `<<"gzip">>` binary if content 21 | was decoded; or be empty otherwise. 22 | 23 | == Options 24 | 25 | [source,erlang] 26 | ---- 27 | opts() :: #{ 28 | decompress_enabled => boolean(), 29 | decompress_ratio_limit => non_neg_integer() 30 | } 31 | ---- 32 | 33 | Configuration for the decompress stream handler. 34 | 35 | The default value is given next to the option name: 36 | 37 | decompress_ratio_limit (20):: 38 | The max ratio of the compressed and decompressed body 39 | before it is rejected with a `413 Payload Too Large` 40 | error response. 41 | + 42 | This option can be updated at any time using the 43 | `set_options` stream handler command. 44 | 45 | decompress_enabled (true):: 46 | 47 | Whether the handler is enabled by default. 48 | + 49 | This option can be updated using the `set_options` 50 | stream handler command. This allows disabling 51 | decompression for the current stream. Attempts 52 | to enable or disable decompression after starting 53 | to read the body will be ignored. 54 | 55 | == Events 56 | 57 | The decompress stream handler does not produce any event. 58 | 59 | == Changelog 60 | 61 | * *2.11*: Module introduced. 62 | 63 | == See also 64 | 65 | link:man:cowboy(7)[cowboy(7)], 66 | link:man:cowboy_stream(3)[cowboy_stream(3)], 67 | link:man:cowboy_compress_h(3)[cowboy_compress_h(3)], 68 | link:man:cowboy_metrics_h(3)[cowboy_metrics_h(3)], 69 | link:man:cowboy_stream_h(3)[cowboy_stream_h(3)], 70 | link:man:cowboy_tracer_h(3)[cowboy_tracer_h(3)] 71 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_handler.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_handler(3) 2 | 3 | == Name 4 | 5 | cowboy_handler - Plain HTTP handlers 6 | 7 | == Description 8 | 9 | The `cowboy_handler` middleware executes the handler selected 10 | by the router or any other preceding middleware. 11 | 12 | This middleware takes the handler module and initial state 13 | from the `handler` and `handler_opts` environment values, 14 | respectively. On completion, it adds a `result` value to 15 | the middleware environment, containing the return value 16 | of the `terminate/3` callback (if defined) and `ok` otherwise. 17 | 18 | This module also defines a callback interface for handling 19 | HTTP requests. 20 | 21 | == Callbacks 22 | 23 | Plain HTTP handlers implement the following interface: 24 | 25 | [source,erlang] 26 | ---- 27 | init(Req, State) -> {ok, Req, State} 28 | 29 | terminate(Reason, Req, State) -> ok %% optional 30 | 31 | Req :: cowboy_req:req() 32 | State :: any() 33 | Reason :: normal 34 | | {crash, error | exit | throw, any()} 35 | ---- 36 | 37 | These two callbacks are common to all handlers. 38 | 39 | Plain HTTP handlers do all their work in the `init/2` 40 | callback. Returning `ok` terminates the handler. If no 41 | response is sent, Cowboy will send a `204 No Content`. 42 | 43 | The optional `terminate/3` callback will ultimately be called 44 | with the reason for the termination of the handler. 45 | Cowboy will terminate the process right after this. There 46 | is no need to perform any cleanup in this callback. 47 | 48 | The following terminate reasons are defined for plain HTTP 49 | handlers: 50 | 51 | normal:: 52 | The connection was closed normally. 53 | 54 | {crash, Class, Reason}:: 55 | A crash occurred in the handler. `Class` and `Reason` can be 56 | used to obtain more information about the crash. 57 | 58 | == Exports 59 | 60 | The following function should be called by modules implementing 61 | custom handlers to execute the optional terminate callback: 62 | 63 | * link:man:cowboy_handler:terminate(3)[cowboy_handler:terminate(3)] - Terminate the handler 64 | 65 | == See also 66 | 67 | link:man:cowboy(7)[cowboy(7)] 68 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_handler.terminate.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_handler:terminate(3) 2 | 3 | == Name 4 | 5 | cowboy_handler:terminate - Terminate the handler 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | terminate(Reason, PartialReq, State, Handler) -> ok 12 | 13 | Reason :: any() 14 | PartialReq :: map() 15 | State :: any() 16 | Handler :: module() 17 | ---- 18 | 19 | Call the optional terminate callback if it is defined. 20 | 21 | Make sure to use this function at the end of the execution 22 | of modules that implement custom handler behaviors. 23 | 24 | == Arguments 25 | 26 | Reason:: 27 | 28 | Reason for termination. 29 | 30 | PartialReq:: 31 | 32 | The Req object. 33 | + 34 | It is possible to remove fields from the Req object to save memory 35 | when the handler has no concept of requests/responses. The only 36 | requirement is that a map is provided. 37 | 38 | State:: 39 | 40 | Handler state. 41 | 42 | Handler:: 43 | 44 | Handler module. 45 | 46 | == Return value 47 | 48 | The atom `ok` is always returned. It can be safely ignored. 49 | 50 | == Changelog 51 | 52 | * *2.0*: Function introduced. 53 | 54 | == Examples 55 | 56 | .Terminate a handler normally 57 | [source,erlang] 58 | ---- 59 | cowboy_handler:terminate(normal, Req, State, Handler). 60 | ---- 61 | 62 | == See also 63 | 64 | link:man:cowboy_handler(3)[cowboy_handler(3)] 65 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_middleware.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_middleware(3) 2 | 3 | == Name 4 | 5 | cowboy_middleware - Middlewares 6 | 7 | == Description 8 | 9 | The module `cowboy_middleware` defines a callback interface for 10 | Cowboy middlewares. 11 | 12 | Middlewares process the request sequentially in the order they 13 | are configured. 14 | 15 | == Callbacks 16 | 17 | Middlewares implement the following interface: 18 | 19 | [source,erlang] 20 | ---- 21 | execute(Req, Env) 22 | -> {ok, Req, Env} 23 | | {suspend, module(), atom(), [any()]} 24 | | {stop, Req} 25 | 26 | Req :: cowboy_req:req() 27 | Env :: cowboy_middleware:env() 28 | ---- 29 | 30 | The `execute/2` is the only callback that needs to be 31 | implemented. It must execute the middleware and return 32 | with instructions for Cowboy. 33 | 34 | ok:: 35 | 36 | Cowboy should continue processing the request using the 37 | returned Req object and environment. 38 | 39 | suspend:: 40 | 41 | Cowboy will hibernate the process. When resuming, Cowboy 42 | will apply the returned module, function and arguments. 43 | 44 | stop:: 45 | 46 | Cowboy will stop middleware execution. No other middleware 47 | will be executed. This effectively ends the processing of 48 | the request. 49 | 50 | // @todo No need to return the Req when stopping. Fix in 3.0. 51 | 52 | == Types 53 | 54 | === env() 55 | 56 | [source,erlang] 57 | ---- 58 | env() :: #{atom() => any()} 59 | ---- 60 | 61 | Middleware environment. 62 | 63 | A new environment is created for every request. The initial 64 | environment contained the user configured environment values 65 | (like `dispatch` for example) plus the `listener` value which 66 | contains the name of the listener for this connection. 67 | 68 | Middlewares may modify the environment as necessary. 69 | 70 | == Changelog 71 | 72 | * *2.0*: The `env` type is now a map instead of a proplist. 73 | * *1.0*: Behavior introduced. 74 | 75 | == See also 76 | 77 | link:man:cowboy(7)[cowboy(7)] 78 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.binding.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:binding(3) 2 | 3 | == Name 4 | 5 | cowboy_req:binding - Access a value bound from the route 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | binding(Name, Req) -> binding(Name, Req, undefined) 12 | binding(Name, Req, Default) -> any() | Default 13 | 14 | Name :: atom() 15 | Req :: cowboy_req:req() 16 | Default :: any() 17 | ---- 18 | 19 | Return the value for the given binding. 20 | 21 | == Arguments 22 | 23 | Name:: 24 | 25 | Desired binding name as an atom. 26 | 27 | Req:: 28 | 29 | The Req object. 30 | 31 | Default:: 32 | 33 | Default value returned when the binding is missing. 34 | 35 | == Return value 36 | 37 | By default the value is a case sensitive binary string, however 38 | constraints may change the type of this value (for example 39 | automatically converting numbers to integer). 40 | 41 | == Changelog 42 | 43 | * *2.0*: Only the value is returned, it is no longer wrapped in a tuple. 44 | * *1.0*: Function introduced. 45 | 46 | == Examples 47 | 48 | .Get the username from the path 49 | [source,erlang] 50 | ---- 51 | %% Route is "/users/:user" 52 | Username = cowboy_req:binding(user, Req). 53 | ---- 54 | 55 | .Get the branch name, with a default 56 | [source,erlang] 57 | ---- 58 | %% Route is "/log[/:branch]" 59 | Branch = cowboy_req:binding(branch, Req, <<"master">>) 60 | ---- 61 | 62 | == See also 63 | 64 | link:man:cowboy_req(3)[cowboy_req(3)], 65 | link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], 66 | link:man:cowboy_req:host_info(3)[cowboy_req:host_info(3)], 67 | link:man:cowboy_req:path_info(3)[cowboy_req:path_info(3)], 68 | link:man:cowboy_router(3)[cowboy_router(3)] 69 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.bindings.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:bindings(3) 2 | 3 | == Name 4 | 5 | cowboy_req:bindings - Access all values bound from the route 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | bindings(Req :: cowboy_req:req()) -> cowboy_router:bindings() 12 | ---- 13 | 14 | Return a map containing all bindings. 15 | 16 | == Arguments 17 | 18 | Req:: 19 | 20 | The Req object. 21 | 22 | == Return value 23 | 24 | By default values are case sensitive binary strings, however 25 | constraints may change the type of this value (for example 26 | automatically converting numbers to integer). 27 | 28 | == Changelog 29 | 30 | * *2.0*: Only the values are returned, they are no longer wrapped in a tuple. 31 | * *1.0*: Function introduced. 32 | 33 | == Examples 34 | 35 | .Get all bindings 36 | [source,erlang] 37 | ---- 38 | Bindings = cowboy_req:bindings(Req). 39 | ---- 40 | 41 | == See also 42 | 43 | link:man:cowboy_req(3)[cowboy_req(3)], 44 | link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], 45 | link:man:cowboy_req:host_info(3)[cowboy_req:host_info(3)], 46 | link:man:cowboy_req:path_info(3)[cowboy_req:path_info(3)], 47 | link:man:cowboy_router(3)[cowboy_router(3)] 48 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.body_length.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:body_length(3) 2 | 3 | == Name 4 | 5 | cowboy_req:body_length - Body length 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | body_length(Req :: cowboy_req:req()) -> undefined | non_neg_integer() 12 | ---- 13 | 14 | Return the length of the request body. 15 | 16 | The length is not always known before reading the body. 17 | In those cases Cowboy will return `undefined`. The body 18 | length is available after the body has been fully read. 19 | 20 | == Arguments 21 | 22 | Req:: 23 | 24 | The Req object. 25 | 26 | == Return value 27 | 28 | The length of the request body, or `undefined` if it is 29 | not known. 30 | 31 | == Changelog 32 | 33 | * *2.0*: Only the length is returned, it is no longer wrapped in a tuple. 34 | * *1.0*: Function introduced. 35 | 36 | == Examples 37 | 38 | .Get the body length 39 | [source,erlang] 40 | ---- 41 | Length = cowboy_req:body_length(Req). 42 | ---- 43 | 44 | == See also 45 | 46 | link:man:cowboy_req(3)[cowboy_req(3)], 47 | link:man:cowboy_req:has_body(3)[cowboy_req:has_body(3)], 48 | link:man:cowboy_req:read_body(3)[cowboy_req:read_body(3)], 49 | link:man:cowboy_req:read_urlencoded_body(3)[cowboy_req:read_urlencoded_body(3)], 50 | link:man:cowboy_req:read_part(3)[cowboy_req:read_part(3)], 51 | link:man:cowboy_req:read_part_body(3)[cowboy_req:read_part_body(3)] 52 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.cast.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:cast(3) 2 | 3 | == Name 4 | 5 | cowboy_req:cast - Cast a stream handler event 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | cast(Event :: any(), Req :: cowboy_req:req()) -> ok 12 | ---- 13 | 14 | Cast a stream handler event. 15 | 16 | The event will be passed to stream handlers through the 17 | `info/3` callback. 18 | 19 | == Arguments 20 | 21 | Event:: 22 | 23 | The event to be sent to stream handlers. 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The atom `ok` is always returned. It can be safely ignored. 32 | 33 | == Changelog 34 | 35 | * *2.7*: Function introduced. 36 | 37 | == Examples 38 | 39 | .Read the body using auto mode 40 | [source,erlang] 41 | ---- 42 | read_body_auto_async(Req) -> 43 | read_body_auto_async(Req, make_ref(), <<>>). 44 | 45 | read_body_auto_async(Req, Ref, Acc) -> 46 | cowboy_req:cast({read_body, self(), Ref, auto, infinity}, Req), 47 | receive 48 | {request_body, Ref, nofin, Data} -> 49 | read_body_auto_async(Req, Ref, <>); 50 | {request_body, Ref, fin, _BodyLen, Data} -> 51 | {ok, <>, Req} 52 | end. 53 | ---- 54 | 55 | .Increase the HTTP/1.1 idle timeout 56 | [source,erlang] 57 | ---- 58 | cowboy_req:cast({set_options, #{ 59 | idle_timeout => 3600000 60 | }}, Req). 61 | ---- 62 | 63 | .Add user data to metrics 64 | ---- 65 | cowboy_req:cast({set_options, #{ 66 | metrics_user_data => #{handler => ?MODULE} 67 | }}, Req). 68 | ---- 69 | 70 | .Enable compression buffering 71 | ---- 72 | cowboy_req:cast({set_options, #{ 73 | compress_buffering => true 74 | }}, Req). 75 | ---- 76 | 77 | == See also 78 | 79 | link:man:cowboy_req(3)[cowboy_req(3)], 80 | link:man:cowboy_stream(3)[cowboy_stream(3)] 81 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.cert.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:cert(3) 2 | 3 | == Name 4 | 5 | cowboy_req:cert - Client TLS certificate 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | cert(Req :: cowboy_req:req()) -> binary() | undefined 12 | ---- 13 | 14 | Return the peer's TLS certificate. 15 | 16 | Using the default configuration this function will always return 17 | `undefined`. You need to explicitly configure Cowboy to request 18 | the client certificate. To do this you need to set the `verify` 19 | transport option to `verify_peer`: 20 | 21 | [source,erlang] 22 | ---- 23 | {ok, _} = cowboy:start_tls(example, [ 24 | {port, 8443}, 25 | {certfile, "path/to/cert.pem"}, 26 | {verify, verify_peer} 27 | ], #{ 28 | env => #{dispatch => Dispatch} 29 | }). 30 | ---- 31 | 32 | You may also want to customize the `verify_fun` function. Please 33 | consult the `ssl` application's manual for more details. 34 | 35 | TCP connections do not allow a certificate and this function 36 | will therefore always return `undefined`. 37 | 38 | The certificate can also be obtained using pattern matching: 39 | 40 | [source,erlang] 41 | ---- 42 | #{cert := Cert} = Req. 43 | ---- 44 | 45 | == Arguments 46 | 47 | Req:: 48 | 49 | The Req object. 50 | 51 | == Return value 52 | 53 | The client TLS certificate. 54 | 55 | == Changelog 56 | 57 | * *2.1*: Function introduced. 58 | 59 | == Examples 60 | 61 | .Get the client TLS certificate. 62 | [source,erlang] 63 | ---- 64 | Cert = cowboy_req:cert(Req). 65 | ---- 66 | 67 | == See also 68 | 69 | link:man:cowboy_req(3)[cowboy_req(3)], 70 | link:man:cowboy_req:peer(3)[cowboy_req:peer(3)], 71 | link:man:cowboy_req:sock(3)[cowboy_req:sock(3)] 72 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.delete_resp_header.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:delete_resp_header(3) 2 | 3 | == Name 4 | 5 | cowboy_req:delete_resp_header - Delete a response header 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | delete_resp_header(Name, Req :: cowboy_req:req()) -> Req 12 | 13 | Name :: binary() %% lowercase; case insensitive 14 | ---- 15 | 16 | Delete the given response header. 17 | 18 | The header name must be given as a lowercase binary string. 19 | While header names are case insensitive, Cowboy requires them 20 | to be given as lowercase to function properly. 21 | 22 | == Arguments 23 | 24 | Name:: 25 | 26 | Header name as a lowercase binary string. 27 | 28 | Req:: 29 | 30 | The Req object. 31 | 32 | == Return value 33 | 34 | A new Req object is returned. 35 | 36 | The returned Req object must be used from that point onward, 37 | otherwise the header will still be sent in the response. 38 | 39 | == Changelog 40 | 41 | * *1.0*: Function introduced. 42 | 43 | == Examples 44 | 45 | .Remove the content-type header from the response 46 | [source,erlang] 47 | ---- 48 | Req = cowboy_req:delete_resp_header(<<"content-type">>, Req0), 49 | ---- 50 | 51 | == See also 52 | 53 | link:man:cowboy_req(3)[cowboy_req(3)], 54 | link:man:cowboy_req:set_resp_header(3)[cowboy_req:set_resp_header(3)], 55 | link:man:cowboy_req:set_resp_headers(3)[cowboy_req:set_resp_headers(3)], 56 | link:man:cowboy_req:has_resp_header(3)[cowboy_req:has_resp_header(3)], 57 | link:man:cowboy_req:resp_header(3)[cowboy_req:resp_header(3)], 58 | link:man:cowboy_req:resp_headers(3)[cowboy_req:resp_headers(3)] 59 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.filter_cookies.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:filter_cookies(3) 2 | 3 | == Name 4 | 5 | cowboy_req:filter_cookies - Filter cookie headers 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | filter_cookies(Names, Req) -> Req 12 | 13 | Names :: [atom() | binary()] 14 | ---- 15 | 16 | Filter cookie headers. 17 | 18 | This function is meant to be used before attempting to parse 19 | or match cookies in order to remove cookies that are not 20 | relevant and are potentially malformed. Because Cowboy by 21 | default crashes on malformed cookies, this function allows 22 | processing requests that would otherwise result in a 400 23 | error. 24 | 25 | Malformed cookies are unfortunately fairly common due to 26 | the string-based interface provided by browsers and this 27 | function provides a middle ground between Cowboy's strict 28 | behavior and chaotic real world use cases. 29 | 30 | Note that there may still be crashes even after filtering 31 | cookies because this function does not correct malformed 32 | values. Cookies that have malformed values should probably 33 | be unset in an error response or in a redirect. 34 | 35 | This function can be called even if there are no cookies 36 | in the request. 37 | 38 | == Arguments 39 | 40 | Names:: 41 | 42 | The cookies that should be kept. 43 | 44 | Req:: 45 | 46 | The Req object. 47 | 48 | == Return value 49 | 50 | The Req object is returned with its cookie header value 51 | filtered. 52 | 53 | == Changelog 54 | 55 | * *2.7*: Function introduced. 56 | 57 | == Examples 58 | 59 | .Filter then parse cookies 60 | [source,erlang] 61 | ---- 62 | Req = cowboy_req:filter_cookies([session_id, token], Req0), 63 | Cookies = cowboy_req:parse_cookies(Req). 64 | ---- 65 | 66 | == See also 67 | 68 | link:man:cowboy_req(3)[cowboy_req(3)], 69 | link:man:cowboy_req:parse_cookies(3)[cowboy_req:parse_cookies(3)], 70 | link:man:cowboy_req:match_cookies(3)[cowboy_req:match_cookies(3)] 71 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.has_body.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:has_body(3) 2 | 3 | == Name 4 | 5 | cowboy_req:has_body - Is there a request body? 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | has_body(Req :: cowboy_req:req()) -> boolean() 12 | ---- 13 | 14 | Return whether the request has a body. 15 | 16 | == Arguments 17 | 18 | Req:: 19 | 20 | The Req object. 21 | 22 | == Return value 23 | 24 | A boolean indicating whether the request has a body. 25 | 26 | == Changelog 27 | 28 | * *1.0*: Function introduced. 29 | 30 | == Examples 31 | 32 | .Ensure the request has a body 33 | [source,erlang] 34 | ---- 35 | true = cowboy_req:has_body(Req). 36 | ---- 37 | 38 | == See also 39 | 40 | link:man:cowboy_req(3)[cowboy_req(3)], 41 | link:man:cowboy_req:body_length(3)[cowboy_req:body_length(3)], 42 | link:man:cowboy_req:read_body(3)[cowboy_req:read_body(3)], 43 | link:man:cowboy_req:read_urlencoded_body(3)[cowboy_req:read_urlencoded_body(3)], 44 | link:man:cowboy_req:read_part(3)[cowboy_req:read_part(3)], 45 | link:man:cowboy_req:read_part_body(3)[cowboy_req:read_part_body(3)] 46 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.has_resp_body.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:has_resp_body(3) 2 | 3 | == Name 4 | 5 | cowboy_req:has_resp_body - Is there a response body? 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | has_resp_body(Req :: cowboy_req:req()) -> boolean() 12 | ---- 13 | 14 | Return whether a response body has been set. 15 | 16 | == Arguments 17 | 18 | Req:: 19 | 20 | The Req object. 21 | 22 | == Return value 23 | 24 | A boolean indicating whether a response body has been set. 25 | 26 | This function will return `false` when an empty response 27 | body has been set. 28 | 29 | == Changelog 30 | 31 | * *1.0*: Function introduced. 32 | 33 | == Examples 34 | 35 | .Check whether a body has been set 36 | [source,erlang] 37 | ---- 38 | false = cowboy_req:has_resp_body(Req0), 39 | Req1 = cowboy_req:set_resp_body(<<"Hello!">>, Req0), 40 | true = cowboy_req:has_resp_body(Req1), 41 | Req = cowboy_req:set_resp_body(<<>>, Req1), 42 | false = cowboy_req:has_resp_body(Req). 43 | ---- 44 | 45 | == See also 46 | 47 | link:man:cowboy_req(3)[cowboy_req(3)], 48 | link:man:cowboy_req:set_resp_body(3)[cowboy_req:set_resp_body(3)] 49 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.has_resp_header.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:has_resp_header(3) 2 | 3 | == Name 4 | 5 | cowboy_req:has_resp_header - Is the given response header set? 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | has_resp_header(Name, Req :: cowboy_req:req()) -> boolean() 12 | 13 | Name :: binary() %% lowercase; case insensitive 14 | ---- 15 | 16 | Return whether the given response header has been set. 17 | 18 | The header name must be given as a lowercase binary string. 19 | While header names are case insensitive, Cowboy requires them 20 | to be given as lowercase to function properly. 21 | 22 | == Arguments 23 | 24 | Name:: 25 | 26 | Header name as a lowercase binary string. 27 | 28 | Req:: 29 | 30 | The Req object. 31 | 32 | == Return value 33 | 34 | A boolean indicating whether the given response header has been set. 35 | 36 | == Changelog 37 | 38 | * *1.0*: Function introduced. 39 | 40 | == Examples 41 | 42 | .Check whether the content-type header has been set 43 | [source,erlang] 44 | ---- 45 | false = cowboy_req:has_resp_header(<<"content-type">>, Req0), 46 | Req = cowboy_req:set_resp_header(<<"content-type">>, <<"text/html">>, Req0), 47 | true = cowboy_req:has_resp_header(<<"content-type">>, Req). 48 | ---- 49 | 50 | == See also 51 | 52 | link:man:cowboy_req(3)[cowboy_req(3)], 53 | link:man:cowboy_req:set_resp_header(3)[cowboy_req:set_resp_header(3)], 54 | link:man:cowboy_req:set_resp_headers(3)[cowboy_req:set_resp_headers(3)], 55 | link:man:cowboy_req:resp_header(3)[cowboy_req:resp_header(3)], 56 | link:man:cowboy_req:resp_headers(3)[cowboy_req:resp_headers(3)], 57 | link:man:cowboy_req:delete_resp_header(3)[cowboy_req:delete_resp_header(3)] 58 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.header.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:header(3) 2 | 3 | == Name 4 | 5 | cowboy_req:header - HTTP header 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | header(Name, Req) -> header(Name, Req, undefined) 12 | header(Name, Req, Default) -> binary() | Default 13 | 14 | Name :: binary() %% lowercase; case insensitive 15 | Req :: cowboy_req:req() 16 | Default :: any() 17 | ---- 18 | 19 | Return the value for the given HTTP header. 20 | 21 | The header name must be given as a lowercase binary string. 22 | While header names are case insensitive, Cowboy requires them 23 | to be given as lowercase to function properly. 24 | 25 | Headers can also be obtained using pattern matching: 26 | 27 | [source,erlang] 28 | ---- 29 | #{headers := #{Name := Value}} = Req. 30 | ---- 31 | 32 | Note that this snippet will crash if the header is missing. 33 | 34 | == Arguments 35 | 36 | Name:: 37 | 38 | Desired HTTP header name as a lowercase binary string. 39 | 40 | Req:: 41 | 42 | The Req object. 43 | 44 | Default:: 45 | 46 | Default value returned when the header is missing. 47 | 48 | == Return value 49 | 50 | The header value is returned as a binary string. When the 51 | header is missing, the default argument is returned. 52 | 53 | == Changelog 54 | 55 | * *2.0*: Only the header value is returned, it is no longer wrapped in a tuple. 56 | * *1.0*: Function introduced. 57 | 58 | == Examples 59 | 60 | .Get the accept header 61 | [source,erlang] 62 | ---- 63 | Accept = cowboy_req:header(<<"accept">>, Req). 64 | ---- 65 | 66 | .Get the content-length header with a default value 67 | [source,erlang] 68 | ---- 69 | Length = cowboy_req:header(<<"content-length">>, Req, <<"0">>). 70 | ---- 71 | 72 | == See also 73 | 74 | link:man:cowboy_req(3)[cowboy_req(3)], 75 | link:man:cowboy_req:headers(3)[cowboy_req:headers(3)], 76 | link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(3)] 77 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.headers.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:headers(3) 2 | 3 | == Name 4 | 5 | cowboy_req:headers - HTTP headers 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | headers(Req :: cowboy_req:req()) -> cowboy:http_headers() 12 | ---- 13 | 14 | Return all request headers. 15 | 16 | Request headers can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{headers := Headers} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | Headers are returned as a map with keys being lowercase 32 | binary strings, and values as binary strings. 33 | 34 | == Changelog 35 | 36 | * *2.0*: Only the headers are returned, they are no longer wrapped in a tuple. 37 | * *1.0*: Function introduced. 38 | 39 | == Examples 40 | 41 | .Get all headers 42 | [source,erlang] 43 | ---- 44 | Headers = cowboy_req:headers(Req). 45 | ---- 46 | 47 | == See also 48 | 49 | link:man:cowboy_req(3)[cowboy_req(3)], 50 | link:man:cowboy_req:header(3)[cowboy_req:header(3)], 51 | link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(3)] 52 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.host.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:host(3) 2 | 3 | == Name 4 | 5 | cowboy_req:host - URI host name 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | host(Req :: cowboy_req:req()) -> Host :: binary() 12 | ---- 13 | 14 | Return the host name of the effective request URI. 15 | 16 | The host name can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{host := Host} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The host name is returned as a lowercase binary string. 32 | It is case insensitive. 33 | 34 | == Changelog 35 | 36 | * *2.0*: Only the host name is returned, it is no longer wrapped in a tuple. 37 | * *1.0*: Function introduced. 38 | 39 | == Examples 40 | 41 | .Get the effective request URI's host name 42 | [source,erlang] 43 | ---- 44 | Host = cowboy_req:host(Req). 45 | ---- 46 | 47 | == See also 48 | 49 | link:man:cowboy_req(3)[cowboy_req(3)], 50 | link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], 51 | link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], 52 | link:man:cowboy_req:host_info(3)[cowboy_req:host_info(3)] 53 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.host_info.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:host_info(3) 2 | 3 | == Name 4 | 5 | cowboy_req:host_info - Access the route's heading host segments 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | host_info(Req :: cowboy_req:req()) -> cowboy_router:tokens() 12 | ---- 13 | 14 | Return the tokens for the heading host segments. 15 | 16 | This is the part of the host name that was matched using 17 | the `...` notation. 18 | 19 | == Arguments 20 | 21 | Req:: 22 | 23 | The Req object. 24 | 25 | == Return value 26 | 27 | The tokens are returned as a list of case insensitive 28 | binary strings. 29 | 30 | == Changelog 31 | 32 | * *2.0*: Only the tokens are returned, they are no longer wrapped in a tuple. 33 | * *1.0*: Function introduced. 34 | 35 | == Examples 36 | 37 | .Get the host_info tokens 38 | [source,erlang] 39 | ---- 40 | HostInfo = cowboy_req:host_info(Req). 41 | ---- 42 | 43 | == See also 44 | 45 | link:man:cowboy_req(3)[cowboy_req(3)], 46 | link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], 47 | link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], 48 | link:man:cowboy_req:path_info(3)[cowboy_req:path_info(3)], 49 | link:man:cowboy_router(3)[cowboy_router(3)] 50 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.inform.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:inform(3) 2 | 3 | == Name 4 | 5 | cowboy_req:inform - Send an informational response 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | inform(Status, Req :: cowboy_req:req()) 12 | -> inform(StatusCode, #{}, Req) 13 | 14 | inform(Status, Headers, Req :: cowboy_req:req()) 15 | -> ok 16 | 17 | Status :: cowboy:http_status() 18 | Headers :: cowboy:http_headers() 19 | ---- 20 | 21 | Send an informational response. 22 | 23 | Informational responses use a status code between 100 and 199. 24 | They cannot include a body. This function will not use any 25 | of the previously set headers. All headers to be sent must 26 | be given directly. 27 | 28 | Any number of informational responses can be sent as long as 29 | they are sent before the proper response. Attempting to use 30 | this function after sending a normal response will result 31 | in an error. 32 | 33 | The header names must be given as lowercase binary strings. 34 | While header names are case insensitive, Cowboy requires them 35 | to be given as lowercase to function properly. 36 | 37 | == Arguments 38 | 39 | Status:: 40 | 41 | The status code for the response. 42 | 43 | Headers:: 44 | 45 | The response headers. 46 | + 47 | Header names must be given as lowercase binary strings. 48 | 49 | Req:: 50 | 51 | The Req object. 52 | 53 | == Return value 54 | 55 | The atom `ok` is always returned. It can be safely ignored. 56 | 57 | == Changelog 58 | 59 | * *2.1*: Function introduced. 60 | 61 | == Examples 62 | 63 | .Send an informational response 64 | [source,erlang] 65 | ---- 66 | Req = cowboy_req:inform(102, Req0). 67 | ---- 68 | 69 | .Send an informational response with headers 70 | [source,erlang] 71 | ---- 72 | Req = cowboy_req:inform(103, #{ 73 | <<"link">> => <<"; rel=preload; as=style, " 74 | "; rel=preload; as=script">> 75 | }, Req0). 76 | ---- 77 | 78 | == See also 79 | 80 | link:man:cowboy_req(3)[cowboy_req(3)], 81 | link:man:cowboy_req:reply(3)[cowboy_req:reply(3)], 82 | link:man:cowboy_req:stream_reply(3)[cowboy_req:stream_reply(3)], 83 | link:man:cowboy_req:push(3)[cowboy_req:push(3)] 84 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.method.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:method(3) 2 | 3 | == Name 4 | 5 | cowboy_req:method - HTTP method 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | method(Req :: cowboy_req:req()) -> Method :: binary() 12 | ---- 13 | 14 | Return the request's HTTP method. 15 | 16 | The method can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{method := Method} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The request's HTTP method is returned as a binary string. 32 | While methods are case sensitive, standard methods are 33 | always uppercase. 34 | 35 | == Changelog 36 | 37 | * *2.0*: Only the method is returned, it is no longer wrapped in a tuple. 38 | * *1.0*: Function introduced. 39 | 40 | == Examples 41 | 42 | .Ensure the request's method is GET 43 | [source,erlang] 44 | ---- 45 | <<"GET">> = cowboy_req:method(Req). 46 | ---- 47 | 48 | .Allow methods from list 49 | [source,erlang] 50 | ---- 51 | init(Req, State) -> 52 | case lists:member(cowboy_req:method(Req), [<<"GET">>, <<"POST">>]) of 53 | true -> handle(Req, State); 54 | false -> method_not_allowed(Req, State) 55 | end. 56 | ---- 57 | 58 | == See also 59 | 60 | link:man:cowboy_req(3)[cowboy_req(3)] 61 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.parse_qs.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:parse_qs(3) 2 | 3 | == Name 4 | 5 | cowboy_req:parse_qs - Parse the query string 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | parse_qs(Req :: cowboy_req:req()) 12 | -> [{Key :: binary(), Value :: binary() | true}] 13 | ---- 14 | 15 | Parse the query string as a list of key/value pairs. 16 | 17 | == Arguments 18 | 19 | Req:: 20 | 21 | The Req object. 22 | 23 | == Return value 24 | 25 | The parsed query string is returned as a list of key/value pairs. 26 | The key is a binary string. The value is either a binary string, 27 | or the atom `true`. Both key and value are case sensitive. 28 | 29 | The atom `true` is returned when a key is present in the query 30 | string without a value. For example, in the following URIs 31 | the key `<<"edit">>` will always have the value `true`: 32 | 33 | * `/posts/42?edit` 34 | * `/posts/42?edit&exclusive=1` 35 | * `/posts/42?exclusive=1&edit` 36 | * `/posts/42?exclusive=1&edit&from=web` 37 | 38 | == Changelog 39 | 40 | * *2.0*: The parsed value is not longer cached in the Req object. 41 | * *2.0*: Only the parsed query string is returned, it is no longer wrapped in a tuple. 42 | * *2.0*: Function introduced. Replaces `qs_val/1` and `qs_vals/1`. 43 | 44 | == Examples 45 | 46 | .Parse the query string and convert the keys to atoms 47 | [source,erlang] 48 | ---- 49 | ParsedQs = cowboy_req:parse_qs(Req), 50 | AtomsQs = [{binary_to_existing_atom(K, latin1), V} 51 | || {K, V} <- ParsedQs]. 52 | ---- 53 | 54 | == See also 55 | 56 | link:man:cowboy_req(3)[cowboy_req(3)], 57 | link:man:cowboy_req:qs(3)[cowboy_req:qs(3)], 58 | link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] 59 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.path.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:path(3) 2 | 3 | == Name 4 | 5 | cowboy_req:path - URI path 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | path(Req :: cowboy_req:req()) -> Path :: binary() 12 | ---- 13 | 14 | Return the path of the effective request URI. 15 | 16 | The path can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{path := Path} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The path is returned as a binary string. It is case sensitive. 32 | 33 | == Changelog 34 | 35 | * *2.0*: Only the path is returned, it is no longer wrapped in a tuple. 36 | * *1.0*: Function introduced. 37 | 38 | == Examples 39 | 40 | .Get the effective request URI's path 41 | [source,erlang] 42 | ---- 43 | Path = cowboy_req:path(Req). 44 | ---- 45 | 46 | == See also 47 | 48 | link:man:cowboy_req(3)[cowboy_req(3)], 49 | link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], 50 | link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], 51 | link:man:cowboy_req:path_info(3)[cowboy_req:path_info(3)] 52 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.path_info.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:path_info(3) 2 | 3 | == Name 4 | 5 | cowboy_req:path_info - Access the route's trailing path segments 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | path_info(Req :: cowboy_req:req()) -> cowboy_router:tokens() 12 | ---- 13 | 14 | Return the tokens for the trailing path segments. 15 | 16 | This is the part of the host name that was matched using 17 | the `...` notation. 18 | 19 | == Arguments 20 | 21 | Req:: 22 | 23 | The Req object. 24 | 25 | == Return value 26 | 27 | The tokens are returned as a list of case sensitive 28 | binary strings. 29 | 30 | == Changelog 31 | 32 | * *2.0*: Only the tokens are returned, they are no longer wrapped in a tuple. 33 | * *1.0*: Function introduced. 34 | 35 | == Examples 36 | 37 | .Get the path_info tokens 38 | [source,erlang] 39 | ---- 40 | PathInfo = cowboy_req:path_info(Req). 41 | ---- 42 | 43 | == See also 44 | 45 | link:man:cowboy_req(3)[cowboy_req(3)], 46 | link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], 47 | link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], 48 | link:man:cowboy_req:host_info(3)[cowboy_req:host_info(3)], 49 | link:man:cowboy_router(3)[cowboy_router(3)] 50 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.peer.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:peer(3) 2 | 3 | == Name 4 | 5 | cowboy_req:peer - Peer address and port 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | peer(Req :: cowboy_req:req()) -> Info 12 | 13 | Info :: {inet:ip_address(), inet:port_number()} 14 | ---- 15 | 16 | Return the peer's IP address and port number. 17 | 18 | The peer information can also be obtained using pattern matching: 19 | 20 | [source,erlang] 21 | ---- 22 | #{peer := {IP, Port}} = Req. 23 | ---- 24 | 25 | == Arguments 26 | 27 | Req:: 28 | 29 | The Req object. 30 | 31 | == Return value 32 | 33 | The peer's IP address and port number. 34 | 35 | The peer is not necessarily the client's IP address and port. 36 | It is the IP address of the endpoint connecting directly to 37 | the server, which may be a gateway or a proxy. 38 | 39 | The forwarded header can be used to get better information 40 | about the different endpoints from the client to the server. 41 | Note however that it is only informative; there is no reliable 42 | way of determining the source of an HTTP request. 43 | 44 | == Changelog 45 | 46 | * *2.0*: Only the peer is returned, it is no longer wrapped in a tuple. 47 | * *1.0*: Function introduced. 48 | 49 | == Examples 50 | 51 | .Get the peer IP address and port number. 52 | [source,erlang] 53 | ---- 54 | {IP, Port} = cowboy_req:peer(Req). 55 | ---- 56 | 57 | == See also 58 | 59 | link:man:cowboy_req(3)[cowboy_req(3)], 60 | link:man:cowboy_req:sock(3)[cowboy_req:sock(3)], 61 | link:man:cowboy_req:cert(3)[cowboy_req:cert(3)] 62 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.port.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:port(3) 2 | 3 | == Name 4 | 5 | cowboy_req:port - URI port number 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | port(Req :: cowboy_req:req()) -> Port :: inet:port_number() 12 | ---- 13 | 14 | Return the port number of the effective request URI. 15 | 16 | Note that the port number returned by this function is obtained 17 | by parsing the host header. It may be different from the port 18 | the peer used to connect to Cowboy. 19 | 20 | The port number can also be obtained using pattern matching: 21 | 22 | [source,erlang] 23 | ---- 24 | #{port := Port} = Req. 25 | ---- 26 | 27 | == Arguments 28 | 29 | Req:: 30 | 31 | The Req object. 32 | 33 | == Return value 34 | 35 | The port number is returned as an integer. 36 | 37 | == Changelog 38 | 39 | * *2.0*: Only the port number is returned, it is no longer wrapped in a tuple. 40 | * *1.0*: Function introduced. 41 | 42 | == Examples 43 | 44 | .Get the effective request URI's port number 45 | [source,erlang] 46 | ---- 47 | Port = cowboy_req:port(Req). 48 | ---- 49 | 50 | == See also 51 | 52 | link:man:cowboy_req(3)[cowboy_req(3)] 53 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.qs.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:qs(3) 2 | 3 | == Name 4 | 5 | cowboy_req:qs - URI query string 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | qs(Req :: cowboy_req:req()) -> Qs :: binary() 12 | ---- 13 | 14 | Return the query string of the effective request URI. 15 | 16 | The query string can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{qs := Qs} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The query string is returned as a binary string. It is case sensitive. 32 | 33 | == Changelog 34 | 35 | * *2.0*: Only the query string is returned, it is no longer wrapped in a tuple. 36 | * *1.0*: Function introduced. 37 | 38 | == Examples 39 | 40 | .Get the effective request URI's query string 41 | [source,erlang] 42 | ---- 43 | Qs = cowboy_req:qs(Req). 44 | ---- 45 | 46 | == See also 47 | 48 | link:man:cowboy_req(3)[cowboy_req(3)], 49 | link:man:cowboy_req:parse_qs(3)[cowboy_req:parse_qs(3)], 50 | link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] 51 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.resp_header.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:resp_header(3) 2 | 3 | == Name 4 | 5 | cowboy_req:resp_header - Response header 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | resp_header(Name, Req) -> resp_header(Name, Req, undefined) 12 | resp_header(Name, Req, Default) -> binary() | Default 13 | 14 | Name :: binary() %% lowercase; case insensitive 15 | Req :: cowboy_req:req() 16 | Default :: any() 17 | ---- 18 | 19 | Return the value for the given response header. 20 | 21 | The response header must have been set previously using 22 | link:man:cowboy_req:set_resp_header(3)[cowboy_req:set_resp_header(3)] or 23 | link:man:cowboy_req:set_resp_headers(3)[cowboy_req:set_resp_headers(3)]. 24 | 25 | The header name must be given as a lowercase binary string. 26 | While header names are case insensitive, Cowboy requires them 27 | to be given as lowercase to function properly. 28 | 29 | == Arguments 30 | 31 | Name:: 32 | 33 | Desired response header name as a lowercase binary string. 34 | 35 | Req:: 36 | 37 | The Req object. 38 | 39 | Default:: 40 | 41 | Default value returned when the header is missing. 42 | 43 | == Return value 44 | 45 | The header value is returned as a binary string. When the 46 | header is missing, the default argument is returned. 47 | 48 | == Changelog 49 | 50 | * *2.0*: Function introduced. 51 | 52 | == Examples 53 | 54 | .Get the content-type response header 55 | [source,erlang] 56 | ---- 57 | Type = cowboy_req:resp_header(<<"content-type">>, Req). 58 | ---- 59 | 60 | .Get the content-type response header with a default value 61 | [source,erlang] 62 | ---- 63 | Type = cowboy_req:resp_header(<<"content-type">>, Req, <<"text/html">>). 64 | ---- 65 | 66 | == See also 67 | 68 | link:man:cowboy_req(3)[cowboy_req(3)], 69 | link:man:cowboy_req:resp_headers(3)[cowboy_req:resp_headers(3)], 70 | link:man:cowboy_req:set_resp_header(3)[cowboy_req:set_resp_header(3)], 71 | link:man:cowboy_req:set_resp_headers(3)[cowboy_req:set_resp_headers(3)] 72 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.resp_headers.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:resp_headers(3) 2 | 3 | == Name 4 | 5 | cowboy_req:resp_headers - Response headers 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | resp_headers(Req :: cowboy_req:req()) -> cowboy:http_headers() 12 | ---- 13 | 14 | Return all response headers. 15 | 16 | == Arguments 17 | 18 | Req:: 19 | 20 | The Req object. 21 | 22 | == Return value 23 | 24 | Headers are returned as a map with keys being lowercase 25 | binary strings, and values as binary strings. 26 | 27 | == Changelog 28 | 29 | * *2.0*: Function introduced. 30 | 31 | == Examples 32 | 33 | .Get all response headers 34 | [source,erlang] 35 | ---- 36 | Headers = cowboy_req:resp_headers(Req). 37 | ---- 38 | 39 | == See also 40 | 41 | link:man:cowboy_req(3)[cowboy_req(3)], 42 | link:man:cowboy_req:resp_header(3)[cowboy_req:resp_header(3)], 43 | link:man:cowboy_req:set_resp_header(3)[cowboy_req:set_resp_header(3)], 44 | link:man:cowboy_req:set_resp_headers(3)[cowboy_req:set_resp_headers(3)] 45 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.scheme.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:scheme(3) 2 | 3 | == Name 4 | 5 | cowboy_req:scheme - URI scheme 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | scheme(Req :: cowboy_req:req()) -> Scheme :: binary() 12 | ---- 13 | 14 | Return the scheme of the effective request URI. 15 | 16 | The scheme can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{scheme := Scheme} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The scheme is returned as a binary. It is case insensitive. 32 | 33 | Cowboy will only set the scheme to `<<"http">>` or `<<"https">>`. 34 | 35 | == Changelog 36 | 37 | * *2.0*: Function introduced. 38 | 39 | == Examples 40 | 41 | .Redirect HTTP to HTTPS 42 | [source,erlang] 43 | ---- 44 | init(Req0=#{scheme := <<"http">>}, State) -> 45 | Req = cowboy_req:reply(302, #{ 46 | <<"location">> => cowboy_req:uri(Req, #{scheme => <<"https">>}) 47 | }, Req0), 48 | {ok, Req, State}; 49 | init(Req, State) -> 50 | {cowboy_rest, Req, State}. 51 | ---- 52 | 53 | == See also 54 | 55 | link:man:cowboy_req(3)[cowboy_req(3)] 56 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.sock.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:sock(3) 2 | 3 | == Name 4 | 5 | cowboy_req:sock - Socket address and port 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | sock(Req :: cowboy_req:req()) -> Info 12 | 13 | Info :: {inet:ip_address(), inet:port_number()} 14 | ---- 15 | 16 | Return the socket's IP address and port number. 17 | 18 | The socket information can also be obtained using pattern matching: 19 | 20 | [source,erlang] 21 | ---- 22 | #{sock := {IP, Port}} = Req. 23 | ---- 24 | 25 | == Arguments 26 | 27 | Req:: 28 | 29 | The Req object. 30 | 31 | == Return value 32 | 33 | The socket's local IP address and port number. 34 | 35 | == Changelog 36 | 37 | * *2.1*: Function introduced. 38 | 39 | == Examples 40 | 41 | .Get the socket's IP address and port number. 42 | [source,erlang] 43 | ---- 44 | {IP, Port} = cowboy_req:sock(Req). 45 | ---- 46 | 47 | == See also 48 | 49 | link:man:cowboy_req(3)[cowboy_req(3)], 50 | link:man:cowboy_req:peer(3)[cowboy_req:peer(3)], 51 | link:man:cowboy_req:cert(3)[cowboy_req:cert(3)] 52 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.stream_trailers.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:stream_trailers(3) 2 | 3 | == Name 4 | 5 | cowboy_req:stream_trailers - Send the response trailers 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | stream_trailers(Trailers, Req :: cowboy_req:req()) -> ok 12 | 13 | Trailers :: cowboy:http_headers() 14 | ---- 15 | 16 | Send the response trailers and terminate the stream. 17 | 18 | This function can only be called once, after initiating 19 | a response using 20 | link:man:cowboy_req:stream_reply(3)[cowboy_req:stream_reply(3)] 21 | and sending zero or more body chunks using 22 | link:man:cowboy_req:stream_body(3)[cowboy_req:stream_body(3)] 23 | with the `nofin` argument set. The function `stream_trailers/2` 24 | implies `fin` and automatically terminate the response. 25 | 26 | You must list all field names sent in trailers in the 27 | trailer header, otherwise they might be dropped by intermediaries 28 | or clients. 29 | 30 | == Arguments 31 | 32 | Trailers:: 33 | 34 | Trailer field values to be sent. 35 | 36 | Req:: 37 | 38 | The Req object. 39 | 40 | == Return value 41 | 42 | The atom `ok` is always returned. It can be safely ignored. 43 | 44 | == Changelog 45 | 46 | * *2.2*: Function introduced. 47 | 48 | == Examples 49 | 50 | .Stream a response body with trailers 51 | [source,erlang] 52 | ---- 53 | Req = cowboy_req:stream_reply(200, #{ 54 | <<"content-type">> => <<"text/plain">>, 55 | <<"trailer">> => <<"expires, content-md5">> 56 | }, Req0), 57 | cowboy_req:stream_body(<<"Hello\n">>, nofin, Req), 58 | timer:sleep(1000), 59 | cowboy_req:stream_body(<<"World!\n">>, nofin, Req). 60 | cowboy_req:stream_trailers(#{ 61 | <<"expires">> => <<"Sun, 10 Dec 2017 19:13:47 GMT">>, 62 | <<"content-md5">> => <<"fbf68a8e34b2ded53bba54e68794b4fe">> 63 | }, Req). 64 | ---- 65 | 66 | == See also 67 | 68 | link:man:cowboy_req(3)[cowboy_req(3)], 69 | link:man:cowboy_req:stream_reply(3)[cowboy_req:stream_reply(3)], 70 | link:man:cowboy_req:stream_body(3)[cowboy_req:stream_body(3)], 71 | link:man:cowboy_req:stream_events(3)[cowboy_req:stream_events(3)] 72 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_req.version.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_req:version(3) 2 | 3 | == Name 4 | 5 | cowboy_req:version - HTTP version 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | version(Req :: cowboy_req:req()) -> Version :: cowboy:http_version() 12 | ---- 13 | 14 | Return the HTTP version used for the request. 15 | 16 | The version can also be obtained using pattern matching: 17 | 18 | [source,erlang] 19 | ---- 20 | #{version := Version} = Req. 21 | ---- 22 | 23 | == Arguments 24 | 25 | Req:: 26 | 27 | The Req object. 28 | 29 | == Return value 30 | 31 | The HTTP version used for the request is returned as an 32 | atom. It is provided for informative purposes only. 33 | 34 | == Changelog 35 | 36 | * *2.0*: Only the version is returned, it is no longer wrapped in a tuple. 37 | * *1.0*: Function introduced. 38 | 39 | == Examples 40 | 41 | .Get the HTTP version 42 | [source,erlang] 43 | ---- 44 | Version = cowboy_req:version(Req). 45 | ---- 46 | 47 | == See also 48 | 49 | link:man:cowboy_req(3)[cowboy_req(3)] 50 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_router.compile.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_router:compile(3) 2 | 3 | == Name 4 | 5 | cowboy_router:compile - Compile routes to the resources 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | compile(cowboy_router:routes()) -> cowboy_router:dispatch_rules() 12 | ---- 13 | 14 | Compile routes to the resources. 15 | 16 | Takes a human readable list of routes and transforms it 17 | into a form more efficient to process. 18 | 19 | == Arguments 20 | 21 | Routes:: 22 | 23 | Human readable list of routes. 24 | 25 | == Return value 26 | 27 | An opaque dispatch rules value is returned. This value 28 | must be given to Cowboy as a middleware environment value. 29 | 30 | == Changelog 31 | 32 | * *1.0*: Function introduced. 33 | 34 | == Examples 35 | 36 | .Compile routes and start a listener 37 | [source,erlang] 38 | ---- 39 | Dispatch = cowboy_router:compile([ 40 | {'_', [ 41 | {"/", toppage_h, []}, 42 | {"/[...]", cowboy_static, {priv_dir, my_example_app, ""}} 43 | ]} 44 | ]), 45 | 46 | {ok, _} = cowboy:start_clear(example, [{port, 8080}], #{ 47 | env => #{dispatch => Dispatch} 48 | }). 49 | ---- 50 | 51 | == See also 52 | 53 | link:man:cowboy_router(3)[cowboy_router(3)] 54 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_stream.data.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_stream:data(3) 2 | 3 | == Name 4 | 5 | cowboy_stream:data - Handle data for a stream 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | data(StreamID, IsFin, Data, State) -> {Commands, State} 12 | 13 | StreamID :: cowboy_stream:stream_id() 14 | IsFin :: cowboy_stream:fin() 15 | Data :: binary() 16 | Commands :: cowboy_stream:commands() 17 | State - opaque 18 | ---- 19 | 20 | Handle data for a stream. 21 | 22 | This function should be called by all stream handlers. It will 23 | propagate data to the next configured stream handler. Handlers 24 | do not have to propagate data that has been fully handled. 25 | 26 | == Arguments 27 | 28 | StreamID:: 29 | 30 | The stream ID. 31 | 32 | IsFin:: 33 | 34 | Whether this is the end of the request body. 35 | 36 | Data:: 37 | 38 | The data received. 39 | 40 | Commands:: 41 | 42 | The commands to be executed. 43 | 44 | State:: 45 | 46 | The state for the next stream handler. 47 | 48 | == Return value 49 | 50 | A list of commands and an opaque state is returned. 51 | 52 | The list of commands returned should be included in the 53 | commands returned from the current stream handler. It 54 | can be modified if necessary. 55 | 56 | The state should be stored in the current stream 57 | handler's state and passed to `cowboy_stream` when 58 | necessary. The state should be treated as opaque. 59 | 60 | == Changelog 61 | 62 | * *2.0*: Function introduced. 63 | 64 | == Examples 65 | 66 | .Propagate data to the next stream handler 67 | [source,erlang] 68 | ---- 69 | data(StreamID, IsFin, Data, State=#state{next=Next0}) -> 70 | MyCommands = my_commands(), 71 | {Commands, Next} = cowboy_stream:data(StreamID, IsFin, Data, Next0), 72 | {MyCommands ++ Commands, #state{next=Next}}. 73 | ---- 74 | 75 | == See also 76 | 77 | link:man:cowboy_stream(3)[cowboy_stream(3)], 78 | link:man:cowboy_stream:init(3)[cowboy_stream:init(3)], 79 | link:man:cowboy_stream:info(3)[cowboy_stream:info(3)], 80 | link:man:cowboy_stream:terminate(3)[cowboy_stream:terminate(3)], 81 | link:man:cowboy_stream:early_error(3)[cowboy_stream:early_error(3)] 82 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_stream.early_error.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_stream:early_error(3) 2 | 3 | == Name 4 | 5 | cowboy_stream:early_error - Handle an early error for a stream 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | early_error(StreamID, Reason, PartialReq, Resp, Opts) -> Resp 12 | 13 | StreamID :: cowboy_stream:stream_id() 14 | Reason :: cowboy_stream:reason() 15 | PartialReq :: cowboy_stream:partial_req() 16 | Resp :: cowboy_stream:resp_command() 17 | Opts :: cowboy:opts() 18 | ---- 19 | 20 | Handle an early error for a stream. 21 | 22 | This function should be called by all stream handlers. It will 23 | propagate the early error to the next configured stream handler. 24 | 25 | == Arguments 26 | 27 | StreamID:: 28 | 29 | The stream ID. 30 | 31 | Reason:: 32 | 33 | Reason for termination. 34 | 35 | PartialReq:: 36 | 37 | The request data that has been received so far. 38 | 39 | Resp:: 40 | 41 | The response that will be sent as a result of the early error. 42 | + 43 | It may be modified by the stream handler before or after 44 | being propagated to the next handler. 45 | 46 | Opts:: 47 | 48 | The protocol options. 49 | 50 | == Return value 51 | 52 | The response to be sent as a result of the early error. 53 | 54 | == Changelog 55 | 56 | * *2.0*: Function introduced. 57 | 58 | == Examples 59 | 60 | .Propagate the early error to the next stream handler 61 | [source,erlang] 62 | ---- 63 | early_error(StreamID, Reason, PartialReq, Resp, Opts) -> 64 | cowboy_stream:early_error(StreamID, Reason, PartialReq, Resp, Opts). 65 | ---- 66 | 67 | == See also 68 | 69 | link:man:cowboy_stream(3)[cowboy_stream(3)], 70 | link:man:cowboy_stream:init(3)[cowboy_stream:init(3)], 71 | link:man:cowboy_stream:data(3)[cowboy_stream:data(3)], 72 | link:man:cowboy_stream:info(3)[cowboy_stream:info(3)], 73 | link:man:cowboy_stream:terminate(3)[cowboy_stream:terminate(3)] 74 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_stream.info.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_stream:info(3) 2 | 3 | == Name 4 | 5 | cowboy_stream:info - Handle a message for a stream 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | info(StreamID, Info, State) -> {Commands, State} 12 | 13 | StreamID :: cowboy_stream:stream_id() 14 | Info :: any() 15 | Commands :: cowboy_stream:commands() 16 | State - opaque 17 | ---- 18 | 19 | Handle a message for a stream. 20 | 21 | This function should be called by all stream handlers. It will 22 | propagate the event to the next configured stream handler. 23 | Handlers do not have to propagate events that have been 24 | fully handled. 25 | 26 | == Arguments 27 | 28 | StreamID:: 29 | 30 | The stream ID. 31 | 32 | Info:: 33 | 34 | The event received. 35 | 36 | Commands:: 37 | 38 | The commands to be executed. 39 | 40 | State:: 41 | 42 | The state for the next stream handler. 43 | 44 | == Return value 45 | 46 | A list of commands and an opaque state is returned. 47 | 48 | The list of commands returned should be included in the 49 | commands returned from the current stream handler. It 50 | can be modified if necessary. 51 | 52 | The state should be stored in the current stream 53 | handler's state and passed to `cowboy_stream` when 54 | necessary. The state should be treated as opaque. 55 | 56 | == Changelog 57 | 58 | * *2.0*: Function introduced. 59 | 60 | == Examples 61 | 62 | .Propagate an event to the next stream handler 63 | [source,erlang] 64 | ---- 65 | info(StreamID, Info, State=#state{next=Next0}) -> 66 | MyCommands = my_commands(), 67 | {Commands, Next} = cowboy_stream:info(StreamID, Info, Next0), 68 | {MyCommands ++ Commands, #state{next=Next}}. 69 | ---- 70 | 71 | == See also 72 | 73 | link:man:cowboy_stream(3)[cowboy_stream(3)], 74 | link:man:cowboy_stream:init(3)[cowboy_stream:init(3)], 75 | link:man:cowboy_stream:data(3)[cowboy_stream:data(3)], 76 | link:man:cowboy_stream:terminate(3)[cowboy_stream:terminate(3)], 77 | link:man:cowboy_stream:early_error(3)[cowboy_stream:early_error(3)] 78 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_stream.init.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_stream:init(3) 2 | 3 | == Name 4 | 5 | cowboy_stream:init - Initialize a stream 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | init(StreamID, Req, Opts) -> {Commands, State} 12 | 13 | StreamID :: cowboy_stream:stream_id() 14 | Req :: cowboy_req:req() 15 | Opts :: cowboy:opts() 16 | Commands :: cowboy_stream:commands() 17 | State - opaque 18 | ---- 19 | 20 | Initialize a stream. 21 | 22 | This function must be called by all stream handlers. It will 23 | initialize the next configured stream handler. 24 | 25 | == Arguments 26 | 27 | StreamID:: 28 | 29 | The stream ID. 30 | 31 | Req:: 32 | 33 | The Req object. 34 | 35 | Opts:: 36 | 37 | The protocol options. 38 | 39 | Commands:: 40 | 41 | The commands to be executed. 42 | 43 | State:: 44 | 45 | The state for the next stream handler. 46 | 47 | == Return value 48 | 49 | A list of commands and an opaque state is returned. 50 | 51 | The list of commands returned should be included in the 52 | commands returned from the current stream handler. It 53 | can be modified if necessary. 54 | 55 | The state should be stored in the current stream 56 | handler's state and passed to `cowboy_stream` when 57 | necessary. The state should be treated as opaque. 58 | 59 | == Changelog 60 | 61 | * *2.0*: Function introduced. 62 | 63 | == Examples 64 | 65 | .Initialize the next stream handler 66 | [source,erlang] 67 | ---- 68 | init(StreamID, Req, Opts) -> 69 | MyCommands = my_commands(), 70 | {Commands, Next} = cowboy_stream:init(StreamID, Req, Opts), 71 | {MyCommands ++ Commands, #state{next=Next}}. 72 | ---- 73 | 74 | == See also 75 | 76 | link:man:cowboy_stream(3)[cowboy_stream(3)], 77 | link:man:cowboy_stream:data(3)[cowboy_stream:data(3)], 78 | link:man:cowboy_stream:info(3)[cowboy_stream:info(3)], 79 | link:man:cowboy_stream:terminate(3)[cowboy_stream:terminate(3)], 80 | link:man:cowboy_stream:early_error(3)[cowboy_stream:early_error(3)] 81 | -------------------------------------------------------------------------------- /doc/src/manual/cowboy_stream.terminate.asciidoc: -------------------------------------------------------------------------------- 1 | = cowboy_stream:terminate(3) 2 | 3 | == Name 4 | 5 | cowboy_stream:terminate - Terminate a stream 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | terminate(StreamID, Reason, State) -> ok 12 | 13 | StreamID :: cowboy_stream:stream_id() 14 | Reason :: cowboy_stream:reason() 15 | State - opaque 16 | ---- 17 | 18 | Terminate a stream. 19 | 20 | This function must be called by all stream handlers. It will 21 | terminate the next configured stream handler. 22 | 23 | == Arguments 24 | 25 | StreamID:: 26 | 27 | The stream ID. 28 | 29 | Reason:: 30 | 31 | Reason for termination. 32 | 33 | State:: 34 | 35 | The state for the next stream handler. 36 | 37 | == Return value 38 | 39 | The atom `ok` is always returned. It can be safely ignored. 40 | 41 | == Changelog 42 | 43 | * *2.0*: Function introduced. 44 | 45 | == Examples 46 | 47 | .Terminate the next stream handler 48 | [source,erlang] 49 | ---- 50 | terminate(StreamID, Reason, State=#state{next=Next0}) -> 51 | my_termination(State), 52 | cowboy_stream:terminate(StreamID, Reason, Next0). 53 | ---- 54 | 55 | == See also 56 | 57 | link:man:cowboy_stream(3)[cowboy_stream(3)], 58 | link:man:cowboy_stream:init(3)[cowboy_stream:init(3)], 59 | link:man:cowboy_stream:data(3)[cowboy_stream:data(3)], 60 | link:man:cowboy_stream:info(3)[cowboy_stream:info(3)], 61 | link:man:cowboy_stream:early_error(3)[cowboy_stream:early_error(3)] 62 | -------------------------------------------------------------------------------- /doc/src/specs/index.ezdoc: -------------------------------------------------------------------------------- 1 | ::: Cowboy Implementation Reference 2 | 3 | The implementation reference documents the behavior of Cowboy 4 | with regards to various standards and specifications. 5 | 6 | * ^"RFC6585 status codes^rfc6585 7 | * ^"RFC7230 HTTP/1.1 server^rfc7230_server 8 | -------------------------------------------------------------------------------- /doc/src/specs/rfc6585.ezdoc: -------------------------------------------------------------------------------- 1 | ::: RFC6585 2 | 3 | This document lists status codes that Cowboy implements as 4 | defined in the RFC6585 specifications. 5 | 6 | :: Status codes 7 | 8 | : 428 Precondition Required (RFC6585 3) 9 | 10 | The server requires the request to this resource to be conditional. 11 | 12 | The response should explain how to resubmit the request successfully. 13 | 14 | : 429 Too Many Requests (RFC6585 4, RFC6585 7.2) 15 | 16 | The user has sent too many requests in a given amount of time. 17 | 18 | The response should detail the rates allowed. 19 | 20 | The retry-after header can be used to indicate how long the 21 | user has to wait before making a new request. 22 | 23 | When an attack is detected it is recommended to drop the 24 | connection directly instead of sending this response. 25 | 26 | : 431 Request Header Fields Too Large (RFC6585 5, RFC6585 7.3) 27 | 28 | The request's header fields are too large. 29 | 30 | When rejecting a single header, the response should detail 31 | which header was at fault. 32 | 33 | When an attack is detected it is recommended to drop the 34 | connection directly instead of sending this response. 35 | 36 | : 511 Network Authentication Required (RFC6585 6) 37 | 38 | The user needs to authenticate into the network to gain access. 39 | 40 | This status code is meant to be used by proxies only, not by 41 | origin servers. 42 | 43 | The response should contain a link to the resource allowing 44 | the user to log in. 45 | -------------------------------------------------------------------------------- /ebin/cowboy.app: -------------------------------------------------------------------------------- 1 | {application, 'cowboy', [ 2 | {description, "Small, fast, modern HTTP server."}, 3 | {vsn, "2.13.0"}, 4 | {modules, ['cowboy','cowboy_app','cowboy_bstr','cowboy_children','cowboy_clear','cowboy_clock','cowboy_compress_h','cowboy_constraints','cowboy_decompress_h','cowboy_handler','cowboy_http','cowboy_http2','cowboy_http3','cowboy_loop','cowboy_metrics_h','cowboy_middleware','cowboy_quicer','cowboy_req','cowboy_rest','cowboy_router','cowboy_static','cowboy_stream','cowboy_stream_h','cowboy_sub_protocol','cowboy_sup','cowboy_tls','cowboy_tracer_h','cowboy_websocket']}, 5 | {registered, [cowboy_sup,cowboy_clock]}, 6 | {applications, [kernel,stdlib,crypto,cowlib,ranch]}, 7 | {optional_applications, []}, 8 | {mod, {cowboy_app, []}}, 9 | {env, []} 10 | ]}. -------------------------------------------------------------------------------- /examples/README.asciidoc: -------------------------------------------------------------------------------- 1 | = Cowboy examples 2 | 3 | * link:chunked_hello_world[]: 4 | demonstrate chunked data transfer with two one-second delays 5 | 6 | * link:compress_response[]: 7 | send a response body compressed if the client supports it 8 | 9 | * link:cookie[]: 10 | set cookies from server and client side 11 | 12 | * link:echo_get[]: 13 | parse and echo a GET query string 14 | 15 | * link:echo_post[]: 16 | parse and echo a POST parameter 17 | 18 | * link:eventsource[]: 19 | eventsource emitter and consumer 20 | 21 | * link:file_server[]: 22 | file server with directory listing 23 | 24 | * link:hello_world[]: 25 | simplest example application 26 | 27 | * link:markdown_middleware[]: 28 | static file handler with markdown preprocessor 29 | 30 | * link:rest_basic_auth[]: 31 | basic HTTP authorization with REST 32 | 33 | * link:rest_hello_world[]: 34 | return the data type that matches the request type (ex: html, text, json) 35 | 36 | * link:rest_pastebin[]: 37 | create text objects and return the data type that matches the request type (html, text) 38 | 39 | * link:ssl_hello_world[]: 40 | simplest SSL application 41 | 42 | * link:upload[]: 43 | multipart/form-data upload 44 | 45 | * link:websocket[]: 46 | websocket example 47 | 48 | == Other languages 49 | 50 | * https://github.com/joshrotenberg/elixir_cowboy_examples[Elixir] 51 | * https://github.com/quasiquoting/lfe-cowboy-examples[LFE] 52 | -------------------------------------------------------------------------------- /examples/chunked_hello_world/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = chunked_hello_world 2 | PROJECT_DESCRIPTION = Cowboy chunked Hello World example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/chunked_hello_world/relx.config: -------------------------------------------------------------------------------- 1 | {release, {chunked_hello_world_example, "1"}, [chunked_hello_world]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/chunked_hello_world/src/chunked_hello_world_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(chunked_hello_world_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | chunked_hello_world_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/chunked_hello_world/src/chunked_hello_world_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(chunked_hello_world_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/chunked_hello_world/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Chunked hello world handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | Req = cowboy_req:stream_reply(200, Req0), 10 | cowboy_req:stream_body("Hello\r\n", nofin, Req), 11 | timer:sleep(1000), 12 | cowboy_req:stream_body("World\r\n", nofin, Req), 13 | timer:sleep(1000), 14 | cowboy_req:stream_body("Chunked!\r\n", fin, Req), 15 | {ok, Req, Opts}. 16 | -------------------------------------------------------------------------------- /examples/compress_response/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = compress_response 2 | PROJECT_DESCRIPTION = Cowboy compressed response example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/compress_response/relx.config: -------------------------------------------------------------------------------- 1 | {release, {compress_response_example, "1"}, [compress_response]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/compress_response/src/compress_response_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(compress_response_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch}, 21 | stream_handlers => [cowboy_compress_h, cowboy_stream_h] 22 | }), 23 | compress_response_sup:start_link(). 24 | 25 | stop(_State) -> 26 | ok = cowboy:stop_listener(http). 27 | -------------------------------------------------------------------------------- /examples/compress_response/src/compress_response_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(compress_response_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/compress_response/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Compress response handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | BigBody = 10 | <<"A cowboy is an animal herder who tends cattle on ranches in North America, 11 | traditionally on horseback, and often performs a multitude of other ranch- 12 | related tasks. The historic American cowboy of the late 19th century arose 13 | from the vaquero traditions of northern Mexico and became a figure of special 14 | significance and legend. A subtype, called a wrangler, specifically tends the 15 | horses used to work cattle. In addition to ranch work, some cowboys work for 16 | or participate in rodeos. Cowgirls, first defined as such in the late 19th 17 | century, had a less-well documented historical role, but in the modern world 18 | have established the ability to work at virtually identical tasks and obtained 19 | considerable respect for their achievements. There are also cattle handlers 20 | in many other parts of the world, particularly South America and Australia, 21 | who perform work similar to the cowboy in their respective nations.\n">>, 22 | Req = cowboy_req:reply(200, #{}, BigBody, Req0), 23 | {ok, Req, Opts}. 24 | -------------------------------------------------------------------------------- /examples/cookie/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = cookie 2 | PROJECT_DESCRIPTION = Cowboy Cookie example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy erlydtl 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/cookie/README.asciidoc: -------------------------------------------------------------------------------- 1 | = Cookie example 2 | 3 | To try this example, you need GNU `make` and `git` in your PATH. 4 | 5 | To build and run the example, use the following command: 6 | 7 | [source,bash] 8 | $ make run 9 | 10 | Then point your browser to http://localhost:8080 11 | 12 | This example allows you to use any path to show that the cookies 13 | are defined site-wide. Try it! 14 | -------------------------------------------------------------------------------- /examples/cookie/relx.config: -------------------------------------------------------------------------------- 1 | {release, {cookie_example, "1"}, [cookie]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/cookie/src/cookie_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(cookie_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {'_', toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | cookie_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/cookie/src/cookie_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(cookie_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/cookie/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Cookie handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | NewValue = integer_to_list(rand:uniform(1000000)), 10 | Req1 = cowboy_req:set_resp_cookie(<<"server">>, NewValue, 11 | Req0, #{path => <<"/">>}), 12 | #{client := ClientCookie, server := ServerCookie} 13 | = cowboy_req:match_cookies([{client, [], <<>>}, {server, [], <<>>}], Req1), 14 | {ok, Body} = toppage_dtl:render([ 15 | {client, ClientCookie}, 16 | {server, ServerCookie} 17 | ]), 18 | Req = cowboy_req:reply(200, #{ 19 | <<"content-type">> => <<"text/html">> 20 | }, Body, Req1), 21 | {ok, Req, Opts}. 22 | -------------------------------------------------------------------------------- /examples/cookie/templates/toppage.dtl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Cowboy Cookie Example 6 | 7 | 8 | 9 |

Cowboy Cookie Example

10 |

Refresh the page to see the next cookie.

11 | 12 |

Cookie Set Server-Side

13 |

{{ server }}

14 | 15 |

Cookie Set Client-Side

16 |

{{ client }}

17 | 18 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/echo_get/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = echo_get 2 | PROJECT_DESCRIPTION = Cowboy GET echo example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/echo_get/relx.config: -------------------------------------------------------------------------------- 1 | {release, {echo_get_example, "1"}, [echo_get]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/echo_get/src/echo_get_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(echo_get_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | echo_get_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/echo_get/src/echo_get_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(echo_get_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/echo_get/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc GET echo handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | Method = cowboy_req:method(Req0), 10 | #{echo := Echo} = cowboy_req:match_qs([{echo, [], undefined}], Req0), 11 | Req = echo(Method, Echo, Req0), 12 | {ok, Req, Opts}. 13 | 14 | echo(<<"GET">>, undefined, Req) -> 15 | cowboy_req:reply(400, #{}, <<"Missing echo parameter.">>, Req); 16 | echo(<<"GET">>, Echo, Req) -> 17 | cowboy_req:reply(200, #{ 18 | <<"content-type">> => <<"text/plain; charset=utf-8">> 19 | }, Echo, Req); 20 | echo(_, _, Req) -> 21 | %% Method not allowed. 22 | cowboy_req:reply(405, Req). 23 | -------------------------------------------------------------------------------- /examples/echo_post/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = echo_post 2 | PROJECT_DESCRIPTION = Cowboy POST echo example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/echo_post/relx.config: -------------------------------------------------------------------------------- 1 | {release, {echo_post_example, "1"}, [echo_post]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/echo_post/src/echo_post_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(echo_post_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | echo_post_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/echo_post/src/echo_post_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(echo_post_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/echo_post/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc POST echo handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | Method = cowboy_req:method(Req0), 10 | HasBody = cowboy_req:has_body(Req0), 11 | Req = maybe_echo(Method, HasBody, Req0), 12 | {ok, Req, Opts}. 13 | 14 | maybe_echo(<<"POST">>, true, Req0) -> 15 | {ok, PostVals, Req} = cowboy_req:read_urlencoded_body(Req0), 16 | Echo = proplists:get_value(<<"echo">>, PostVals), 17 | echo(Echo, Req); 18 | maybe_echo(<<"POST">>, false, Req) -> 19 | cowboy_req:reply(400, #{}, <<"Missing body.">>, Req); 20 | maybe_echo(_, _, Req) -> 21 | %% Method not allowed. 22 | cowboy_req:reply(405, Req). 23 | 24 | echo(undefined, Req) -> 25 | cowboy_req:reply(400, #{}, <<"Missing echo parameter.">>, Req); 26 | echo(Echo, Req) -> 27 | cowboy_req:reply(200, #{ 28 | <<"content-type">> => <<"text/plain; charset=utf-8">> 29 | }, Echo, Req). 30 | -------------------------------------------------------------------------------- /examples/eventsource/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = eventsource 2 | PROJECT_DESCRIPTION = Cowboy EventSource example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/eventsource/README.asciidoc: -------------------------------------------------------------------------------- 1 | = EventSource example 2 | 3 | To try this example, you need GNU `make` and `git` in your PATH. 4 | 5 | To build and run the example, use the following command: 6 | 7 | [source,bash] 8 | $ make run 9 | 10 | Then point your browser to http://localhost:8080 11 | -------------------------------------------------------------------------------- /examples/eventsource/priv/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 39 | 40 | 41 | Hi! 42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/eventsource/relx.config: -------------------------------------------------------------------------------- 1 | {release, {eventsource_example, "1"}, [eventsource]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/eventsource/src/eventsource_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(eventsource_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/eventsource", eventsource_h, []}, 17 | {"/", cowboy_static, {priv_file, eventsource, "index.html"}} 18 | ]} 19 | ]), 20 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 21 | env => #{dispatch => Dispatch} 22 | }), 23 | eventsource_sup:start_link(). 24 | 25 | stop(_State) -> 26 | ok = cowboy:stop_listener(http). 27 | -------------------------------------------------------------------------------- /examples/eventsource/src/eventsource_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc EventSource emitter. 4 | -module(eventsource_h). 5 | 6 | -export([init/2]). 7 | -export([info/3]). 8 | 9 | init(Req0, Opts) -> 10 | Req = cowboy_req:stream_reply(200, #{ 11 | <<"content-type">> => <<"text/event-stream">> 12 | }, Req0), 13 | erlang:send_after(1000, self(), {message, "Tick"}), 14 | {cowboy_loop, Req, Opts}. 15 | 16 | info({message, Msg}, Req, State) -> 17 | cowboy_req:stream_events(#{ 18 | id => id(), 19 | data => Msg 20 | }, nofin, Req), 21 | erlang:send_after(1000, self(), {message, "Tick"}), 22 | {ok, Req, State}. 23 | 24 | id() -> 25 | integer_to_list(erlang:unique_integer([positive, monotonic]), 16). 26 | -------------------------------------------------------------------------------- /examples/eventsource/src/eventsource_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(eventsource_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/file_server/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = file_server 2 | PROJECT_DESCRIPTION = Cowboy file server example with directory listing 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/file_server/priv/small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/examples/file_server/priv/small.mp4 -------------------------------------------------------------------------------- /examples/file_server/priv/small.ogv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/examples/file_server/priv/small.ogv -------------------------------------------------------------------------------- /examples/file_server/priv/test.txt: -------------------------------------------------------------------------------- 1 | If you read this then the static file server works! 2 | -------------------------------------------------------------------------------- /examples/file_server/priv/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

HTML5 Video Example

5 | 9 |

Videos taken from TechSlides

10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/file_server/priv/中文/中文.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 中文! 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/file_server/relx.config: -------------------------------------------------------------------------------- 1 | {release, {file_server_example, "1"}, [file_server]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/file_server/src/directory_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Directory handler. 4 | -module(directory_h). 5 | 6 | %% REST Callbacks 7 | -export([init/2]). 8 | -export([allowed_methods/2]). 9 | -export([resource_exists/2]). 10 | -export([content_types_provided/2]). 11 | -export([charsets_provided/2]). 12 | 13 | %% Callback Callbacks 14 | -export([list_json/2]). 15 | -export([list_html/2]). 16 | 17 | init(Req, Paths) -> 18 | {cowboy_rest, Req, Paths}. 19 | 20 | allowed_methods(Req, State) -> 21 | {[<<"GET">>], Req, State}. 22 | 23 | resource_exists(Req, {ReqPath, FilePath}) -> 24 | case file:list_dir(FilePath) of 25 | {ok, Fs} -> {true, Req, {ReqPath, lists:sort(Fs)}}; 26 | _Err -> {false, Req, {ReqPath, FilePath}} 27 | end. 28 | 29 | content_types_provided(Req, State) -> 30 | {[ 31 | {{<<"text">>, <<"html">>, []}, list_html}, 32 | {{<<"application">>, <<"json">>, []}, list_json} 33 | ], Req, State}. 34 | 35 | charsets_provided(Req, State) -> 36 | {[<<"utf-8">>], Req, State}. 37 | 38 | list_json(Req, {Path, Fs}) -> 39 | Files = [unicode:characters_to_binary(F) || F <- Fs], 40 | {json:encode(Files), Req, Path}. 41 | 42 | list_html(Req, {Path, Fs}) -> 43 | Body = [[links(Path, unicode:characters_to_binary(F)) || F <- [".."|Fs]]], 44 | HTML = [<<"Index", 45 | "">>, Body, <<"\n">>], 46 | {HTML, Req, Path}. 47 | 48 | links(<<>>, "..") -> 49 | "..
\n"; 50 | links(Prefix, "..") -> 51 | Tokens = string:tokens(binary_to_list(Prefix), "/"), 52 | Back = lists:join("/", lists:reverse(tl(lists:reverse(Tokens)))), 53 | ["..
\n"]; 54 | links(<<>>, File) -> 55 | ["", File, "
\n"]; 56 | links(Prefix, File) -> 57 | ["", File, "
\n"]. 58 | -------------------------------------------------------------------------------- /examples/file_server/src/directory_lister.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(directory_lister). 4 | -behaviour(cowboy_middleware). 5 | 6 | -export([execute/2]). 7 | 8 | execute(Req, Env=#{handler := cowboy_static}) -> 9 | redirect_directory(Req, Env); 10 | execute(Req, Env) -> 11 | {ok, Req, Env}. 12 | 13 | redirect_directory(Req, Env=#{handler_opts := {_, _, _, Extra}}) -> 14 | Path = cowboy_req:path_info(Req), 15 | Path1 = << <> || S <- Path >>, 16 | {dir_handler, DirHandler} = lists:keyfind(dir_handler, 1, Extra), 17 | FullPath = resource_path(Path1), 18 | case valid_path(Path) and filelib:is_dir(FullPath) of 19 | true -> handle_directory(Req, Env, Path1, FullPath, DirHandler); 20 | false -> {ok, Req, Env} 21 | end. 22 | 23 | handle_directory(Req, Env, Prefix, Path, DirHandler) -> 24 | {ok, Req, Env#{handler => DirHandler, handler_opts => {Prefix, Path}}}. 25 | 26 | valid_path([]) -> true; 27 | valid_path([<<"..">> | _T]) -> false; 28 | valid_path([<<"/", _/binary>> | _T]) -> false; 29 | valid_path([_H | Rest]) -> valid_path(Rest). 30 | 31 | resource_path(Path) -> 32 | filename:join([code:priv_dir(file_server), Path]). 33 | -------------------------------------------------------------------------------- /examples/file_server/src/file_server_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(file_server_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/[...]", cowboy_static, {priv_dir, file_server, "", [ 17 | {mimetypes, cow_mimetypes, all}, 18 | {dir_handler, directory_h}, 19 | {charset, <<"utf-8">>} 20 | ]}} 21 | ]} 22 | ]), 23 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 24 | env => #{dispatch => Dispatch}, 25 | middlewares => [cowboy_router, directory_lister, cowboy_handler] 26 | }), 27 | file_server_sup:start_link(). 28 | 29 | stop(_State) -> 30 | ok = cowboy:stop_listener(http). 31 | -------------------------------------------------------------------------------- /examples/file_server/src/file_server_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(file_server_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/hello_world/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = hello_world 2 | PROJECT_DESCRIPTION = Cowboy Hello World example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/hello_world/relx.config: -------------------------------------------------------------------------------- 1 | {release, {hello_world_example, "1"}, [hello_world]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/hello_world/src/hello_world_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(hello_world_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | hello_world_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/hello_world/src/hello_world_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(hello_world_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/hello_world/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Hello world handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | Req = cowboy_req:reply(200, #{ 10 | <<"content-type">> => <<"text/plain">> 11 | }, <<"Hello world!">>, Req0), 12 | {ok, Req, Opts}. 13 | -------------------------------------------------------------------------------- /examples/markdown_middleware/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = markdown_middleware 2 | PROJECT_DESCRIPTION = Cowboy static file handler example with middleware component 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy markdown 6 | dep_cowboy_commit = master 7 | dep_markdown = git https://github.com/hypernumbers/erlmarkdown master 8 | 9 | REL_DEPS = relx 10 | 11 | include ../../erlang.mk 12 | -------------------------------------------------------------------------------- /examples/markdown_middleware/README.asciidoc: -------------------------------------------------------------------------------- 1 | = Middleware example 2 | 3 | To try this example, you need GNU `make` and `git` in your PATH. 4 | 5 | To build and run the example, use the following command: 6 | 7 | [source,bash] 8 | $ make run 9 | 10 | Then point your browser to http://localhost:8080/video.html 11 | 12 | Cowboy will serve all the files you put in the `priv` directory. 13 | If you request a `.html` file that has a corresponding `.md` file 14 | that has been modified more recently than the `.html` file, the 15 | Markdown file will be converted to HTML and served by Cowboy. 16 | -------------------------------------------------------------------------------- /examples/markdown_middleware/priv/small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/examples/markdown_middleware/priv/small.mp4 -------------------------------------------------------------------------------- /examples/markdown_middleware/priv/small.ogv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/examples/markdown_middleware/priv/small.ogv -------------------------------------------------------------------------------- /examples/markdown_middleware/priv/video.md: -------------------------------------------------------------------------------- 1 | HTML5 Video With Markdown 2 | ========================= 3 | 4 | 8 | 9 | Videos taken from [TechSlides](http://techslides.com/sample-webm-ogg-and-mp4-video-files-for-html5/) 10 | -------------------------------------------------------------------------------- /examples/markdown_middleware/relx.config: -------------------------------------------------------------------------------- 1 | {release, {markdown_middleware_example, "1"}, [markdown_middleware]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/markdown_middleware/src/markdown_converter.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(markdown_converter). 4 | -behaviour(cowboy_middleware). 5 | 6 | -export([execute/2]). 7 | 8 | execute(Req, Env) -> 9 | [Path] = cowboy_req:path_info(Req), 10 | case filename:extension(Path) of 11 | <<".html">> -> maybe_generate_markdown(resource_path(Path)); 12 | _Ext -> ok 13 | end, 14 | {ok, Req, Env}. 15 | 16 | maybe_generate_markdown(Path) -> 17 | ModifiedAt = filelib:last_modified(source_path(Path)), 18 | GeneratedAt = filelib:last_modified(Path), 19 | case ModifiedAt > GeneratedAt of 20 | true -> markdown:conv_file(source_path(Path), Path); 21 | false -> ok 22 | end. 23 | 24 | resource_path(Path) -> 25 | PrivDir = code:priv_dir(markdown_middleware), 26 | filename:join([PrivDir, Path]). 27 | 28 | source_path(Path) -> 29 | << (filename:rootname(Path))/binary, ".md" >>. 30 | -------------------------------------------------------------------------------- /examples/markdown_middleware/src/markdown_middleware_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(markdown_middleware_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/[...]", cowboy_static, {priv_dir, markdown_middleware, ""}} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch}, 21 | middlewares => [cowboy_router, markdown_converter, cowboy_handler] 22 | }), 23 | markdown_middleware_sup:start_link(). 24 | 25 | stop(_State) -> 26 | ok = cowboy:stop_listener(http). 27 | -------------------------------------------------------------------------------- /examples/markdown_middleware/src/markdown_middleware_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(markdown_middleware_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/rest_basic_auth/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = rest_basic_auth 2 | PROJECT_DESCRIPTION = Cowboy Basic HTTP Authorization example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/rest_basic_auth/relx.config: -------------------------------------------------------------------------------- 1 | {release, {rest_basic_auth_example, "1"}, [rest_basic_auth]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/rest_basic_auth/src/rest_basic_auth_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(rest_basic_auth_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | rest_basic_auth_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/rest_basic_auth/src/rest_basic_auth_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(rest_basic_auth_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/rest_basic_auth/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Handler with basic HTTP authorization. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([is_authorized/2]). 9 | -export([to_text/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | is_authorized(Req, State) -> 15 | case cowboy_req:parse_header(<<"authorization">>, Req) of 16 | {basic, User = <<"Alladin">>, <<"open sesame">>} -> 17 | {true, Req, User}; 18 | _ -> 19 | {{false, <<"Basic realm=\"cowboy\"">>}, Req, State} 20 | end. 21 | 22 | content_types_provided(Req, State) -> 23 | {[ 24 | {<<"text/plain">>, to_text} 25 | ], Req, State}. 26 | 27 | to_text(Req, User) -> 28 | {<< "Hello, ", User/binary, "!\n" >>, Req, User}. 29 | -------------------------------------------------------------------------------- /examples/rest_hello_world/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = rest_hello_world 2 | PROJECT_DESCRIPTION = Cowboy REST Hello World example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/rest_hello_world/relx.config: -------------------------------------------------------------------------------- 1 | {release, {rest_hello_world_example, "1"}, [rest_hello_world]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/rest_hello_world/src/rest_hello_world_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(rest_hello_world_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | rest_hello_world_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/rest_hello_world/src/rest_hello_world_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(rest_hello_world_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/rest_hello_world/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Hello world handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([hello_to_html/2]). 9 | -export([hello_to_json/2]). 10 | -export([hello_to_text/2]). 11 | 12 | init(Req, Opts) -> 13 | {cowboy_rest, Req, Opts}. 14 | 15 | content_types_provided(Req, State) -> 16 | {[ 17 | {<<"text/html">>, hello_to_html}, 18 | {<<"application/json">>, hello_to_json}, 19 | {<<"text/plain">>, hello_to_text} 20 | ], Req, State}. 21 | 22 | hello_to_html(Req, State) -> 23 | Body = <<" 24 | 25 | 26 | REST Hello World! 27 | 28 | 29 |

REST Hello World as HTML!

30 | 31 | ">>, 32 | {Body, Req, State}. 33 | 34 | hello_to_json(Req, State) -> 35 | Body = <<"{\"rest\": \"Hello World!\"}">>, 36 | {Body, Req, State}. 37 | 38 | hello_to_text(Req, State) -> 39 | {<<"REST Hello World as text!">>, Req, State}. 40 | -------------------------------------------------------------------------------- /examples/rest_pastebin/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = rest_pastebin 2 | PROJECT_DESCRIPTION = Cowboy REST Pastebin example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/rest_pastebin/README.asciidoc: -------------------------------------------------------------------------------- 1 | = REST pastebin example 2 | 3 | To try this example, you need GNU `make` and `git` in your PATH. 4 | 5 | To build and run the example, use the following command: 6 | 7 | [source,bash] 8 | $ make run 9 | 10 | Then point your browser to http://localhost:8080 11 | 12 | == Usage 13 | 14 | To upload something to the paste application, you can use `curl`: 15 | 16 | [source,bash] 17 | $ | curl -i --data-urlencode paste@- localhost:8080 18 | 19 | Or, to upload the file `my_file`: 20 | 21 | [source,bash] 22 | curl -i --data-urlencode paste@my_file localhost:8080 23 | 24 | The URL of your data will be in the location header. Alternately, you can visit 25 | http://localhost:8080 with your favorite web browser and submit your paste via 26 | the form. 27 | 28 | Code that has been pasted can be highlighted with ?lang= option if 29 | you have http://www.andre-simon.de/doku/highlight/en/highlight.html[highlight] 30 | installed (although `pygments` or any other should work just fine). 31 | 32 | This will show the contents of the HTML file: 33 | 34 | [source,bash] 35 | curl -i --data-urlencode paste@priv/index.html localhost:8080 36 | curl 37 | 38 | If your terminal supports color sequences and `highlight` is installed, 39 | the following command will show the same contents but with HTML syntax 40 | highlighting. 41 | 42 | [source,bash] 43 | curl ?lang=html 44 | 45 | If you open the same URL in your web browser and your web browser tells 46 | Cowboy that it prefers HTML files, you will see the file highlighted 47 | with special HTML markup and CSS. Firefox is known to work. 48 | -------------------------------------------------------------------------------- /examples/rest_pastebin/priv/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Simple Pastebin 5 | 6 | 7 |

Simple Pastebin

8 |

9 | You can paste your text into the text field to submit, or you can 10 | capture the output of a command with: 11 |

12 | 13 | command | curl -i --data-urlencode paste@- localhost:8080 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/rest_pastebin/priv/index.txt: -------------------------------------------------------------------------------- 1 | Simple Pastebin 2 | --------------- 3 | 4 | You can paste your text into the text field to submit, or you can capture the 5 | output of a command with: 6 | 7 | | curl -i --data-urlencode paste@- localhost:8080 8 | -------------------------------------------------------------------------------- /examples/rest_pastebin/relx.config: -------------------------------------------------------------------------------- 1 | {release, {rest_pastebin_example, "1"}, [rest_pastebin]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/rest_pastebin/src/rest_pastebin_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(rest_pastebin_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/[:paste_id]", toppage_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | rest_pastebin_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/rest_pastebin/src/rest_pastebin_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(rest_pastebin_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = ssl_hello_world 2 | PROJECT_DESCRIPTION = Cowboy SSL Hello World example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | LOCAL_DEPS = ssl 7 | dep_cowboy_commit = master 8 | 9 | REL_DEPS = relx 10 | 11 | include ../../erlang.mk 12 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/priv/ssl/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDTzCCAjegAwIBAgIUD7jNyCgABo8GlnEojOSTFWZzkJswDQYJKoZIhvcNAQEL 3 | BQAwNzELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxEzARBgNVBAoM 4 | Ck5pbmUgTmluZXMwHhcNMjQwMTI2MTQyODExWhcNMzcxMDA0MTQyODExWjA3MQsw 5 | CQYDVQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTETMBEGA1UECgwKTmluZSBO 6 | aW5lczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKfNEwF0v1Gm2e6a 7 | M4hqI3JhmerZSNYWw8NiaUybR5hVUS9X4Chk+/y8kBLX2OYbGGlAxgbOZJa5D+kf 8 | H1iakoUQaILinxPx3yxtIOePS3q/Xi5/EBVTdwLOoI26oSdzY2RTKKAPO1PCcAjq 9 | 6gDpw2u7q26sSU1kul6dD4Wle6+yNtnJdNKo9zLCLXr6TtuHdvbAU1oblLCKZ1Db 10 | /uLkhGaUI/EUNeU1ZJrPmnoneYkTcG5mC5PMFVhqJ3bNYez5Hgr2Ra1Fz0dVgmRM 11 | FpJ8NF6UQgA9dAs2Oh1uWbTjJiX0tO92RslXlhpLHS2VKZWsxiN2bniNXsNKzQ9M 12 | ty0qnxkCAwEAAaNTMFEwHQYDVR0OBBYEFKuBPzB9rBCJNAnUyQMXjkVKIMJlMB8G 13 | A1UdIwQYMBaAFKuBPzB9rBCJNAnUyQMXjkVKIMJlMA8GA1UdEwEB/wQFMAMBAf8w 14 | DQYJKoZIhvcNAQELBQADggEBAHWXDKlY39csROTQ2Dm3CnTj14tj3cW4onsOYTKW 15 | FSlVdMOk3+ionB4vZA/Ino8OjrjiZ2dB3Tvl2J+AxEea3ltDbdh6qVuqSwvQZCeV 16 | 8gWp05wzyTfIpQRD10ZwOU6dzR89T+o7oG/7D8Ydk3nzecthF1aU0YBW8OtuZFog 17 | lC/PIIoVEyUiTEnFJrkQge1OmZWiAuImIed+cEmkw9ZAN2/9i/OxWZKAGoKrmfPq 18 | kzdOoxxFRLnqHo2OYdA0IPpSuGK5ayjYrLgXW0Wa4FKzmDh7Gy+JSrvLuFur9PEi 19 | D0Encva2uX1hAcFQDrzICTsD6ANuIbw0cmlrCJYH6E21PrM= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/priv/ssl/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCnzRMBdL9Rptnu 3 | mjOIaiNyYZnq2UjWFsPDYmlMm0eYVVEvV+AoZPv8vJAS19jmGxhpQMYGzmSWuQ/p 4 | Hx9YmpKFEGiC4p8T8d8sbSDnj0t6v14ufxAVU3cCzqCNuqEnc2NkUyigDztTwnAI 5 | 6uoA6cNru6turElNZLpenQ+FpXuvsjbZyXTSqPcywi16+k7bh3b2wFNaG5SwimdQ 6 | 2/7i5IRmlCPxFDXlNWSaz5p6J3mJE3BuZguTzBVYaid2zWHs+R4K9kWtRc9HVYJk 7 | TBaSfDRelEIAPXQLNjodblm04yYl9LTvdkbJV5YaSx0tlSmVrMYjdm54jV7DSs0P 8 | TLctKp8ZAgMBAAECggEAR5e6D6l5hUNcgS4+ZWnvhLo6utYI+vrMfFzNE3e+5LIm 9 | CL6D74gicRMcn0WDj62ozSNrOfUuOpZrwOlb7OhKMkataIZ7G73bG6/V1aYwLIdg 10 | jhL9UDQDt2lkXAPwBQ54rhHC6AOHqvVu6ocb3tbd32W7P2V3gvNChuKZAEr6Chwc 11 | 1JE5e1k7uZK4rjqZhd86pV2hks/jNknAZpEROTw80qpo3MzlMDMhXyKmyGa84t91 12 | 1bijJ2DMPKsaxSYkWa06Zx3ymiX+qtKFRnSqZo2aEqpeTgQ0hRBSA429d7uCKO0o 13 | kwqOyT85qMFRA+4jfkcAwUi4DELVCFlN/QNWCMH09wKBgQDVuw/sGnjVxCQ/s7pH 14 | FuGA55S1qUtrcYsMHV5uZNtxLOqeAURomgiTpDVNNhLBuJwVjZrBv8Msl1/99EZ7 15 | 8Hws+ERcjlbmyBiq6/VdRW6bJsrFnOS4qUbwWQp0Yztdeu6sTwIEI0KO/oFypf9G 16 | L9mwjXwTvWEFg5etW1BPq+XmMwKBgQDI/KXNul1zCnrOY6sYrbPShYLZgPQRjNi5 17 | Ho6N5NxRc3xhyzExbjNtA/N/30d+/p7H8ND+TgpsYdjvEqqgpQQmCeg3/n6eSzb2 18 | hotCVBt8dU2TjD5v68DLzGv61s7PV81e4grkU5nCe+y7zJMwKGQ8BbmYTBBYEO0P 19 | nTHwuwHhgwKBgQCx2B8OopRro/NZwm69Wq+3+HtIkh98vxUptoJuL6RdzzdG1N0c 20 | gRej6t6jadw/sCLI2HSuxaddQnSQt6Oy29AoB0mzDooHLPdBumgH/Y9ksOnHd57m 21 | fYzWz/CgGjY6ueFCJdgSo1ht7h6+zJvWxlhIzeIx9sJ1uSMMEFCKiwoY+wKBgGb+ 22 | kTjLt/er9yKskJEk8nF/WX58RpZ3xteWgRbVoNFcjPDQX3UlM9U5oR52HP1HHbb4 23 | ASFQfKbtvW1F84o/BdE4YnfPQrN7d779U3+5+hvdQNPLmnNgLHxDVVJFodU++U8W 24 | Jt66uKChQL88JnEXQcZAaMtSr01x3wmRVHY4Xs5hAoGBAMPfa+rcGukjbMF+MZ0P 25 | ZV1Pq7AxVJ/C0XINnpZrsN+e6dO52Y2VXbnQkML7PKZXzSY88QwunBp88VoPlDux 26 | llmLZc54zUFlsC1iHrEzt+hoxFG0tfL83vic5kSx6u5oZdxjZ2InqTzE8TmORU3v 27 | 6/ik7Q4VeDQ5uLnR4GiLW+qj 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/relx.config: -------------------------------------------------------------------------------- 1 | {release, {ssl_hello_world_example, "1"}, [ssl_hello_world]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/src/ssl_hello_world_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(ssl_hello_world_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | Dispatch = cowboy_router:compile([ 15 | {'_', [ 16 | {"/", toppage_h, []} 17 | ]} 18 | ]), 19 | PrivDir = code:priv_dir(ssl_hello_world), 20 | {ok, _} = cowboy:start_tls(https, [ 21 | {port, 8443}, 22 | {certfile, PrivDir ++ "/ssl/cert.pem"}, 23 | {keyfile, PrivDir ++ "/ssl/key.pem"} 24 | ], #{env => #{dispatch => Dispatch}}), 25 | ssl_hello_world_sup:start_link(). 26 | 27 | stop(_State) -> 28 | ok = cowboy:stop_listener(https). 29 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/src/ssl_hello_world_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(ssl_hello_world_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/ssl_hello_world/src/toppage_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Hello world handler. 4 | -module(toppage_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req0, Opts) -> 9 | Req = cowboy_req:reply(200, #{ 10 | <<"content-type">> => <<"text/plain">> 11 | }, <<"Hello world!">>, Req0), 12 | {ok, Req, Opts}. 13 | -------------------------------------------------------------------------------- /examples/upload/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = upload 2 | PROJECT_DESCRIPTION = Cowboy multipart upload example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/upload/README.asciidoc: -------------------------------------------------------------------------------- 1 | = Multipart upload example 2 | 3 | To try this example, you need GNU `make` and `git` in your PATH. 4 | 5 | To build and run the example, use the following command: 6 | 7 | [source,bash] 8 | $ make run 9 | 10 | Then point your browser to http://localhost:8080 11 | 12 | The uploaded file will be displayed in the shell directly. 13 | -------------------------------------------------------------------------------- /examples/upload/priv/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Multipart upload example 5 | 6 | 7 | 8 |
9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/upload/relx.config: -------------------------------------------------------------------------------- 1 | {release, {upload_example, "1"}, [upload]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/upload/src/upload_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(upload_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | start(_Type, _Args) -> 13 | Dispatch = cowboy_router:compile([ 14 | {'_', [ 15 | {"/", cowboy_static, {priv_file, upload, "index.html"}}, 16 | {"/upload", upload_h, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 20 | env => #{dispatch => Dispatch} 21 | }), 22 | upload_sup:start_link(). 23 | 24 | stop(_State) -> 25 | ok = cowboy:stop_listener(http). 26 | -------------------------------------------------------------------------------- /examples/upload/src/upload_h.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @doc Upload handler. 4 | -module(upload_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req, Opts) -> 9 | {ok, Headers, Req2} = cowboy_req:read_part(Req), 10 | {ok, Data, Req3} = cowboy_req:read_part_body(Req2), 11 | {file, <<"inputfile">>, Filename, ContentType} 12 | = cow_multipart:form_data(Headers), 13 | io:format("Received file ~p of content-type ~p as follow:~n~p~n~n", 14 | [Filename, ContentType, Data]), 15 | {ok, Req3, Opts}. 16 | -------------------------------------------------------------------------------- /examples/upload/src/upload_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(upload_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/websocket/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = websocket 2 | PROJECT_DESCRIPTION = Cowboy Websocket example 3 | PROJECT_VERSION = 1 4 | 5 | DEPS = cowboy 6 | dep_cowboy_commit = master 7 | 8 | REL_DEPS = relx 9 | 10 | include ../../erlang.mk 11 | -------------------------------------------------------------------------------- /examples/websocket/README.asciidoc: -------------------------------------------------------------------------------- 1 | = Websocket example 2 | 3 | To try this example, you need GNU `make` and `git` in your PATH. 4 | 5 | To build and run the example, use the following command: 6 | 7 | [source,bash] 8 | $ make run 9 | 10 | Then point your browser to http://localhost:8080 11 | -------------------------------------------------------------------------------- /examples/websocket/relx.config: -------------------------------------------------------------------------------- 1 | {release, {websocket_example, "1"}, [websocket]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/websocket/src/websocket_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(websocket_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | start(_Type, _Args) -> 13 | Dispatch = cowboy_router:compile([ 14 | {'_', [ 15 | {"/", cowboy_static, {priv_file, websocket, "index.html"}}, 16 | {"/websocket", ws_h, []}, 17 | {"/static/[...]", cowboy_static, {priv_dir, websocket, "static"}} 18 | ]} 19 | ]), 20 | {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ 21 | env => #{dispatch => Dispatch} 22 | }), 23 | websocket_sup:start_link(). 24 | 25 | stop(_State) -> 26 | ok = cowboy:stop_listener(http). 27 | -------------------------------------------------------------------------------- /examples/websocket/src/websocket_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(websocket_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | Procs = [], 23 | {ok, {{one_for_one, 10, 10}, Procs}}. 24 | -------------------------------------------------------------------------------- /examples/websocket/src/ws_h.erl: -------------------------------------------------------------------------------- 1 | -module(ws_h). 2 | 3 | -export([init/2]). 4 | -export([websocket_init/1]). 5 | -export([websocket_handle/2]). 6 | -export([websocket_info/2]). 7 | 8 | init(Req, Opts) -> 9 | {cowboy_websocket, Req, Opts}. 10 | 11 | websocket_init(State) -> 12 | erlang:start_timer(1000, self(), <<"Hello!">>), 13 | {[], State}. 14 | 15 | websocket_handle({text, Msg}, State) -> 16 | {[{text, << "That's what she said! ", Msg/binary >>}], State}; 17 | websocket_handle(_Data, State) -> 18 | {[], State}. 19 | 20 | websocket_info({timeout, _Ref, Msg}, State) -> 21 | erlang:start_timer(1000, self(), <<"How' you doin'?">>), 22 | {[{text, Msg}], State}; 23 | websocket_info(_Info, State) -> 24 | {[], State}. 25 | -------------------------------------------------------------------------------- /plugins.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE for licensing information. 2 | 3 | # Plain HTTP handlers. 4 | define tpl_cowboy.http 5 | -module($(n)). 6 | -behavior(cowboy_handler). 7 | 8 | -export([init/2]). 9 | 10 | init(Req, State) -> 11 | {ok, Req, State}. 12 | endef 13 | 14 | # Loop handlers. 15 | define tpl_cowboy.loop 16 | -module($(n)). 17 | -behavior(cowboy_loop). 18 | 19 | -export([init/2]). 20 | -export([info/3]). 21 | 22 | init(Req, State) -> 23 | {cowboy_loop, Req, State, hibernate}. 24 | 25 | info(_Info, Req, State) -> 26 | {ok, Req, State, hibernate}. 27 | endef 28 | 29 | # REST handlers. 30 | define tpl_cowboy.rest 31 | -module($(n)). 32 | -behavior(cowboy_rest). 33 | 34 | -export([init/2]). 35 | -export([content_types_provided/2]). 36 | -export([to_html/2]). 37 | 38 | init(Req, State) -> 39 | {cowboy_rest, Req, State}. 40 | 41 | content_types_provided(Req, State) -> 42 | {[ 43 | {{<<"text">>, <<"html">>, '*'}, to_html} 44 | ], Req, State}. 45 | 46 | to_html(Req, State) -> 47 | {<<"This is REST!">>, Req, State}. 48 | endef 49 | 50 | # Websocket handlers. 51 | define tpl_cowboy.ws 52 | -module($(n)). 53 | -behavior(cowboy_websocket). 54 | 55 | -export([init/2]). 56 | -export([websocket_init/1]). 57 | -export([websocket_handle/2]). 58 | -export([websocket_info/2]). 59 | 60 | init(Req, State) -> 61 | {cowboy_websocket, Req, State}. 62 | 63 | websocket_init(State) -> 64 | {[], State}. 65 | 66 | websocket_handle({text, Data}, State) -> 67 | {[{text, Data}], State}; 68 | websocket_handle({binary, Data}, State) -> 69 | {[{binary, Data}], State}; 70 | websocket_handle(_Frame, State) -> 71 | {[], State}. 72 | 73 | websocket_info(_Info, State) -> 74 | {[], State}. 75 | endef 76 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {deps, [ 2 | {cowlib,".*",{git,"https://github.com/ninenines/cowlib",{tag,"2.14.0"}}},{ranch,".*",{git,"https://github.com/ninenines/ranch",{tag,"1.8.1"}}} 3 | ]}. 4 | {erl_opts, [debug_info,warn_export_vars,warn_shadow_vars,warn_obsolete_guard,warn_missing_spec,warn_untyped_record]}. 5 | -------------------------------------------------------------------------------- /src/cowboy_app.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(cowboy_app). 16 | -behaviour(application). 17 | 18 | -export([start/2]). 19 | -export([stop/1]). 20 | 21 | -spec start(_, _) -> {ok, pid()}. 22 | start(_, _) -> 23 | cowboy_sup:start_link(). 24 | 25 | -spec stop(_) -> ok. 26 | stop(_) -> 27 | ok. 28 | -------------------------------------------------------------------------------- /src/cowboy_middleware.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(cowboy_middleware). 16 | 17 | -type env() :: #{atom() => any()}. 18 | -export_type([env/0]). 19 | 20 | -callback execute(Req, Env) 21 | -> {ok, Req, Env} 22 | | {suspend, module(), atom(), [any()]} 23 | | {stop, Req} 24 | when Req::cowboy_req:req(), Env::env(). 25 | -------------------------------------------------------------------------------- /src/cowboy_sub_protocol.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% Copyright (c) James Fish 3 | %% 4 | %% Permission to use, copy, modify, and/or distribute this software for any 5 | %% purpose with or without fee is hereby granted, provided that the above 6 | %% copyright notice and this permission notice appear in all copies. 7 | %% 8 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | -module(cowboy_sub_protocol). 17 | 18 | -callback upgrade(Req, Env, module(), any()) 19 | -> {ok, Req, Env} | {suspend, module(), atom(), [any()]} | {stop, Req} 20 | when Req::cowboy_req:req(), Env::cowboy_middleware:env(). 21 | 22 | -callback upgrade(Req, Env, module(), any(), any()) 23 | -> {ok, Req, Env} | {suspend, module(), atom(), [any()]} | {stop, Req} 24 | when Req::cowboy_req:req(), Env::cowboy_middleware:env(). 25 | -------------------------------------------------------------------------------- /src/cowboy_sup.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(cowboy_sup). 16 | -behaviour(supervisor). 17 | 18 | -export([start_link/0]). 19 | -export([init/1]). 20 | 21 | -spec start_link() -> {ok, pid()}. 22 | start_link() -> 23 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 24 | 25 | -spec init([]) 26 | -> {ok, {{supervisor:strategy(), 10, 10}, [supervisor:child_spec()]}}. 27 | init([]) -> 28 | Procs = [{cowboy_clock, {cowboy_clock, start_link, []}, 29 | permanent, 5000, worker, [cowboy_clock]}], 30 | {ok, {{one_for_one, 10, 10}, Procs}}. 31 | -------------------------------------------------------------------------------- /test/cover.spec: -------------------------------------------------------------------------------- 1 | {incl_app, cowboy, details}. 2 | -------------------------------------------------------------------------------- /test/cowboy_ct_hook.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(cowboy_ct_hook). 16 | 17 | -export([init/2]). 18 | 19 | init(_, _) -> 20 | ct_helper:start([cowboy, gun]), 21 | ct_helper:make_certs_in_ets(), 22 | error_logger:add_report_handler(ct_helper_error_h), 23 | {ok, undefined}. 24 | -------------------------------------------------------------------------------- /test/handlers/accept_callback_h.erl: -------------------------------------------------------------------------------- 1 | %% This module returns something different in 2 | %% AcceptCallback depending on the query string. 3 | 4 | -module(accept_callback_h). 5 | 6 | -export([init/2]). 7 | -export([allowed_methods/2]). 8 | -export([content_types_accepted/2]). 9 | -export([put_text_plain/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | allowed_methods(Req, State) -> 15 | {[<<"PUT">>, <<"POST">>, <<"PATCH">>], Req, State}. 16 | 17 | content_types_accepted(Req, State) -> 18 | {[{{<<"text">>, <<"plain">>, []}, put_text_plain}], Req, State}. 19 | 20 | put_text_plain(Req=#{qs := <<"false">>}, State) -> 21 | {false, Req, State}; 22 | put_text_plain(Req=#{qs := <<"true">>}, State) -> 23 | {true, Req, State}. 24 | -------------------------------------------------------------------------------- /test/handlers/accept_callback_missing_h.erl: -------------------------------------------------------------------------------- 1 | -module(accept_callback_missing_h). 2 | 3 | -export([init/2]). 4 | -export([allowed_methods/2]). 5 | -export([content_types_accepted/2]). 6 | 7 | init(Req, State) -> 8 | {cowboy_rest, Req, State}. 9 | 10 | allowed_methods(Req, State) -> 11 | {[<<"PUT">>], Req, State}. 12 | 13 | content_types_accepted(Req, State) -> 14 | ct_helper_error_h:ignore(cowboy_rest, process_content_type, 3), 15 | {[{<<"text/plain">>, accept}], Req, State}. 16 | -------------------------------------------------------------------------------- /test/handlers/asterisk_h.erl: -------------------------------------------------------------------------------- 1 | %% This module echoes back the value the test is interested in. 2 | 3 | -module(asterisk_h). 4 | 5 | -export([init/2]). 6 | 7 | init(Req, Opts) -> 8 | echo(cowboy_req:header(<<"x-echo">>, Req), Req, Opts). 9 | 10 | echo(undefined, Req, Opts) -> 11 | {ok, cowboy_req:reply(200, Req), Opts}; 12 | echo(What, Req, Opts) -> 13 | F = binary_to_atom(What, latin1), 14 | Value = case cowboy_req:F(Req) of 15 | V when is_integer(V) -> integer_to_binary(V); 16 | V -> V 17 | end, 18 | {ok, cowboy_req:reply(200, #{}, Value, Req), Opts}. 19 | -------------------------------------------------------------------------------- /test/handlers/charset_in_content_types_provided_h.erl: -------------------------------------------------------------------------------- 1 | %% This module has a media type provided with an explicit charset. 2 | 3 | -module(charset_in_content_types_provided_h). 4 | 5 | -export([init/2]). 6 | -export([content_types_provided/2]). 7 | -export([charsets_provided/2]). 8 | -export([get_text_plain/2]). 9 | 10 | init(Req, Opts) -> 11 | {cowboy_rest, Req, Opts}. 12 | 13 | content_types_provided(Req, State) -> 14 | {[ 15 | {{<<"text">>, <<"plain">>, [{<<"charset">>, <<"utf-8">>}]}, get_text_plain} 16 | ], Req, State}. 17 | 18 | charsets_provided(Req, State) -> 19 | {[<<"utf-16">>, <<"iso-8861-1">>], Req, State}. 20 | 21 | get_text_plain(Req, State) -> 22 | {<<"This is REST!">>, Req, State}. 23 | -------------------------------------------------------------------------------- /test/handlers/charset_in_content_types_provided_implicit_h.erl: -------------------------------------------------------------------------------- 1 | %% This module has a media type provided with a wildcard 2 | %% and a list of charsets that is limited. 3 | 4 | -module(charset_in_content_types_provided_implicit_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([charsets_provided/2]). 9 | -export([get_text_plain/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | content_types_provided(Req, State) -> 15 | {[ 16 | {{<<"text">>, <<"plain">>, '*'}, get_text_plain} 17 | ], Req, State}. 18 | 19 | charsets_provided(Req, State) -> 20 | {[<<"utf-8">>, <<"utf-16">>], Req, State}. 21 | 22 | get_text_plain(Req, State) -> 23 | {<<"This is REST!">>, Req, State}. 24 | 25 | -------------------------------------------------------------------------------- /test/handlers/charset_in_content_types_provided_implicit_no_callback_h.erl: -------------------------------------------------------------------------------- 1 | %% This module has a media type provided with a wildcard 2 | %% and lacks a charsets_provided callback. 3 | 4 | -module(charset_in_content_types_provided_implicit_no_callback_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([get_text_plain/2]). 9 | 10 | init(Req, Opts) -> 11 | {cowboy_rest, Req, Opts}. 12 | 13 | content_types_provided(Req, State) -> 14 | {[ 15 | {{<<"text">>, <<"plain">>, '*'}, get_text_plain} 16 | ], Req, State}. 17 | 18 | get_text_plain(Req, State) -> 19 | {<<"This is REST!">>, Req, State}. 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/handlers/charsets_provided_empty_h.erl: -------------------------------------------------------------------------------- 1 | %% This module has a text and non-text media type, 2 | %% but provides no charset. All requests will result 3 | %% in a 406 not acceptable. 4 | 5 | -module(charsets_provided_empty_h). 6 | 7 | -export([init/2]). 8 | -export([content_types_provided/2]). 9 | -export([charsets_provided/2]). 10 | -export([get_text_plain/2]). 11 | -export([get_application_json/2]). 12 | 13 | init(Req, Opts) -> 14 | {cowboy_rest, Req, Opts}. 15 | 16 | content_types_provided(Req, State) -> 17 | {[ 18 | {{<<"text">>, <<"plain">>, []}, get_text_plain}, 19 | {{<<"application">>, <<"json">>, []}, get_application_json} 20 | ], Req, State}. 21 | 22 | charsets_provided(Req, State) -> 23 | {[], Req, State}. 24 | 25 | get_text_plain(Req, State) -> 26 | {<<"This is REST!">>, Req, State}. 27 | 28 | get_application_json(Req, State) -> 29 | {<<"{\"hello\": \"rest\"}">>, Req, State}. 30 | 31 | -------------------------------------------------------------------------------- /test/handlers/charsets_provided_h.erl: -------------------------------------------------------------------------------- 1 | %% This module has a text and non-text media type, 2 | %% and provides two charsets. 3 | 4 | -module(charsets_provided_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([charsets_provided/2]). 9 | -export([get_text_plain/2]). 10 | -export([get_application_json/2]). 11 | 12 | init(Req, Opts) -> 13 | {cowboy_rest, Req, Opts}. 14 | 15 | content_types_provided(Req, State) -> 16 | {[ 17 | {{<<"text">>, <<"plain">>, []}, get_text_plain}, 18 | {{<<"application">>, <<"json">>, []}, get_application_json} 19 | ], Req, State}. 20 | 21 | charsets_provided(Req, State) -> 22 | {[<<"utf-8">>, <<"utf-16">>], Req, State}. 23 | 24 | get_text_plain(Req, State) -> 25 | {<<"This is REST!">>, Req, State}. 26 | 27 | get_application_json(Req, State) -> 28 | {<<"{\"hello\": \"rest\"}">>, Req, State}. 29 | -------------------------------------------------------------------------------- /test/handlers/content_types_accepted_h.erl: -------------------------------------------------------------------------------- 1 | %% This module returns something different in 2 | %% content_types_accepted depending on the query string. 3 | 4 | -module(content_types_accepted_h). 5 | 6 | -export([init/2]). 7 | -export([allowed_methods/2]). 8 | -export([content_types_accepted/2]). 9 | -export([put_multipart_mixed/2]). 10 | -export([put_text_plain/2]). 11 | 12 | init(Req, Opts) -> 13 | {cowboy_rest, Req, Opts}. 14 | 15 | allowed_methods(Req, State) -> 16 | {[<<"PUT">>], Req, State}. 17 | 18 | content_types_accepted(Req=#{qs := <<"multipart">>}, State) -> 19 | {[ 20 | {{<<"multipart">>, <<"mixed">>, [{<<"v">>, <<"1">>}]}, put_multipart_mixed} 21 | ], Req, State}; 22 | content_types_accepted(Req=#{qs := <<"param">>}, State) -> 23 | {[{{<<"text">>, <<"plain">>, [{<<"charset">>, <<"utf-8">>}]}, put_text_plain}], Req, State}; 24 | content_types_accepted(Req=#{qs := <<"wildcard">>}, State) -> 25 | {[{'*', put_text_plain}], Req, State}; 26 | content_types_accepted(Req=#{qs := <<"wildcard-param">>}, State) -> 27 | {[{{<<"text">>, <<"plain">>, '*'}, put_text_plain}], Req, State}. 28 | 29 | put_multipart_mixed(Req, State) -> 30 | {true, Req, State}. 31 | 32 | put_text_plain(Req0, State) -> 33 | {ok, _, Req} = cowboy_req:read_body(Req0), 34 | {true, Req, State}. 35 | -------------------------------------------------------------------------------- /test/handlers/content_types_provided_h.erl: -------------------------------------------------------------------------------- 1 | %% This module has different content_types_provided values 2 | %% and/or sends a different response body depending on the 3 | %% query string. 4 | 5 | -module(content_types_provided_h). 6 | 7 | -export([init/2]). 8 | -export([content_types_provided/2]). 9 | -export([get_text_plain/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | content_types_provided(Req=#{qs := <<"invalid-type">>}, State) -> 15 | ct_helper:ignore(cowboy_rest, normalize_content_types, 2), 16 | {[{{'*', '*', '*'}, get_text_plain}], Req, State}; 17 | content_types_provided(Req=#{qs := <<"wildcard-param">>}, State) -> 18 | {[{{<<"text">>, <<"plain">>, '*'}, get_text_plain}], Req, State}. 19 | 20 | get_text_plain(Req=#{qs := <<"invalid-type">>}, State) -> 21 | {<<"invalid-type">>, Req, State}; 22 | get_text_plain(Req=#{qs := <<"wildcard-param">>}, State) -> 23 | {_, _, Param} = maps:get(media_type, Req), 24 | Body = if 25 | Param =:= [] -> <<"[]">>; 26 | Param =/= [] -> 27 | iolist_to_binary([[Key, $=, Value] || {Key, Value} <- Param]) 28 | end, 29 | {Body, Req, State}. 30 | -------------------------------------------------------------------------------- /test/handlers/crash_h.erl: -------------------------------------------------------------------------------- 1 | %% This module crashes immediately. 2 | 3 | -module(crash_h). 4 | 5 | -behaviour(cowboy_handler). 6 | 7 | -export([init/2]). 8 | 9 | -spec init(_, _) -> no_return(). 10 | init(_, external_exit) -> 11 | ct_helper:ignore(?MODULE, init, 2), 12 | exit(self(), ct_helper_ignore); 13 | init(_, no_reply) -> 14 | ct_helper:ignore(?MODULE, init, 2), 15 | error(crash); 16 | init(Req, reply) -> 17 | _ = cowboy_req:reply(200, Req), 18 | ct_helper:ignore(?MODULE, init, 2), 19 | error(crash). 20 | -------------------------------------------------------------------------------- /test/handlers/create_resource_h.erl: -------------------------------------------------------------------------------- 1 | -module(create_resource_h). 2 | 3 | -export([init/2]). 4 | -export([allowed_methods/2]). 5 | -export([resource_exists/2]). 6 | -export([content_types_accepted/2]). 7 | -export([from_text/2]). 8 | 9 | init(Req, Opts) -> 10 | {cowboy_rest, Req, Opts}. 11 | 12 | allowed_methods(Req, State) -> 13 | {[<<"POST">>], Req, State}. 14 | 15 | resource_exists(Req, State) -> 16 | {true, Req, State}. 17 | 18 | content_types_accepted(Req, State) -> 19 | {[{{<<"application">>, <<"text">>, []}, from_text}], Req, State}. 20 | 21 | from_text(Req=#{qs := Qs}, State) -> 22 | NewURI = [cowboy_req:uri(Req), "/foo"], 23 | case Qs of 24 | <<"created">> -> 25 | {{created, NewURI}, Req, State}; 26 | <<"see_other">> -> 27 | {{see_other, NewURI}, Req, State} 28 | end. 29 | -------------------------------------------------------------------------------- /test/handlers/custom_req_fields_h.erl: -------------------------------------------------------------------------------- 1 | %% This module adds custom fields to the Req object. 2 | %% It is only meant to be checked by Dialyzer. 3 | 4 | -module(custom_req_fields_h). 5 | 6 | -export([init/2]). 7 | 8 | -spec init(Req, Opts) -> {ok, Req, Opts} when Req::cowboy_req:req(). 9 | init(Req, Opts) -> 10 | {ok, Req#{'_myapp_auth_method' => pubkey}, Opts}. 11 | -------------------------------------------------------------------------------- /test/handlers/default_h.erl: -------------------------------------------------------------------------------- 1 | %% This module does not do anything. 2 | 3 | -module(default_h). 4 | 5 | -export([init/2]). 6 | 7 | init(Req, Opts) -> 8 | {ok, Req, Opts}. 9 | -------------------------------------------------------------------------------- /test/handlers/delay_hello_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a hello world response after a delay. 2 | 3 | -module(delay_hello_h). 4 | 5 | -export([init/2]). 6 | 7 | init(Req, Delay) when is_integer(Delay) -> 8 | init(Req, #{delay => Delay}); 9 | init(Req, Opts=#{delay := Delay}) -> 10 | _ = case Opts of 11 | #{notify_received := Pid} -> 12 | Pid ! {request_received, maps:get(path, Req)}; 13 | _ -> 14 | ok 15 | end, 16 | timer:sleep(Delay), 17 | {ok, cowboy_req:reply(200, #{}, <<"Hello world!">>, Req), Delay}. 18 | -------------------------------------------------------------------------------- /test/handlers/delete_resource_h.erl: -------------------------------------------------------------------------------- 1 | %% This module accepts a multipart media type with parameters 2 | %% that do not include boundary. 3 | 4 | -module(delete_resource_h). 5 | 6 | -export([init/2]). 7 | -export([allowed_methods/2]). 8 | -export([delete_resource/2]). 9 | 10 | init(Req, Opts) -> 11 | {cowboy_rest, Req, Opts}. 12 | 13 | allowed_methods(Req, State) -> 14 | {[<<"DELETE">>], Req, State}. 15 | 16 | delete_resource(#{qs := <<"missing">>}, _) -> 17 | no_call. 18 | -------------------------------------------------------------------------------- /test/handlers/expires_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a different expires value 2 | %% depending on the query string. 3 | 4 | -module(expires_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([get_text_plain/2]). 9 | -export([expires/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | content_types_provided(Req, State) -> 15 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 16 | 17 | get_text_plain(Req, State) -> 18 | {<<"This is REST!">>, Req, State}. 19 | 20 | expires(Req=#{qs := <<"tuple">>}, State) -> 21 | {{{2012, 9, 21}, {22, 36, 14}}, Req, State}; 22 | expires(Req=#{qs := <<"binary">>}, State) -> 23 | {<<"0">>, Req, State}; 24 | expires(Req=#{qs := <<"undefined">>}, State) -> 25 | {undefined, Req, State}; 26 | %% Simulate the callback being missing in other cases. 27 | expires(#{qs := <<"missing">>}, _) -> 28 | no_call. 29 | -------------------------------------------------------------------------------- /test/handlers/generate_etag_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a different etag value 2 | %% depending on the query string. 3 | 4 | -module(generate_etag_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([get_text_plain/2]). 9 | -export([generate_etag/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | content_types_provided(Req, State) -> 15 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 16 | 17 | get_text_plain(Req, State) -> 18 | {<<"This is REST!">>, Req, State}. 19 | 20 | %% Correct return values from generate_etag/2. 21 | generate_etag(Req=#{qs := <<"tuple-weak">>}, State) -> 22 | {{weak, <<"etag-header-value">>}, Req, State}; 23 | generate_etag(Req=#{qs := <<"tuple-strong">>}, State) -> 24 | {{strong, <<"etag-header-value">>}, Req, State}; 25 | %% Backwards compatible return values from generate_etag/2. 26 | generate_etag(Req=#{qs := <<"binary-weak-quoted">>}, State) -> 27 | {<<"W/\"etag-header-value\"">>, Req, State}; 28 | generate_etag(Req=#{qs := <<"binary-strong-quoted">>}, State) -> 29 | {<<"\"etag-header-value\"">>, Req, State}; 30 | %% Invalid return values from generate_etag/2. 31 | generate_etag(Req=#{qs := <<"binary-weak-unquoted">>}, State) -> 32 | ct_helper_error_h:ignore(cow_http_hd, parse_etag, 1), 33 | {<<"W/etag-header-value">>, Req, State}; 34 | generate_etag(Req=#{qs := <<"binary-strong-unquoted">>}, State) -> 35 | ct_helper_error_h:ignore(cow_http_hd, parse_etag, 1), 36 | {<<"etag-header-value">>, Req, State}; 37 | %% Returning 'undefined' to indicate no etag. 38 | generate_etag(Req=#{qs := <<"undefined">>}, State) -> 39 | {undefined, Req, State}; 40 | %% Simulate the callback being missing in other cases. 41 | generate_etag(#{qs := <<"missing">>}, _) -> 42 | no_call. 43 | -------------------------------------------------------------------------------- /test/handlers/hello_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a hello world response. 2 | 3 | -module(hello_h). 4 | 5 | -export([init/2]). 6 | 7 | init(Req, Opts) -> 8 | {ok, cowboy_req:reply(200, #{}, <<"Hello world!">>, Req), Opts}. 9 | -------------------------------------------------------------------------------- /test/handlers/if_range_h.erl: -------------------------------------------------------------------------------- 1 | %% This module defines the ranges_provided callback 2 | %% and a generate_etag callback that returns something 3 | %% different depending on query string. It also defines 4 | %% a last_modified callback that must be ignored when a 5 | %% date is provided in if_range. 6 | 7 | -module(if_range_h). 8 | 9 | -export([init/2]). 10 | -export([content_types_provided/2]). 11 | -export([ranges_provided/2]). 12 | -export([generate_etag/2]). 13 | -export([last_modified/2]). 14 | -export([get_text_plain/2]). 15 | -export([get_text_plain_bytes/2]). 16 | 17 | init(Req, State) -> 18 | {cowboy_rest, Req, State}. 19 | 20 | content_types_provided(Req, State) -> 21 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 22 | 23 | %% Simulate the callback being missing. 24 | ranges_provided(#{qs := <<"missing-ranges_provided">>}, _) -> 25 | no_call; 26 | ranges_provided(Req=#{qs := <<"empty-ranges_provided">>}, State) -> 27 | {[], Req, State}; 28 | ranges_provided(Req, State) -> 29 | {[{<<"bytes">>, get_text_plain_bytes}], Req, State}. 30 | 31 | generate_etag(Req=#{qs := <<"weak-etag">>}, State) -> 32 | {{weak, <<"weak-no-match">>}, Req, State}; 33 | generate_etag(Req, State) -> 34 | {{strong, <<"strong-and-match">>}, Req, State}. 35 | 36 | last_modified(Req, State) -> 37 | {{{2222, 2, 22}, {11, 11, 11}}, Req, State}. 38 | 39 | get_text_plain(Req, State) -> 40 | {<<"This is REST!">>, Req, State}. 41 | 42 | get_text_plain_bytes(Req, State) -> 43 | %% We send everything in one part, since we are not testing 44 | %% this callback specifically. 45 | Body = <<"This is ranged REST!">>, 46 | {[{{0, byte_size(Body) - 1, byte_size(Body)}, Body}], Req, State}. 47 | -------------------------------------------------------------------------------- /test/handlers/last_modified_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a different last-modified value 2 | %% depending on the query string. 3 | 4 | -module(last_modified_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([get_text_plain/2]). 9 | -export([last_modified/2]). 10 | 11 | init(Req, Opts) -> 12 | {cowboy_rest, Req, Opts}. 13 | 14 | content_types_provided(Req, State) -> 15 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 16 | 17 | get_text_plain(Req, State) -> 18 | {<<"This is REST!">>, Req, State}. 19 | 20 | last_modified(Req=#{qs := <<"tuple">>}, State) -> 21 | {{{2012, 9, 21}, {22, 36, 14}}, Req, State}; 22 | %% Simulate the callback being missing in other cases. 23 | last_modified(#{qs := <<"missing">>}, _) -> 24 | no_call. 25 | -------------------------------------------------------------------------------- /test/handlers/long_polling_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler for long-polling. 2 | %% It starts by sending itself a message after 200ms, 3 | %% then sends another after that for a total of 3 messages. 4 | %% When it receives the last message, it sends a 102 reply back. 5 | 6 | -module(long_polling_h). 7 | 8 | -export([init/2]). 9 | -export([info/3]). 10 | -export([terminate/3]). 11 | 12 | init(Req, _) -> 13 | erlang:send_after(200, self(), timeout), 14 | {cowboy_loop, Req, 2, hibernate}. 15 | 16 | info(timeout, Req, 0) -> 17 | %% Send an unused status code to make sure there's no 18 | %% conflict with whatever Cowboy may send itself. 19 | {stop, cowboy_req:reply(<<"299 OK!">>, Req), 0}; 20 | info(timeout, Req, Count) -> 21 | erlang:send_after(200, self(), timeout), 22 | {ok, Req, Count - 1, hibernate}. 23 | 24 | terminate(stop, _, 0) -> 25 | ok; 26 | terminate({error, overflow}, _, _) -> 27 | ok. 28 | -------------------------------------------------------------------------------- /test/handlers/long_polling_sys_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that does nothing 2 | %% and expects a crash to happen. 3 | 4 | -module(long_polling_sys_h). 5 | 6 | -export([init/2]). 7 | -export([info/3]). 8 | -export([terminate/3]). 9 | 10 | init(Req, _) -> 11 | process_flag(trap_exit, true), 12 | erlang:send_after(500, self(), timeout), 13 | {cowboy_loop, Req, undefined}. 14 | 15 | info(timeout, Req, State) -> 16 | %% Send an unused status code to make sure there's no 17 | %% conflict with whatever Cowboy may send itself. 18 | {ok, cowboy_req:reply(<<"299 OK!">>, Req), State}; 19 | info(_, Req, State) -> 20 | {ok, Req, State}. 21 | 22 | terminate(_, _, _) -> 23 | ok. 24 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_abort_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that reads 2 | %% 1000 bytes of the request body after sending itself 3 | %% a message, then terminates the stream. 4 | 5 | -module(loop_handler_abort_h). 6 | 7 | -export([init/2]). 8 | -export([info/3]). 9 | -export([terminate/3]). 10 | 11 | init(Req, _) -> 12 | self() ! timeout, 13 | {cowboy_loop, Req, undefined, hibernate}. 14 | 15 | info(timeout, Req0, State) -> 16 | {_Status, Body, Req} = cowboy_req:read_body(Req0, #{length => 1000}), 17 | 1000 = byte_size(Body), 18 | {stop, cowboy_req:reply(200, Req), State}. 19 | 20 | terminate(stop, _, _) -> 21 | ok. 22 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_body_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that reads 2 | %% the request body after sending itself a message, 3 | %% checks that its size is exactly 100000 bytes, 4 | %% then sends a 200 reply back. 5 | 6 | -module(loop_handler_body_h). 7 | 8 | -export([init/2]). 9 | -export([info/3]). 10 | -export([terminate/3]). 11 | 12 | init(Req, _) -> 13 | self() ! timeout, 14 | {cowboy_loop, Req, undefined, hibernate}. 15 | 16 | info(timeout, Req0, State) -> 17 | {ok, Body, Req} = cowboy_req:read_body(Req0), 18 | 100000 = byte_size(Body), 19 | {stop, cowboy_req:reply(200, Req), State}. 20 | 21 | terminate(stop, _, _) -> 22 | ok. 23 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_endless_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that streams endless data. 2 | 3 | -module(loop_handler_endless_h). 4 | 5 | -export([init/2]). 6 | -export([info/3]). 7 | 8 | init(Req0, #{delay := Delay} = Opts) -> 9 | case cowboy_req:header(<<"x-test-pid">>, Req0) of 10 | BinPid when is_binary(BinPid) -> 11 | Pid = list_to_pid(binary_to_list(BinPid)), 12 | Pid ! {Pid, self(), init}, 13 | ok; 14 | _ -> 15 | ok 16 | end, 17 | erlang:send_after(Delay, self(), timeout), 18 | Req = cowboy_req:stream_reply(200, Req0), 19 | {cowboy_loop, Req, Opts}. 20 | 21 | info(timeout, Req, State) -> 22 | cowboy_req:stream_body(<<0:10000/unit:8>>, nofin, Req), 23 | %% Equivalent to a 0 timeout. 24 | self() ! timeout, 25 | {ok, Req, State}. 26 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_timeout_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that sends 2 | %% itself a timeout that will intentionally arrive 3 | %% after the HTTP/1.1 request_timeout. The protocol 4 | %% is not supposed to close the connection when a 5 | %% request is ongoing, and therefore this handler 6 | %% will eventually send a 200 reply. 7 | 8 | -module(loop_handler_timeout_h). 9 | 10 | -export([init/2]). 11 | -export([info/3]). 12 | -export([terminate/3]). 13 | 14 | init(Req, _) -> 15 | erlang:send_after(6000, self(), timeout), 16 | {cowboy_loop, Req, #{hibernate => true}}. 17 | 18 | info(timeout, Req, State) -> 19 | {stop, cowboy_req:reply(200, #{}, <<"Good!">>, Req), State}. 20 | 21 | terminate(stop, _, _) -> 22 | ok. 23 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_timeout_hibernate_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that first 2 | %% sets a timeout, then hibernates, then ensures 3 | %% that the timeout initially set no longer triggers. 4 | %% If everything goes fine a 200 is returned. If the 5 | %% timeout triggers again a 299 is. 6 | 7 | -module(loop_handler_timeout_hibernate_h). 8 | 9 | -export([init/2]). 10 | -export([info/3]). 11 | -export([terminate/3]). 12 | 13 | init(Req, _) -> 14 | self() ! message1, 15 | {cowboy_loop, Req, undefined, 100}. 16 | 17 | info(message1, Req, State) -> 18 | erlang:send_after(200, self(), message2), 19 | {ok, Req, State, hibernate}; 20 | info(message2, Req, State) -> 21 | erlang:send_after(200, self(), message3), 22 | %% Don't set a timeout now. 23 | {ok, Req, State}; 24 | info(message3, Req, State) -> 25 | {stop, cowboy_req:reply(200, Req), State}; 26 | info(timeout, Req, State) -> 27 | {stop, cowboy_req:reply(<<"299 OK!">>, Req), State}. 28 | 29 | terminate(stop, _, _) -> 30 | ok. 31 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_timeout_info_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that changes 2 | %% the timeout value to 500ms after the first message 3 | %% then sends itself another message after 1000ms. 4 | %% It is expected to timeout, that is, reply a 299. 5 | 6 | -module(loop_handler_timeout_info_h). 7 | 8 | -export([init/2]). 9 | -export([info/3]). 10 | -export([terminate/3]). 11 | 12 | init(Req, _) -> 13 | self() ! message, 14 | {cowboy_loop, Req, undefined}. 15 | 16 | info(message, Req, State) -> 17 | erlang:send_after(500, self(), message), 18 | {ok, Req, State, 100}; 19 | info(timeout, Req, State) -> 20 | {stop, cowboy_req:reply(<<"299 OK!">>, Req), State}. 21 | 22 | terminate(stop, _, _) -> 23 | ok. 24 | -------------------------------------------------------------------------------- /test/handlers/loop_handler_timeout_init_h.erl: -------------------------------------------------------------------------------- 1 | %% This module implements a loop handler that reads 2 | %% the request query for a timeout value, then sends 3 | %% itself a message after 1000ms. It replies a 200 when 4 | %% the message does not timeout and a 299 otherwise. 5 | 6 | -module(loop_handler_timeout_init_h). 7 | 8 | -export([init/2]). 9 | -export([info/3]). 10 | -export([terminate/3]). 11 | 12 | init(Req, _) -> 13 | #{timeout := Timeout} = cowboy_req:match_qs([{timeout, int}], Req), 14 | erlang:send_after(500, self(), message), 15 | {cowboy_loop, Req, undefined, Timeout}. 16 | 17 | info(message, Req, State) -> 18 | {stop, cowboy_req:reply(200, Req), State}; 19 | info(timeout, Req, State) -> 20 | {stop, cowboy_req:reply(<<"299 OK!">>, Req), State}. 21 | 22 | terminate(stop, _, _) -> 23 | ok. 24 | -------------------------------------------------------------------------------- /test/handlers/provide_callback_missing_h.erl: -------------------------------------------------------------------------------- 1 | -module(provide_callback_missing_h). 2 | 3 | -export([init/2]). 4 | -export([content_types_provided/2]). 5 | 6 | init(Req, State) -> 7 | {cowboy_rest, Req, State}. 8 | 9 | content_types_provided(Req, State) -> 10 | ct_helper_error_h:ignore(cowboy_rest, set_resp_body, 2), 11 | {[{<<"text/plain">>, provide}], Req, State}. 12 | -------------------------------------------------------------------------------- /test/handlers/range_satisfiable_h.erl: -------------------------------------------------------------------------------- 1 | %% This module defines the range_satisfiable callback 2 | %% and return something different depending on query string. 3 | 4 | -module(range_satisfiable_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([ranges_provided/2]). 9 | -export([range_satisfiable/2]). 10 | -export([get_text_plain/2]). 11 | -export([get_text_plain_bytes/2]). 12 | 13 | init(Req, State) -> 14 | {cowboy_rest, Req, State}. 15 | 16 | content_types_provided(Req, State) -> 17 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 18 | 19 | ranges_provided(Req, State) -> 20 | {[{<<"bytes">>, get_text_plain_bytes}], Req, State}. 21 | 22 | %% Simulate the callback being missing, otherwise expect true/false. 23 | range_satisfiable(#{qs := <<"missing">>}, _) -> 24 | no_call; 25 | range_satisfiable(Req=#{qs := <<"false-int">>}, State) -> 26 | {{false, 123}, Req, State}; 27 | range_satisfiable(Req=#{qs := <<"false-bin">>}, State) -> 28 | {{false, <<"*/456">>}, Req, State}; 29 | range_satisfiable(Req=#{qs := Qs}, State) -> 30 | {Qs =:= <<"true">>, Req, State}. 31 | 32 | get_text_plain(Req, State) -> 33 | {<<"This is REST!">>, Req, State}. 34 | 35 | get_text_plain_bytes(Req, State) -> 36 | %% We send everything in one part, since we are not testing 37 | %% this callback specifically. 38 | Body = <<"This is ranged REST!">>, 39 | {[{{0, byte_size(Body) - 1, byte_size(Body)}, Body}], Req, State}. 40 | -------------------------------------------------------------------------------- /test/handlers/ranges_provided_auto_h.erl: -------------------------------------------------------------------------------- 1 | %% This module defines the ranges_provided callback 2 | %% which returns the auto option for bytes ranges 3 | %% and the normal ProvideCallback that returns 4 | %% something different depending on query string. 5 | 6 | -module(ranges_provided_auto_h). 7 | 8 | -export([init/2]). 9 | -export([content_types_provided/2]). 10 | -export([ranges_provided/2]). 11 | -export([get_text_plain/2]). 12 | 13 | init(Req, State) -> 14 | {cowboy_rest, Req, State}. 15 | 16 | content_types_provided(Req, State) -> 17 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 18 | 19 | ranges_provided(Req, State) -> 20 | {[{<<"bytes">>, auto}], Req, State}. 21 | 22 | get_text_plain(Req=#{qs := <<"data">>}, State) -> 23 | {<<"This is ranged REST!">>, Req, State}; 24 | get_text_plain(Req=#{qs := <<"sendfile">>}, State) -> 25 | Path = code:lib_dir(cowboy) ++ "/ebin/cowboy.app", 26 | Size = filelib:file_size(Path), 27 | {{sendfile, 0, Size, Path}, Req, State}. 28 | -------------------------------------------------------------------------------- /test/handlers/ranges_provided_h.erl: -------------------------------------------------------------------------------- 1 | %% This module defines the ranges_provided callback 2 | %% and return something different depending on query string. 3 | 4 | -module(ranges_provided_h). 5 | 6 | -export([init/2]). 7 | -export([content_types_provided/2]). 8 | -export([ranges_provided/2]). 9 | -export([get_text_plain/2]). 10 | 11 | init(Req, State) -> 12 | {cowboy_rest, Req, State}. 13 | 14 | content_types_provided(Req, State) -> 15 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 16 | 17 | ranges_provided(Req=#{qs := <<"list">>}, State) -> 18 | {[ 19 | {<<"bytes">>, get_text_plain_bytes}, 20 | {<<"pages">>, get_text_plain_pages}, 21 | {<<"chapters">>, get_text_plain_chapters} 22 | ], Req, State}; 23 | ranges_provided(Req=#{qs := <<"none">>}, State) -> 24 | {[], Req, State}; 25 | %% Simulate the callback being missing in other cases. 26 | ranges_provided(_, _) -> 27 | no_call. 28 | 29 | get_text_plain(Req, State) -> 30 | {<<"This is REST!">>, Req, State}. 31 | -------------------------------------------------------------------------------- /test/handlers/rate_limited_h.erl: -------------------------------------------------------------------------------- 1 | %% This module does rate limiting based on the query string value. 2 | 3 | -module(rate_limited_h). 4 | 5 | -export([init/2]). 6 | -export([rate_limited/2]). 7 | -export([content_types_provided/2]). 8 | -export([get_text_plain/2]). 9 | 10 | init(Req, State) -> 11 | {cowboy_rest, Req, State}. 12 | 13 | rate_limited(Req=#{qs := <<"false">>}, State) -> 14 | {false, Req, State}; 15 | rate_limited(Req=#{qs := <<"true-date">>}, State) -> 16 | {{true, {{2222, 2, 22}, {11, 11, 11}}}, Req, State}; 17 | rate_limited(Req=#{qs := <<"true">>}, State) -> 18 | {{true, 3600}, Req, State}. 19 | 20 | content_types_provided(Req, State) -> 21 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 22 | 23 | get_text_plain(Req, State) -> 24 | {<<"This is REST!">>, Req, State}. 25 | -------------------------------------------------------------------------------- /test/handlers/read_body_h.erl: -------------------------------------------------------------------------------- 1 | %% This module reads the request body fully and send a 204 response. 2 | 3 | -module(read_body_h). 4 | 5 | -export([init/2]). 6 | 7 | init(Req0, Opts) -> 8 | {ok, Req} = read_body(Req0), 9 | {ok, cowboy_req:reply(200, #{}, Req), Opts}. 10 | 11 | read_body(Req0) -> 12 | case cowboy_req:read_body(Req0) of 13 | {ok, _, Req} -> {ok, Req}; 14 | {more, _, Req} -> read_body(Req) 15 | end. 16 | -------------------------------------------------------------------------------- /test/handlers/rest_hello_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a hello world response via a REST handler. 2 | 3 | -module(rest_hello_h). 4 | 5 | -export([init/2]). 6 | -export([content_types_provided/2]). 7 | -export([get_text_plain/2]). 8 | 9 | init(Req, Opts) -> 10 | {cowboy_rest, Req, Opts}. 11 | 12 | content_types_provided(Req, State) -> 13 | {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. 14 | 15 | get_text_plain(Req, State) -> 16 | {<<"This is REST!">>, Req, State}. 17 | -------------------------------------------------------------------------------- /test/handlers/send_message_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a message to the pid passed in a header. 2 | 3 | -module(send_message_h). 4 | -export([init/2]). 5 | 6 | init(Req, State) -> 7 | Pid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, Req))), 8 | Pid ! {Pid, self(), init, Req, State}, 9 | {ok, cowboy_req:reply(200, Req), State}. 10 | -------------------------------------------------------------------------------- /test/handlers/set_options_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sets options dynamically and performs 2 | %% some related relevant operation for testing the change. 3 | 4 | -module(set_options_h). 5 | 6 | -export([init/2]). 7 | 8 | init(Req, State) -> 9 | set_options(cowboy_req:binding(key, Req), Req, State). 10 | 11 | set_options(<<"chunked_false">>, Req0, State) -> 12 | cowboy_req:cast({set_options, #{chunked => false}}, Req0), 13 | Req = cowboy_req:stream_reply(200, Req0), 14 | cowboy_req:stream_body(<<0:8000000>>, fin, Req), 15 | {ok, Req, State}; 16 | set_options(<<"chunked_false_ignored">>, Req0, State) -> 17 | cowboy_req:cast({set_options, #{chunked => false}}, Req0), 18 | Req = cowboy_req:reply(200, #{}, <<"Hello world!">>, Req0), 19 | {ok, Req, State}; 20 | set_options(<<"idle_timeout_short">>, Req0, State) -> 21 | cowboy_req:cast({set_options, #{idle_timeout => 500}}, Req0), 22 | {_, Body, Req} = cowboy_req:read_body(Req0), 23 | {ok, cowboy_req:reply(200, #{}, Body, Req), State}; 24 | set_options(<<"idle_timeout_long">>, Req0, State) -> 25 | cowboy_req:cast({set_options, #{idle_timeout => 60000}}, Req0), 26 | {_, Body, Req} = cowboy_req:read_body(Req0), 27 | {ok, cowboy_req:reply(200, #{}, Body, Req), State}; 28 | set_options(<<"metrics_user_data">>, Req, State) -> 29 | cowboy_req:cast({set_options, #{metrics_user_data => #{handler => ?MODULE}}}, Req), 30 | {ok, cowboy_req:reply(200, #{}, <<"Hello world!">>, Req), State}. 31 | -------------------------------------------------------------------------------- /test/handlers/stream_hello_h.erl: -------------------------------------------------------------------------------- 1 | %% This module is the fastest way of producing a Hello world! 2 | 3 | -module(stream_hello_h). 4 | 5 | -export([init/3]). 6 | -export([terminate/3]). 7 | 8 | init(_, _, State) -> 9 | {[ 10 | {response, 200, #{<<"content-length">> => <<"12">>}, <<"Hello world!">>}, 11 | stop 12 | ], State}. 13 | 14 | terminate(_, _, _) -> 15 | ok. 16 | -------------------------------------------------------------------------------- /test/handlers/streamed_result_h.erl: -------------------------------------------------------------------------------- 1 | -module(streamed_result_h). 2 | 3 | -export([init/2]). 4 | 5 | init(Req, Opts) -> 6 | N = list_to_integer(binary_to_list(cowboy_req:binding(n, Req))), 7 | Interval = list_to_integer(binary_to_list(cowboy_req:binding(interval, Req))), 8 | chunked(N, Interval, Req, Opts). 9 | 10 | chunked(N, Interval, Req0, Opts) -> 11 | Req = cowboy_req:stream_reply(200, Req0), 12 | {ok, loop(N, Interval, Req), Opts}. 13 | 14 | loop(0, _Interval, Req) -> 15 | ok = cowboy_req:stream_body("Finished!\n", fin, Req), 16 | Req; 17 | loop(N, Interval, Req) -> 18 | ok = cowboy_req:stream_body(iolist_to_binary([integer_to_list(N), <<"\n">>]), nofin, Req), 19 | timer:sleep(Interval), 20 | loop(N-1, Interval, Req). 21 | -------------------------------------------------------------------------------- /test/handlers/switch_protocol_flush_h.erl: -------------------------------------------------------------------------------- 1 | %% This module is used to test the flushing of messages when 2 | %% switch_protocol is executed by cowboy_http. 3 | 4 | -module(switch_protocol_flush_h). 5 | 6 | -export([init/3]). 7 | -export([info/3]). 8 | -export([terminate/3]). 9 | -export([takeover/7]). 10 | -export([validate/1]). 11 | 12 | init(StreamID, Req, _) -> 13 | Pid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, Req))), 14 | %% Send ourselves a few messages that may or may not be flushed. 15 | self() ! good, 16 | self() ! {'EXIT', Pid, normal}, 17 | self() ! {system, a, b}, 18 | self() ! {{self(), StreamID}, hello}, 19 | self() ! {'$gen_call', a, b}, 20 | self() ! {timeout, make_ref(), ?MODULE}, 21 | self() ! {ranch_tcp, socket, <<"123">>}, 22 | {[{switch_protocol, #{}, ?MODULE, Pid}], undefined}. 23 | 24 | info(_, _, State) -> 25 | {[], State}. 26 | 27 | terminate(_, _, _) -> 28 | ok. 29 | 30 | %% @todo It would be good if we could allow this function to return normally. 31 | -spec takeover(_, _, _, _, _, _, _) -> no_return(). 32 | takeover(_, _, _, _, _, _, Pid) -> 33 | Msgs = receive_all([]), 34 | Pid ! {Pid, Msgs}, 35 | exit(normal). 36 | 37 | receive_all(Acc) -> 38 | receive 39 | Msg -> 40 | receive_all([Msg|Acc]) 41 | after 0 -> 42 | Acc 43 | end. 44 | 45 | validate(Msgs) -> 46 | [ 47 | {ranch_tcp, socket, <<"123">>}, 48 | {'$gen_call', a, b}, 49 | {system, a, b}, 50 | good 51 | ] = Msgs, 52 | ok. 53 | -------------------------------------------------------------------------------- /test/handlers/ws_active_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module starts with active mode disabled 2 | %% and enables it again once a timeout is triggered. 3 | 4 | -module(ws_active_commands_h). 5 | -behavior(cowboy_websocket). 6 | 7 | -export([init/2]). 8 | -export([websocket_init/1]). 9 | -export([websocket_handle/2]). 10 | -export([websocket_info/2]). 11 | 12 | init(Req, RunOrHibernate) -> 13 | {cowboy_websocket, Req, RunOrHibernate}. 14 | 15 | websocket_init(State=run) -> 16 | erlang:send_after(1500, self(), active_true), 17 | {[{active, false}], State}; 18 | websocket_init(State=hibernate) -> 19 | erlang:send_after(1500, self(), active_true), 20 | {[{active, false}], State, hibernate}. 21 | 22 | websocket_handle(Frame, State=run) -> 23 | {[Frame], State}; 24 | websocket_handle(Frame, State=hibernate) -> 25 | {[Frame], State, hibernate}. 26 | 27 | websocket_info(active_true, State=run) -> 28 | {[{active, true}], State}; 29 | websocket_info(active_true, State=hibernate) -> 30 | {[{active, true}], State, hibernate}. 31 | -------------------------------------------------------------------------------- /test/handlers/ws_deflate_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module enables/disables compression 2 | %% every time it echoes a frame. 3 | 4 | -module(ws_deflate_commands_h). 5 | -behavior(cowboy_websocket). 6 | 7 | -export([init/2]). 8 | -export([websocket_handle/2]). 9 | -export([websocket_info/2]). 10 | 11 | init(Req, RunOrHibernate) -> 12 | {cowboy_websocket, Req, 13 | #{deflate => true, hibernate => RunOrHibernate}, 14 | #{compress => true}}. 15 | 16 | websocket_handle(Frame, State=#{deflate := Deflate0, hibernate := run}) -> 17 | Deflate = not Deflate0, 18 | {[Frame, {deflate, Deflate}], State#{deflate => Deflate}}; 19 | websocket_handle(Frame, State=#{deflate := Deflate0, hibernate := hibernate}) -> 20 | Deflate = not Deflate0, 21 | {[Frame, {deflate, Deflate}], State#{deflate => Deflate}, hibernate}. 22 | 23 | websocket_info(_Info, State) -> 24 | {[], State}. 25 | -------------------------------------------------------------------------------- /test/handlers/ws_deflate_opts_h.erl: -------------------------------------------------------------------------------- 1 | %% This module enables compression and returns deflate 2 | %% options depending on the query string. 3 | 4 | -module(ws_deflate_opts_h). 5 | -behavior(cowboy_websocket). 6 | 7 | -export([init/2]). 8 | -export([websocket_handle/2]). 9 | -export([websocket_info/2]). 10 | 11 | init(Req=#{qs := Qs}, State) -> 12 | {Name, Value} = case Qs of 13 | <<"server_context_takeover">> -> {server_context_takeover, takeover}; 14 | <<"server_no_context_takeover">> -> {server_context_takeover, no_takeover}; 15 | <<"client_context_takeover">> -> {client_context_takeover, takeover}; 16 | <<"client_no_context_takeover">> -> {client_context_takeover, no_takeover}; 17 | <<"server_max_window_bits">> -> {server_max_window_bits, 9}; 18 | <<"client_max_window_bits">> -> {client_max_window_bits, 9}; 19 | <<"level">> -> {level, best_speed}; 20 | <<"mem_level">> -> {mem_level, 1}; 21 | <<"strategy">> -> {strategy, rle} 22 | end, 23 | {cowboy_websocket, Req, State, #{ 24 | compress => true, 25 | deflate_opts => #{Name => Value} 26 | }}. 27 | 28 | websocket_handle({text, Data}, State) -> 29 | {[{text, Data}], State}; 30 | websocket_handle({binary, Data}, State) -> 31 | {[{binary, Data}], State}; 32 | websocket_handle(_, State) -> 33 | {[], State}. 34 | 35 | websocket_info(_, State) -> 36 | {[], State}. 37 | -------------------------------------------------------------------------------- /test/handlers/ws_dont_validate_utf8_h.erl: -------------------------------------------------------------------------------- 1 | %% This module disables UTF-8 validation. 2 | 3 | -module(ws_dont_validate_utf8_h). 4 | -behavior(cowboy_websocket). 5 | 6 | -export([init/2]). 7 | -export([websocket_handle/2]). 8 | -export([websocket_info/2]). 9 | 10 | init(Req, State) -> 11 | {cowboy_websocket, Req, State, #{ 12 | validate_utf8 => false 13 | }}. 14 | 15 | websocket_handle({text, Data}, State) -> 16 | {[{text, Data}], State}; 17 | websocket_handle({binary, Data}, State) -> 18 | {[{binary, Data}], State}; 19 | websocket_handle(_, State) -> 20 | {[], State}. 21 | 22 | websocket_info(_, State) -> 23 | {[], State}. 24 | -------------------------------------------------------------------------------- /test/handlers/ws_handle_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module takes commands from the x-commands header 2 | %% and returns them in the websocket_handle/2 callback. 3 | 4 | -module(ws_handle_commands_h). 5 | -behavior(cowboy_websocket). 6 | 7 | -export([init/2]). 8 | -export([websocket_init/1]). 9 | -export([websocket_handle/2]). 10 | -export([websocket_info/2]). 11 | 12 | init(Req=#{pid := Pid}, RunOrHibernate) -> 13 | Commands0 = cowboy_req:header(<<"x-commands">>, Req), 14 | Commands = binary_to_term(base64:decode(Commands0)), 15 | case Commands of 16 | bad -> ct_helper_error_h:ignore(Pid, cowboy_websocket, handler_call, 6); 17 | _ -> ok 18 | end, 19 | {cowboy_websocket, Req, {Commands, RunOrHibernate}}. 20 | 21 | websocket_init(State) -> 22 | {[], State}. 23 | 24 | websocket_handle(_, State={Commands, run}) -> 25 | {Commands, State}; 26 | websocket_handle(_, State={Commands, hibernate}) -> 27 | {Commands, State, hibernate}. 28 | 29 | websocket_info(_, State) -> 30 | {[], State}. 31 | 32 | -------------------------------------------------------------------------------- /test/handlers/ws_ignore.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_ignore). 4 | 5 | -export([init/2]). 6 | -export([websocket_handle/2]). 7 | -export([websocket_info/2]). 8 | 9 | init(Req, _) -> 10 | {cowboy_websocket, Req, undefined, #{ 11 | compress => true 12 | }}. 13 | 14 | websocket_handle({text, <<"CHECK">>}, State) -> 15 | {[{text, <<"CHECK">>}], State}; 16 | websocket_handle(_Frame, State) -> 17 | {[], State}. 18 | 19 | websocket_info(_Info, State) -> 20 | {[], State}. 21 | -------------------------------------------------------------------------------- /test/handlers/ws_info_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module takes commands from the x-commands header 2 | %% and returns them in the websocket_info/2 callback. 3 | %% This callback is triggered via a message. 4 | 5 | -module(ws_info_commands_h). 6 | -behavior(cowboy_websocket). 7 | 8 | -export([init/2]). 9 | -export([websocket_init/1]). 10 | -export([websocket_handle/2]). 11 | -export([websocket_info/2]). 12 | 13 | init(Req=#{pid := Pid}, RunOrHibernate) -> 14 | Commands0 = cowboy_req:header(<<"x-commands">>, Req), 15 | Commands = binary_to_term(base64:decode(Commands0)), 16 | case Commands of 17 | bad -> ct_helper_error_h:ignore(Pid, cowboy_websocket, handler_call, 6); 18 | _ -> ok 19 | end, 20 | {cowboy_websocket, Req, {Commands, RunOrHibernate}}. 21 | 22 | websocket_init(State) -> 23 | self() ! shoot, 24 | {[], State}. 25 | 26 | websocket_handle(_, State) -> 27 | {[], State}. 28 | 29 | websocket_info(_, State={Commands, run}) -> 30 | {Commands, State}; 31 | websocket_info(_, State={Commands, hibernate}) -> 32 | {Commands, State, hibernate}. 33 | -------------------------------------------------------------------------------- /test/handlers/ws_init_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module takes commands from the x-commands header 2 | %% and returns them in the websocket_init/1 callback. 3 | 4 | -module(ws_init_commands_h). 5 | -behavior(cowboy_websocket). 6 | 7 | -export([init/2]). 8 | -export([websocket_init/1]). 9 | -export([websocket_handle/2]). 10 | -export([websocket_info/2]). 11 | 12 | init(Req=#{pid := Pid}, RunOrHibernate) -> 13 | Commands0 = cowboy_req:header(<<"x-commands">>, Req), 14 | Commands = binary_to_term(base64:decode(Commands0)), 15 | case Commands of 16 | bad -> ct_helper_error_h:ignore(Pid, cowboy_websocket, handler_call, 6); 17 | _ -> ok 18 | end, 19 | {cowboy_websocket, Req, {Commands, RunOrHibernate}}. 20 | 21 | websocket_init(State={Commands, run}) -> 22 | {Commands, State}; 23 | websocket_init(State={Commands, hibernate}) -> 24 | {Commands, State, hibernate}. 25 | 26 | websocket_handle(_, State) -> 27 | {[], State}. 28 | 29 | websocket_info(_, State) -> 30 | {[], State}. 31 | -------------------------------------------------------------------------------- /test/handlers/ws_init_h.erl: -------------------------------------------------------------------------------- 1 | %% This module returns a different value in websocket_init/1 depending on the query string. 2 | 3 | -module(ws_init_h). 4 | -behavior(cowboy_websocket). 5 | 6 | -export([init/2]). 7 | -export([websocket_init/1]). 8 | -export([websocket_handle/2]). 9 | -export([websocket_info/2]). 10 | 11 | init(Req, _) -> 12 | State = binary_to_atom(cowboy_req:qs(Req), latin1), 13 | {cowboy_websocket, Req, State}. 14 | 15 | %% Sleep to make sure the HTTP response was sent. 16 | websocket_init(State) -> 17 | timer:sleep(100), 18 | do_websocket_init(State). 19 | 20 | do_websocket_init(State=ok) -> 21 | {[], State}; 22 | do_websocket_init(State=ok_hibernate) -> 23 | {[], State, hibernate}; 24 | do_websocket_init(State=reply) -> 25 | {[{text, "Hello"}], State}; 26 | do_websocket_init(State=reply_hibernate) -> 27 | {[{text, "Hello"}], State, hibernate}; 28 | do_websocket_init(State=reply_close) -> 29 | {[close], State}; 30 | do_websocket_init(State=reply_close_hibernate) -> 31 | {[close], State, hibernate}; 32 | do_websocket_init(State=reply_many) -> 33 | {[{text, "Hello"}, {binary, "World"}], State}; 34 | do_websocket_init(State=reply_many_hibernate) -> 35 | {[{text, "Hello"}, {binary, "World"}], State, hibernate}; 36 | do_websocket_init(State=reply_many_close) -> 37 | {[{text, "Hello"}, close], State}; 38 | do_websocket_init(State=reply_many_close_hibernate) -> 39 | {[{text, "Hello"}, close], State, hibernate}; 40 | do_websocket_init(State=reply_trap_exit) -> 41 | Text = "trap_exit: " ++ atom_to_list(element(2, process_info(self(), trap_exit))), 42 | {[{text, Text}, close], State, hibernate}. 43 | 44 | websocket_handle(_, State) -> 45 | {[], State}. 46 | 47 | websocket_info(_, State) -> 48 | {[], State}. 49 | -------------------------------------------------------------------------------- /test/handlers/ws_ping_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends an empty ping to the client and 2 | %% waits for a pong before sending a text frame. It 3 | %% is used to confirm server-initiated pings work. 4 | 5 | -module(ws_ping_h). 6 | -behavior(cowboy_websocket). 7 | 8 | -export([init/2]). 9 | -export([websocket_init/1]). 10 | -export([websocket_handle/2]). 11 | -export([websocket_info/2]). 12 | 13 | init(Req, _) -> 14 | {cowboy_websocket, Req, undefined}. 15 | 16 | websocket_init(State) -> 17 | {[{ping, <<>>}], State}. 18 | 19 | websocket_handle(pong, State) -> 20 | {[{text, <<"OK!!">>}], State}. 21 | 22 | websocket_info(_, State) -> 23 | {[], State}. 24 | -------------------------------------------------------------------------------- /test/handlers/ws_set_options_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sets options based on the frame received. 2 | 3 | -module(ws_set_options_commands_h). 4 | -behavior(cowboy_websocket). 5 | 6 | -export([init/2]). 7 | -export([websocket_handle/2]). 8 | -export([websocket_info/2]). 9 | 10 | init(Req, RunOrHibernate) -> 11 | {cowboy_websocket, Req, RunOrHibernate, 12 | #{idle_timeout => infinity}}. 13 | 14 | %% Set the idle_timeout option dynamically. 15 | websocket_handle({text, <<"idle_timeout_short">>}, State=run) -> 16 | {[{set_options, #{idle_timeout => 500}}], State}; 17 | websocket_handle({text, <<"idle_timeout_short">>}, State=hibernate) -> 18 | {[{set_options, #{idle_timeout => 500}}], State, hibernate}; 19 | %% Set the max_frame_size option dynamically. 20 | websocket_handle({text, <<"max_frame_size_small">>}, State=run) -> 21 | {[{set_options, #{max_frame_size => 1000}}], State}; 22 | websocket_handle({text, <<"max_frame_size_small">>}, State=hibernate) -> 23 | {[{set_options, #{max_frame_size => 1000}}], State, hibernate}; 24 | %% We just echo binary frames. 25 | websocket_handle(Frame={binary, _}, State=run) -> 26 | {[Frame], State}; 27 | websocket_handle(Frame={binary, _}, State=hibernate) -> 28 | {[Frame], State, hibernate}. 29 | 30 | websocket_info(_Info, State) -> 31 | {[], State}. 32 | -------------------------------------------------------------------------------- /test/handlers/ws_shutdown_reason_commands_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends the process pid to the test pid 2 | %% found in the x-test-pid header, then changes the 3 | %% shutdown reason and closes the connection normally. 4 | 5 | -module(ws_shutdown_reason_commands_h). 6 | -behavior(cowboy_websocket). 7 | 8 | -export([init/2]). 9 | -export([websocket_init/1]). 10 | -export([websocket_handle/2]). 11 | -export([websocket_info/2]). 12 | 13 | init(Req, RunOrHibernate) -> 14 | TestPid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, Req))), 15 | {cowboy_websocket, Req, {TestPid, RunOrHibernate}}. 16 | 17 | websocket_init(State={TestPid, RunOrHibernate}) -> 18 | TestPid ! {ws_pid, self()}, 19 | ShutdownReason = receive 20 | {TestPid, SR} -> 21 | SR 22 | after 1000 -> 23 | error(timeout) 24 | end, 25 | Commands = [ 26 | {shutdown_reason, ShutdownReason}, 27 | close 28 | ], 29 | case RunOrHibernate of 30 | run -> {Commands, State}; 31 | hibernate -> {Commands, State, hibernate} 32 | end. 33 | 34 | websocket_handle(_, State) -> 35 | {[], State}. 36 | 37 | websocket_info(_, State) -> 38 | {[], State}. 39 | -------------------------------------------------------------------------------- /test/handlers/ws_terminate_h.erl: -------------------------------------------------------------------------------- 1 | %% This module sends a message with terminate arguments to the test case process. 2 | 3 | -module(ws_terminate_h). 4 | -behavior(cowboy_websocket). 5 | 6 | -export([init/2]). 7 | -export([websocket_init/1]). 8 | -export([websocket_handle/2]). 9 | -export([websocket_info/2]). 10 | -export([terminate/3]). 11 | 12 | -record(state, { 13 | pid 14 | }). 15 | 16 | init(Req, _) -> 17 | Pid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, Req))), 18 | Opts = case cowboy_req:qs(Req) of 19 | <<"req_filter">> -> #{req_filter => fun(_) -> filtered end}; 20 | _ -> #{} 21 | end, 22 | {cowboy_websocket, Req, #state{pid=Pid}, Opts}. 23 | 24 | websocket_init(State) -> 25 | {ok, State}. 26 | 27 | websocket_handle(_, State) -> 28 | {ok, State}. 29 | 30 | websocket_info(_, State) -> 31 | {ok, State}. 32 | 33 | terminate(Reason, Req, #state{pid=Pid}) -> 34 | Pid ! {terminate, Reason, Req}, 35 | ok. 36 | -------------------------------------------------------------------------------- /test/rfc7538_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(rfc7538_SUITE). 16 | -compile(export_all). 17 | -compile(nowarn_export_all). 18 | 19 | -import(ct_helper, [config/2]). 20 | -import(ct_helper, [doc/1]). 21 | -import(cowboy_test, [gun_open/1]). 22 | 23 | all() -> 24 | cowboy_test:common_all(). 25 | 26 | groups() -> 27 | cowboy_test:common_groups(ct_helper:all(?MODULE)). 28 | 29 | init_per_group(Name, Config) -> 30 | cowboy_test:init_common_groups(Name, Config, ?MODULE). 31 | 32 | end_per_group(Name, _) -> 33 | cowboy_test:stop_group(Name). 34 | 35 | init_dispatch(_) -> 36 | cowboy_router:compile([{"[...]", [ 37 | {"/resp/:key[/:arg]", resp_h, []} 38 | ]}]). 39 | 40 | status_code_308(Config) -> 41 | doc("The 308 Permanent Redirect status code can be sent. (RFC7538 3)"), 42 | ConnPid = gun_open(Config), 43 | Ref = gun:get(ConnPid, "/resp/reply2/308", [ 44 | {<<"accept-encoding">>, <<"gzip">>} 45 | ]), 46 | {response, _, 308, _} = gun:await(ConnPid, Ref), 47 | ok. 48 | 49 | %% @todo 50 | % The server SHOULD generate a Location header field ([RFC7231], 51 | % Section 7.1.2) in the response containing a preferred URI reference 52 | % for the new permanent URI. 53 | -------------------------------------------------------------------------------- /test/rfc8297_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(rfc8297_SUITE). 16 | -compile(export_all). 17 | -compile(nowarn_export_all). 18 | 19 | -import(ct_helper, [config/2]). 20 | -import(ct_helper, [doc/1]). 21 | -import(cowboy_test, [gun_open/1]). 22 | 23 | all() -> 24 | cowboy_test:common_all(). 25 | 26 | groups() -> 27 | cowboy_test:common_groups(ct_helper:all(?MODULE)). 28 | 29 | init_per_group(Name, Config) -> 30 | cowboy_test:init_common_groups(Name, Config, ?MODULE). 31 | 32 | end_per_group(Name, _) -> 33 | cowboy_test:stop_group(Name). 34 | 35 | init_dispatch(_) -> 36 | cowboy_router:compile([{"[...]", [ 37 | {"/resp/:key[/:arg]", resp_h, []} 38 | ]}]). 39 | 40 | status_code_103(Config) -> 41 | doc("The 103 Early Hints status code can be sent. (RFC8297 2)"), 42 | ConnPid = gun_open(Config), 43 | Ref = gun:get(ConnPid, "/resp/inform2/103", [ 44 | {<<"accept-encoding">>, <<"gzip">>} 45 | ]), 46 | {inform, 103, []} = gun:await(ConnPid, Ref), 47 | ok. 48 | -------------------------------------------------------------------------------- /test/rfc9114_SUITE_data/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVJakPYfQA1Hr6Gnq 3 | GYmpMfXpxUi2QwDBrZfw8dBcVqKhRANCAAQDHeeAvjwD7p+Mg1F+G9FBNy+7Wcms 4 | HEw4sGMzhUL4wjwsqKHpoiuQg3qUXXK0gamx0l77vFjrUc6X1al4+ZM5 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /test/rfc9114_SUITE_data/client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBtTCCAVugAwIBAgIUeAPi9oyMIE/KRpsRdukfx2eMuuswCgYIKoZIzj0EAwIw 3 | IDELMAkGA1UEBhMCU0UxETAPBgNVBAoMCE5PQk9EWUFCMB4XDTIzMDcwNTEwMjIy 4 | MloXDTI0MTExNjEwMjIyMlowMTELMAkGA1UEBhMCU0UxETAPBgNVBAoMCE5PQk9E 5 | WUFCMQ8wDQYDVQQDDAZjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQD 6 | HeeAvjwD7p+Mg1F+G9FBNy+7WcmsHEw4sGMzhUL4wjwsqKHpoiuQg3qUXXK0gamx 7 | 0l77vFjrUc6X1al4+ZM5o2IwYDALBgNVHQ8EBAMCA4gwEQYDVR0RBAowCIIGY2xp 8 | ZW50MB0GA1UdDgQWBBTnhPpO+rSIFAxvkwVjlkKOO2jOeDAfBgNVHSMEGDAWgBSD 9 | Hw8A4XXG3jB1Atrqux7AUsf+KjAKBggqhkjOPQQDAgNIADBFAiEA2qf29EBp2hcL 10 | sEO7MM0ZLm4gnaMdcxtyneF3+c7Lg3cCIBFTVP8xHlhCJyb8ESV7S052VU0bKQFN 11 | ioyoYtcycxuZ 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /test/rfc9114_SUITE_data/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvykUYMOS2gW8XTTh 3 | HgmeJM36NT8GGTNXzzt4sIs0o9ahRANCAATnQOMkKbLFQCZY/cxf8otEJG2tVuG6 4 | QvLqUdERV2+gzE+4ROGDqbb2Jk1szyz4CfBMB4ZfLA/PdSiO+KrOeOcj 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /test/rfc9114_SUITE_data/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBtTCCAVugAwIBAgIUeAPi9oyMIE/KRpsRdukfx2eMuuowCgYIKoZIzj0EAwIw 3 | IDELMAkGA1UEBhMCU0UxETAPBgNVBAoMCE5PQk9EWUFCMB4XDTIzMDcwNTEwMjIy 4 | MloXDTI0MTExNjEwMjIyMlowMTELMAkGA1UEBhMCU0UxETAPBgNVBAoMCE5PQk9E 5 | WUFCMQ8wDQYDVQQDDAZzZXJ2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATn 6 | QOMkKbLFQCZY/cxf8otEJG2tVuG6QvLqUdERV2+gzE+4ROGDqbb2Jk1szyz4CfBM 7 | B4ZfLA/PdSiO+KrOeOcjo2IwYDALBgNVHQ8EBAMCA4gwEQYDVR0RBAowCIIGc2Vy 8 | dmVyMB0GA1UdDgQWBBS+Np5J8BtmWU534pm9hqhrG/EQ7zAfBgNVHSMEGDAWgBSD 9 | Hw8A4XXG3jB1Atrqux7AUsf+KjAKBggqhkjOPQQDAgNIADBFAiEApRfjIEJfO1VH 10 | ETgNG3/MzDayYScPocVn4v8U15ygEw8CIFUY3xMZzJ5AmiRe9PhIUgueOKQNMtds 11 | wdF9+097+Ey0 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /test/static_handler_SUITE_data/static_files_app.ez: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninenines/cowboy/24d32de931a0c985ff7939077463fc8be939f0e9/test/static_handler_SUITE_data/static_files_app.ez -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_echo.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_echo). 4 | 5 | -export([init/2]). 6 | -export([websocket_handle/2]). 7 | -export([websocket_info/2]). 8 | 9 | init(Req, _) -> 10 | {cowboy_websocket, Req, undefined, #{ 11 | compress => true 12 | }}. 13 | 14 | websocket_handle({text, Data}, State) -> 15 | {[{text, Data}], State}; 16 | websocket_handle({binary, Data}, State) -> 17 | {[{binary, Data}], State}; 18 | websocket_handle(_Frame, State) -> 19 | {[], State}. 20 | 21 | websocket_info(_Info, State) -> 22 | {[], State}. 23 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_echo_timer.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_echo_timer). 4 | 5 | -export([init/2]). 6 | -export([websocket_init/1]). 7 | -export([websocket_handle/2]). 8 | -export([websocket_info/2]). 9 | 10 | init(Req, _) -> 11 | {cowboy_websocket, Req, undefined}. 12 | 13 | websocket_init(State) -> 14 | erlang:start_timer(1000, self(), <<"websocket_init">>), 15 | {[], State}. 16 | 17 | websocket_handle({text, Data}, State) -> 18 | {[{text, Data}], State}; 19 | websocket_handle({binary, Data}, State) -> 20 | {[{binary, Data}], State}; 21 | websocket_handle(_Frame, State) -> 22 | {[], State}. 23 | 24 | websocket_info({timeout, _Ref, Msg}, State) -> 25 | erlang:start_timer(1000, self(), <<"websocket_handle">>), 26 | {[{text, Msg}], State}; 27 | websocket_info(_Info, State) -> 28 | {[], State}. 29 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_init_shutdown.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_init_shutdown). 4 | 5 | -export([init/2]). 6 | 7 | init(Req, Opts) -> 8 | {ok, cowboy_req:reply(403, Req), Opts}. 9 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_max_frame_size.erl: -------------------------------------------------------------------------------- 1 | -module(ws_max_frame_size). 2 | 3 | -export([init/2]). 4 | -export([websocket_handle/2]). 5 | -export([websocket_info/2]). 6 | 7 | init(Req, State) -> 8 | {cowboy_websocket, Req, State, #{max_frame_size => 8, compress => true}}. 9 | 10 | websocket_handle({text, Data}, State) -> 11 | {[{text, Data}], State}; 12 | websocket_handle({binary, Data}, State) -> 13 | {[{binary, Data}], State}; 14 | websocket_handle(_Frame, State) -> 15 | {[], State}. 16 | 17 | websocket_info(_Info, State) -> 18 | {[], State}. 19 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_send_many.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_send_many). 4 | 5 | -export([init/2]). 6 | -export([websocket_init/1]). 7 | -export([websocket_handle/2]). 8 | -export([websocket_info/2]). 9 | 10 | init(Req, Opts) -> 11 | {cowboy_websocket, Req, Opts}. 12 | 13 | websocket_init(State) -> 14 | erlang:send_after(10, self(), send_many), 15 | {[], State}. 16 | 17 | websocket_handle(_Frame, State) -> 18 | {[], State}. 19 | 20 | websocket_info(send_many, State = [{sequence, Sequence}]) -> 21 | {Sequence, State}. 22 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_subprotocol.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_subprotocol). 4 | 5 | -export([init/2]). 6 | -export([websocket_handle/2]). 7 | -export([websocket_info/2]). 8 | 9 | init(Req, Opts) -> 10 | [Protocol | _] = cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req), 11 | Req2 = cowboy_req:set_resp_header(<<"sec-websocket-protocol">>, Protocol, Req), 12 | {cowboy_websocket, Req2, Opts, #{ 13 | idle_timeout => 1000 14 | }}. 15 | 16 | websocket_handle(_Frame, State) -> 17 | {ok, State}. 18 | 19 | websocket_info(_Info, State) -> 20 | {ok, State}. 21 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_timeout_cancel.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_timeout_cancel). 4 | 5 | -export([init/2]). 6 | -export([websocket_handle/2]). 7 | -export([websocket_info/2]). 8 | 9 | init(Req, _) -> 10 | erlang:start_timer(500, self(), should_not_cancel_timer), 11 | {cowboy_websocket, Req, undefined, #{ 12 | idle_timeout => 1000 13 | }}. 14 | 15 | websocket_handle({text, Data}, State) -> 16 | {[{text, Data}], State}; 17 | websocket_handle({binary, Data}, State) -> 18 | {[{binary, Data}], State}. 19 | 20 | websocket_info(_Info, State) -> 21 | erlang:start_timer(500, self(), should_not_cancel_timer), 22 | {[], State}. 23 | -------------------------------------------------------------------------------- /test/ws_SUITE_data/ws_timeout_hibernate.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(ws_timeout_hibernate). 4 | 5 | -export([init/2]). 6 | -export([websocket_init/1]). 7 | -export([websocket_handle/2]). 8 | -export([websocket_info/2]). 9 | 10 | init(Req, _) -> 11 | {cowboy_websocket, Req, undefined, #{ 12 | idle_timeout => 1000 13 | }}. 14 | 15 | websocket_init(State) -> 16 | {ok, State, hibernate}. 17 | 18 | websocket_handle(_Frame, State) -> 19 | {ok, State, hibernate}. 20 | 21 | websocket_info(_Info, State) -> 22 | {ok, State, hibernate}. 23 | -------------------------------------------------------------------------------- /test/ws_autobahn_SUITE_data/client.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": {"failByDrop": false}, 3 | "enable-ssl": false, 4 | 5 | "servers": [{ 6 | "agent": "Cowboy", 7 | "url": "ws://host.docker.internal:33080/ws_echo", 8 | "options": {"version": 18} 9 | }], 10 | 11 | "cases": ["*"], 12 | "exclude-cases": [], 13 | "exclude-agent-cases": {} 14 | } 15 | -------------------------------------------------------------------------------- /test/ws_perf_SUITE_data/ascii.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. 2 | 3 | Ut velit mauris, egestas sed, gravida nec, ornare ut, mi. Aenean ut orci vel massa suscipit pulvinar. Nulla sollicitudin. Fusce varius, ligula non tempus aliquam, nunc turpis ullamcorper nibh, in tempus sapien eros vitae ligula. Pellentesque rhoncus nunc et augue. Integer id felis. Curabitur aliquet pellentesque diam. Integer quis metus vitae elit lobortis egestas. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi vel erat non mauris convallis vehicula. Nulla et sapien. Integer tortor tellus, aliquam faucibus, convallis id, congue eu, quam. Mauris ullamcorper felis vitae erat. Proin feugiat, augue non elementum posuere, metus purus iaculis lectus, et tristique ligula justo vitae magna. 4 | 5 | Aliquam convallis sollicitudin purus. Praesent aliquam, enim at fermentum mollis, ligula massa adipiscing nisl, ac euismod nibh nisl eu lectus. Fusce vulputate sem at sapien. Vivamus leo. Aliquam euismod libero eu enim. Nulla nec felis sed leo placerat imperdiet. Aenean suscipit nulla in justo. Suspendisse cursus rutrum augue. Nulla tincidunt tincidunt mi. Curabitur iaculis, lorem vel rhoncus faucibus, felis magna fermentum augue, et ultricies lacus lorem varius purus. Curabitur eu amet. 6 | -------------------------------------------------------------------------------- /test/ws_perf_SUITE_data/japanese.txt: -------------------------------------------------------------------------------- 1 | JAP 2 | 3 | 1 4 | 5 | 天と地の創造 6 | 7 | 1まだ何もなかった時、神は天と地を造りました。 2地は形も定まらず、闇に包まれた水の上を、さらに神の霊が覆っていました。 8 | 9 | 3「光よ、輝き出よ。」神が言われると、光がさっとさしてきました。 4-5それを見て、神は大いに満足し、光と闇とを区別しました。しばらくの間、光は輝き続け、やがて、もう一度闇に覆われました。神は光を「昼」、闇を「夜」と名づけました。こうして昼と夜ができて、一日目が終わりました。 10 | 11 | 12 | 6「もやは上下に分かれ、空と海になれ」と神が言われると、 7-8そのとおり水蒸気が二つに分かれ、空ができました。こうして二日目も終わりました。 13 | 14 | 9-10「空の下の水は集まって海となり、乾いた地が現れ出よ。」こう神が言われると、そのとおりになりました。神は乾いた地を「陸地」、水の部分を「海」と名づけました。それを見て満足すると、 11-12神はまた言われました。「陸地には、あらゆる種類の草、種のある植物、実のなる木が生えよ。それぞれの種から同じ種類の草や木が生えるようになれ。」すると、そのとおりになり、神は満足しました。 13これが三日目です。 15 | 16 | 14-15神のことばはさらに続きます。「空に光が輝き、地を照らせ。その光で、昼と夜の区別、季節の変化、一日や一年の区切りをつけよ。」すると、そのとおりになりました。 16こうして、地を照らす太陽と月ができました。太陽は大きく明るいので昼を、月は夜を治めました。このほかにも、星々が造られました。 17神はそれをみな空にちりばめ、地を照らすようにしました。 18こうして昼と夜を分け終えると、神は満足しました。 19ここまでが四日目の出来事です。 17 | 18 | 20神は再び言われました。「海は魚やその他の生き物であふれ、空はあらゆる種類の鳥で満ちよ。」 21-22神は海に住む大きな生き物をはじめ、あらゆる種類の魚と鳥を造りました。みなすばらしいものばかりです。神はそれを見て、「海いっぱいに満ちよ。鳥たちは地を覆うまでに増えよ」と祝福しました。 23これが五日目です。 19 | 20 | 24次に神は言われました。「地は、家畜や地をはうもの、野の獣など、あらゆる種類の生き物を生み出せ。」そのとおりになりました。 25神が造った生き物は、どれも満足のいくものばかりでした。 21 | 22 | 26そして最後に、神はこう言われました。「さあ、人間を造ろう。地と空と海のあらゆる生き物を治めさせるために、われわれに最も近い、われわれのかたちに似せて人間を造ろう。」 27このように人間は、天地を造った神の特性を持つ者として、男と女とに創造されました。 23 | 24 | 28神は人間を祝福して言われました。「地に増え広がり、大地を治めよ。あなたがたは、魚と鳥とすべての動物の主人なのだ。 29全地に生える種のある植物を見てみなさい。みなあなたがたのものだ。実のなる木もすべて与えるから、好きなだけ食べるがいい。 30また、動物や鳥にも、あらゆる草と植物を彼らの食物として与える。」 31神はでき上がった世界を隅から隅まで見渡しました。とてもすばらしい世界が広がっていました。こうして六日目が終わりました。 25 | 26 | 27 | 2 28 | 29 | 1ついに全世界が完成しました。 2すべてを創造し終えると、神は七日目には休まれ、 3この日を祝福して、聖なる日と定めました。この日、天地創造の働きが完了したからです。 30 | 31 | 人間の創造 32 | 33 | 人間の創造 34 | 35 | 人間の創造 36 | 37 | 人間の創造 38 | 39 | 人間の創造 40 | 41 | 人間の創造. 42 | --------------------------------------------------------------------------------