Compare commits

...

482 Commits

Author SHA1 Message Date
Anton Bachin
27ff43177b
Typo in README.md 2024-12-20 11:18:22 +03:00
Mostafa Touny
204a792b57
example/h-sql: tup2 is deprecated (#370) 2024-12-17 12:47:11 +03:00
asymmetric
da94944400
example/w-template-logic: explain % (#366) 2024-12-10 14:08:48 +03:00
Anton Bachin
ac92bc072e Module Dream assumes latest dream-httpaf 2024-12-01 20:24:14 +03:00
alxtuz
deb4526387
Replace all #files anchors by #folders-and-files (#361) 2024-11-04 21:47:42 +03:00
alxtuz
59ce312808
dream.mli: use #folders-and-files in example links (#360) 2024-11-01 17:43:55 +03:00
alxtuz
e4fa99812b
Docs: link to example/e-json from Dream.json (#359) 2024-11-01 11:59:45 +03:00
Anton Bachin
e94401a7d8
CI: try dune-cache (#353) 2024-10-25 08:13:50 +03:00
alxtuz
6c75fb9e22 CI: skip example/w-dream-html (#358)
w-dream-html depends on external package dream-html, which, in turn,
depends on package dream, which makes it awkward to install dream-html
inside Dream's CI. So skip this example.
2024-10-22 09:20:32 +03:00
alxtuz
186ab997d8 Fix opam lint in examples (#356)
Resolves #350.
2024-10-17 18:47:09 +03:00
Emmanuel Ferdman
b7b477379f
Update e-json.opam reference (#354)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-10-15 11:23:58 +03:00
Anton Bachin
a888e44e88
Replace vendored httpaf with httpun (#351) 2024-10-14 20:00:57 +03:00
Yawar Amin
c8ec9d1af9
Add dream-html example (#323) 2024-10-14 19:59:53 +03:00
Andrey Popp
6a1a2f0db2
Examples: add w-mlx (#330) 2024-10-14 19:39:10 +03:00
Anton Bachin
91b470dcd8
CI: use Ubuntu 22.04 (#352)
See https://github.com/ocaml/setup-ocaml/issues/872
2024-10-14 19:24:27 +03:00
Anton Bachin
d088771512 Dream.run docs: remove mention of ~stop_on_input
It was removed in #46, but a dangling reference to it still remained.
Caught by Yawar Amin in

  https://github.com/aantron/dream/issues/46#issuecomment-1962267244
2024-09-09 19:01:14 +03:00
Anton Bachin
5858e47c92
Log fd numbers (#345) 2024-09-05 18:56:19 +03:00
Anton Bachin
3f556c89f0 Fix some whitespace 2024-09-05 13:26:31 +03:00
Anton Bachin
1bf9f992f8 Fix typo 2024-09-05 12:56:41 +03:00
Anton Bachin
e84720d2ee Adjust whitespace and disabled job 2024-09-04 00:58:59 +03:00
Max Große
d3cb68bf18
Fix CI (#337)
Fixes #338.
Incorporates and closes #335.

Co-authored-by: Anton Bachin <antonbachin@yahoo.com>
2024-09-04 00:54:04 +03:00
Max Große
f8958e71cf
Fix typo in .opam description (#343) 2024-09-03 10:09:25 +03:00
Max Große
2b13c3206a
Remove unused documentation (#342)
upload_event was removed from dream.mli in 018e8e273c5e01e24efefa8e2b2b5a9e4145c7a1
new_global was removed in d81b1986b67ccf8024deeb3d1c223452116fdb4d
2024-09-03 09:49:21 +03:00
Anton Bachin
d2656380b5 Bump version shown in the docs 2024-09-03 09:43:54 +03:00
Anton Bachin
5a7871f845 Add make release-clean target 2024-09-03 09:40:22 +03:00
Anton Bachin
05a04f56c2 Dream.run: warn on any use of ~adjust_terminal 2024-08-23 16:00:18 +03:00
Anton Bachin
ea262bce22 Adjust whitespace after preceding commit 2024-08-23 15:50:39 +03:00
Max Große
b3f89c860f
Dream.run: disable ~adjust_terminal behavior (#336) 2024-08-23 15:46:13 +03:00
Anton Bachin
b0b401bf4b
Warn upon re-entrant call to Dream.sql (#333)
Resolves #332.
2024-08-21 17:29:44 +03:00
Anton Bachin
6081749621 Document Dream.sql_pool ?size argument
Prompted by #332.
2024-08-21 11:52:24 +03:00
Anton Bachin
4ea4d94ca6 Touch up Makefiles 2024-08-21 11:51:30 +03:00
Anton Bachin
17c113380f
Adapt to mirage-crypto 1.0.0 (#334)
Fixes #328.
Closes #331.
2024-08-21 11:10:28 +03:00
Anton Bachin
7e5f18abcb Add html_of_jsx as with-test dependency 2024-07-25 09:06:13 +03:00
David Sancho
d72f21d18f
Add html_of_jsx example (#326) 2024-07-25 09:05:05 +03:00
Anton Bachin
b059575c57 Install tyxml-jsx as a test dep
Possible since https://github.com/ocsigen/tyxml/pull/312 was released in
TyXML 4.6.0.
2024-07-24 14:48:31 +03:00
Anton Bachin
41eaac9afc Docs: add a lot more links 2024-05-29 22:57:14 +03:00
Anton Bachin
d30fa5e322 make release: use SHA-256 instead of MD5
As recommended by the linter in opam-repository.
2024-05-28 15:46:06 +03:00
Anton Bachin
8eb7cf2c40 Docs: update version and copyright year 2024-05-28 14:52:20 +03:00
Anton Bachin
b2abbecfe5 Try again to disable dream.as GitHub Actions 2024-05-28 12:43:42 +03:00
Anton Bachin
e71c7aed2f Remove references to playground and dream.as
Maintaining dream.as has become a time sink and it is often down. This
is likely due to an upstream issue in the HTTP stack, which might be
replaced soon anyway. For now, it is best not to try to run the
playground.

Closes #123.
Closes #222.
2024-05-28 12:34:00 +03:00
Anton Bachin
3033ad6f85 make release: handle opam versions better 2024-05-28 12:00:53 +03:00
Anton Bachin
ba5e384b9f dream.opam: depend on latest dream-httpaf 2024-05-28 00:57:55 +03:00
v-gb
78c79e3328
Fix build error in Fly.io Dockerfile (#315) 2024-01-18 13:38:56 +03:00
Quentin Stiévenart
e9154ac51d
Fix typo in doc of Dream.router (#314)
Dream.param takes the request as first argument.
2024-01-02 17:51:02 +03:00
re.natillas
e513b8a6db
Update docker install command (#312)
Update example/z-docker-esy Docker install command
2023-12-26 13:34:21 +03:00
Anton Bachin
f96c81209f Tweak CONTRIBUTING.md
Resolves #310.
2023-12-26 11:57:10 +03:00
Anton Bachin
bbbf188a01 Examples: add --root . to build steps
Resolves #308.
2023-12-26 10:12:58 +03:00
re.natillas
5f42c87227
Sync example/r-template-files README with the code (#311) 2023-12-25 20:43:17 +03:00
Anton Bachin
1d582af222 Docs: reflow text in .mli files 2023-12-25 20:05:07 +03:00
denver-s
1337a4d4d7 Docs: replace inria.fr URLs with ocaml.org URLs
inria.fr URLs now redirect to ocaml.org.
2023-12-25 20:05:07 +03:00
Anton Bachin
337a35fb12 Depend on current Dream in playground 2023-12-01 00:50:27 +03:00
Anton Bachin
087b5ff1ea Oversight in example/r-fullstack-melange README 2023-11-30 20:00:23 +03:00
Anton Bachin
e570114299 Update example/r-fullstack-melange
- Use opam instead of esy, following Melange.
- Use new Dune build integration.

Fixes #293.
2023-11-30 19:55:57 +03:00
Anton Bachin
090b62287b example/z-playground: add dummy examples.ml
Fixes #294.
2023-11-30 17:39:05 +03:00
Anton Bachin
8abe1a162e README: detail opam instructions 2023-11-30 17:19:15 +03:00
Anton Bachin
e27a8123cf README: prefer opam 2023-11-30 17:16:27 +03:00
Anton Bachin
108c3cc4a9 Give all example .opam files unique names
This simplifies the example command lines. More importantly, it makes it
much easier to vendor Dream into a project.
2023-11-30 17:12:38 +03:00
Anton Bachin
680d5d289d Tweak example/1-hello text 2023-11-29 19:15:24 +03:00
Anton Bachin
c75379625d Partially port the systemd example to opam 2023-11-29 19:13:04 +03:00
Anton Bachin
41d4bb0b38 Fix Debian Docker examples; convert to opam
Install libssl3 package in Debian.

Fixes #305.
2023-11-29 19:07:38 +03:00
Anton Bachin
20f62d209e Convert most examples to opam
Reason examples still use esy.
2023-11-29 18:18:33 +03:00
Anton Bachin
59abca6af0 Convert Quick Start script to use opam 2023-11-29 16:40:57 +03:00
Anton Bachin
a9a9dfc09f Docs: flip logic of sun and moon theme icons 2023-11-14 12:42:16 +03:00
Anton Bachin
3c49624bb2 Document Dream.run ?socket_path 2023-11-14 12:31:37 +03:00
Anton Bachin
cb60070633 Adjust whitespace after preceding commit 2023-11-12 19:01:05 +03:00
Thomas Gazagnaire
689eb2cff6
Support for listening on Unix domain sockets (#219)
Resolves #218.
2023-11-12 18:58:46 +03:00
Anton Bachin
99388503cc EML: don't access internal Dream_pure module
Fixes #291.
2023-11-12 18:25:39 +03:00
Anton Bachin
4c18ba8450 WebSocket: don't need client handlers value
Since https://github.com/anmonteiro/websocketaf/issues/39, an Obj.magic
cast from the server's WebSocket handlers to the client's is not longer
necessary.

See also https://github.com/aantron/dream/issues/181.
2023-11-10 21:06:30 +03:00
Anton Bachin
a2cfbf4975 WebSocket: allow non-FIN frames
Since https://github.com/anmonteiro/websocketaf/issues/33, websocket/af
supports sending frames without the FIN bit. Begin using this in Dream.

See also https://github.com/aantron/dream/issues/181.
2023-11-10 20:54:40 +03:00
Anton Bachin
aaabf4dfe3 WebSocket: send ping and pong payloads
Since https://github.com/anmonteiro/websocketaf/issues/36 was fixed
recently, websocket/af supports sending ping and pong payloads, as
required by the WebSocket spec. This commit has dream-httpaf using that
support.

See also https://github.com/aantron/dream/issues/181.
2023-11-10 11:23:19 +03:00
Anton Bachin
8cb51f18ee Document Dream.form ~csrf:false 2023-11-07 21:06:02 +03:00
Anton Bachin
a3579218c2 Upgrade to latest websocket/af fork commits 2023-11-07 18:58:19 +03:00
Anton Bachin
d802548914 Upgrade H2 to 0.11 and newest commits 2023-11-07 18:50:20 +03:00
Anton Bachin
51902fc63c Pull in latest http/af fork commits
These commits do not affect the Dream code in any way.
2023-11-07 18:43:36 +03:00
Anton Bachin
c86e49225e Upgrade Gluten to 0.5 2023-11-07 18:37:35 +03:00
Anton Bachin
9c72a39ef8 Log initialization: respect custom log levels
Fixes #299.
2023-11-06 14:26:42 +03:00
Pedro Dias
1c60e60f17
example/z-docker-opam: update alpine version (#300) 2023-11-02 16:36:41 +03:00
Tim McGilchrist
f5c8ba0cff
Update dream-mirage (#283)
Mainly to provide csrf_tag rather than form_tag helper.
2023-11-02 16:27:16 +03:00
Louis Pilfold
60a0dc5df5
Fix typo (#292) 2023-10-31 17:33:19 +03:00
Petter A. Urkedal
6e58736e28
Compatibility with Caqti 2.0.0 (#302) 2023-10-31 17:20:40 +03:00
Anton Bachin
8140a600e4 Advance vendored Gluten commit
Fixes #286 by including anmonteiro/gluten#58.
2023-07-14 15:41:54 +03:00
Benjamin Thomas
4a5310b09b
Fix JSON example broken by ppx_yojson_conv 0.16.0 (#287) 2023-07-14 15:25:57 +03:00
Benjamin Thomas
aada26ce54
CONTRIBUTING.md: fix bad remote URL (#288) 2023-07-13 14:33:17 +03:00
Anton Bachin
7a2c5a03ff Add Dream.drop_session_field
Resolves #284.
2023-06-22 15:50:26 +03:00
Thomas Coopman
1bf8e1115c Add STDOUT as output from dream_eml (#228)
Resolves #227.
2023-06-05 15:12:32 +03:00
Anton Bachin
10ae36fa5f Live reload: retry indefinitely 2023-06-01 16:37:01 +03:00
Anton Bachin
8e89f7cd2a Live reload: remove optional arguments 2023-06-01 16:37:01 +03:00
Thibaut Mattio
7b46896bf9 Add a Dream.livereload middleware
The code is adapted from dream-livereload, itself adapted from the w-live-reload example.
We update the w-live-reload to use the newly introduced middleware.

Apply nits
2023-06-01 16:37:01 +03:00
Anton Bachin
635c0589e9
Get the Windows CI working (#282)
The syntax of the constraint is based on a suggestion in Discord.

Tests are disabled due to a difference in ppx_expect output on Windows.

Co-authored-by: Et7f3 <cadeaudeelie@gmail.com>
2023-05-22 16:14:19 +03:00
Anton Bachin
b55d1914cf Docs: initialize theme earlier to avoid flicker
Follow-on to #268.
2023-05-22 16:08:59 +03:00
Tom Ekander
e529b0eb15
Docs: add light- heme and use save in local storage (#268)
Also removed the shadow on the <h1> element. It was probably left over
from an early version of the dark theme, before Dream's alpha 1 release.

Resolves #235.

Co-authored-by: Anton Bachin <antonbachin@yahoo.com>
2023-05-22 16:08:23 +03:00
Anton Bachin
6e666d4c70 Playground: update lockfiles 2023-05-14 16:55:08 +03:00
Anton Bachin
f5558638f3 Upgrades while rebuilding the playground 2023-05-14 16:34:55 +03:00
Anton Bachin
d35a6338d1 Update dream-serve and add a couple tests 2023-05-14 08:15:06 +03:00
Yawar Amin
c7da98b718
Fix typo (#281) 2023-05-14 08:13:14 +03:00
Anton Bachin
e14bd91a44 Remove deprecated values
Path getter and setter not removed. See #238. not_found just deprecated,
so not removed, for users to have more of a chance to adapt.
2023-05-11 06:51:12 +03:00
Jean-Michel Bea
14093e16cc Reason 3.8.x releases support recent OCaml
Cherry-picked from #229.
2023-05-11 05:49:31 +03:00
Dennis Dang
006196fa0c
Upgrade GraphiQL to 2.4.1 (#271) 2023-05-03 15:21:46 +03:00
Anton Bachin
0826c267b3 Clarify docs expected markup mismatch message 2023-04-28 15:27:18 +03:00
Anton Bachin
881d26da23 Refresh CONTRIBUTING.md 2023-04-28 15:10:33 +03:00
Anton Bachin
765da90414 .gitignore nano .swp files 2023-04-28 10:24:40 +03:00
Anton Bachin
860e4563bd Fix link to example/w-watch in 1-hello 2023-04-27 10:37:21 +03:00
Dennis Dang
313fe46c3f
Update w-watch's README command to match directory (#267) 2023-04-25 07:47:00 +03:00
Anton Bachin
76faf6f3b2 Docs: link to note about trailing /
Follow-on to #265.
2023-04-24 10:36:27 +03:00
Rawley
561e99d837
Router: add doc about trailing slashes (#265) 2023-04-24 09:30:20 +03:00
Anton Bachin
c27a83ecd9 Adapt example/9-error to not_found deprecation
Done in 23b740622b4084162ffcd067d5a59514bcb7d289.
2023-04-23 22:22:43 +03:00
Anton Bachin
7117d90379 example/w-watch: requires Dune 3.7.0 2023-04-23 21:29:29 +03:00
Anton Bachin
d135ba6046 Change logger's tag to dream.logger
dream.log is too generic -- it appears to refer to the whole Dream log,
when it is meant to refer to Dream's logger.
2023-04-23 21:23:57 +03:00
Dennis Dang
dbf01b83df
Warn if response header has empty name (#262)
Co-authored-by: Anton Bachin <antonbachin@yahoo.com>
2023-04-23 17:20:11 +03:00
Anton Bachin
f784018e1d Rename w-fswatch to w-watch
Follow-on to #266.
2023-04-23 16:47:39 +03:00
Anton Bachin
23b740622b Deprecate Dream.not_found 2023-04-23 16:40:24 +03:00
Dennis Dang
a57e8bc860
Use dune exec -w in fswatch example (#266) 2023-04-23 16:39:29 +03:00
Anton Bachin
3df0d85c0a Dream.run docs: don't show non-existent options 2023-04-23 09:02:26 +03:00
Anton Bachin
1b0ac702b0 Update Dream.run docs w.r.t. ?debug
?debug was removed in 640a1b218b0c6932088077416455463ffd34f036. This
commit updates the docs to refer to its replacement.
2023-04-23 08:57:03 +03:00
Dennis Dang
a2961cd7fa
Upgrade ocamlformat to 0.25.1 (#263) 2023-04-22 20:42:14 +03:00
Anton Bachin
baa222bb8e Upgrade vendored deps and adapt their Eio support 2023-04-21 08:32:57 +03:00
Tim McGilchrist
18cd2a08ac
Mirage: add dependency on rresult (#260) 2023-04-21 07:37:58 +03:00
Anton Bachin
a39c938835 README: add Twitch to contact info 2023-04-20 22:13:24 +03:00
Anton Bachin
edd0cd9167 Fix make watch 2023-04-19 09:29:33 +03:00
Anton Bachin
da604f1478 make build: Dune workspace-friendly command 2023-04-19 09:14:33 +03:00
Anton Bachin
599efd55fc Docs: fix cross-reference 2023-04-14 10:57:29 +03:00
Anton Bachin
f0cde12979 Examples: esy.json: upgrade OCaml to 4.14
esy does not seem to offer OCaml 5.0.0 at the moment.

Resolves #256.
2023-04-14 10:32:25 +03:00
Anton Bachin
d2f0016613 Upgrade examples to use Dream alpha 5
Resolves #257.
2023-04-14 05:43:02 +03:00
Anton Bachin
fcc618d200 Rephrase note about nginx WebSocket proxying 2023-03-29 20:20:26 +03:00
Thomas Refis
27ee901773
nginx example: add a note about the use of websockets (#252) 2023-03-29 20:12:59 +03:00
Anton Bachin
cede19ac1b Upgrade to odoc 2.0.2 2023-03-29 13:43:25 +03:00
Anton Bachin
a6b705ca16 Package dream will require the latest dream-httpaf 2023-03-28 13:08:41 +03:00
Anton Bachin
c078067e71 Add make deps target 2023-03-28 12:50:20 +03:00
Anton Bachin
1b96d180c9 Bump version in docs 2023-03-28 12:21:43 +03:00
Anton Bachin
da15b89c38 Update release script 2023-03-28 12:21:30 +03:00
Anton Bachin
70bb4332b1 Basic README for the Mirage example 2023-03-26 07:08:30 +03:00
Anton Bachin
89f21f4427 dream-mirage depends on duration
As part of the Let's Encrypt support. It's questionable that this is
built right into core dream-mirage, but that is how it is at this point.
2023-03-17 13:15:02 +03:00
Anton Bachin
368d84cadd http/af no longer uses result package 2023-03-17 13:14:14 +03:00
Anton Bachin
ff97ac7583 Upgrade ocamlformat 2023-03-14 10:23:00 +03:00
Anton Bachin
a1ca19e10e Add example/w-mirage and build it in CI 2023-03-14 10:08:09 +03:00
Anton Bachin
f20a335ed9 Rename example/w-mirage to w-mirage-letsencrypt 2023-03-13 17:13:53 +03:00
Anton Bachin
72834957cc Adjust grammar in example/1-hello 2023-03-13 15:51:46 +03:00
Anton Bachin
ac4a4e077b Clean up src/vendor/dune
- Do a topological sort of the vendored libraries.
- Place each dependency on its own line for diff-friendliness.
2023-03-13 15:50:01 +03:00
Anton Bachin
c394615293 Continue renaming for Mirage version 2023-03-13 15:39:50 +03:00
Anton Bachin
c8d2db0f63 Rename vendored modules to avoid build conflicts
Fixes #198.
Closes #200.
2023-03-10 14:15:03 +03:00
Anton Bachin
1ed0a6fed5 Revert "Mirage: add mirage-stack dependency"
This reverts commit 3eb7834bb18fcba8c8f065e69b9a23ec31d91fad. This
commit made a change to dream.opam that was probably intended for
dream-mirage.opam, and was probably wrong for that file anyway, due to
mirage-stack being deprecated.

Added in #249.
2023-03-09 13:41:05 +03:00
Anton Bachin
80be1362df Rewind h2 to a commit that is compatible with paf
Follow-on to #249.
2023-03-09 12:06:36 +03:00
Anton Bachin
30690bc299 dream-mirage.opam: alphabetize dependencies 2023-03-09 09:52:49 +03:00
Lucas Pluvinage
206f19d0ed Missing dependencies in dream-mirage
@aantron: replaced mirage-stack with tcpip due to
9cc4a6e76d2273316bffd1ef0ce4cbf528ccd5c8.
2023-03-09 09:51:30 +03:00
Anton Bachin
ec533f2306 Add new Gluten deps to dream-httpaf.opam 2023-03-09 09:35:03 +03:00
Anton Bachin
fedfd2bec7 Revert "Add dependency to dream-pure in dream-httpaf"
This reverts commit f7b45a357e5bd0170a512e8ace431de8e7600d4f. There is
already a dependency.
2023-03-09 09:23:44 +03:00
Anton Bachin
dd83bf3760 Caqti: latest infix operators require 1.8.0 2023-03-09 09:18:51 +03:00
Anton Bachin
10a6e3459f
Merge pull request #249 from aantron/cherries
Cherry-picking updates from the Mirage maintenance fork
2023-03-08 21:41:51 +03:00
Lucas Pluvinage
235ac215cd CI: pass opam file lint on helper opam files 2023-03-08 21:21:33 +03:00
Lucas Pluvinage
bc58f05af9 Add js_of_ocaml as a test dependency 2023-03-08 21:19:27 +03:00
Lucas Pluvinage
b5187b8ca4 Add missing function in dream-mirage's signature 2023-03-08 21:13:24 +03:00
Lucas Pluvinage
c132456293 Update vendored dependencies 2023-03-08 16:21:32 +03:00
Lucas Pluvinage
0d837d4b37 dream-mirage: add missing parts in the API 2023-03-08 10:47:46 +03:00
Lucas Pluvinage
bb2e409c09 Mirage: fix memory leak 2023-03-08 10:46:11 +03:00
Lucas Pluvinage
c1025ad8fb Mirage: fix memory leak 2023-03-08 10:45:52 +03:00
Lucas Pluvinage
b703ad1730 Mirage: adapt to new paf and http/af 2023-03-08 10:40:46 +03:00
Lucas Pluvinage
930d15f114 Update submodules
h2 was already at a more advanced commit in Dream master. I also moved
the tweak of src/vendor/dune to this commit rather than a following one,
otherwise the build gets broken, which will needlessly screw up git
bisect later.

Co-authored-by: Anton Bachin <antonbachin@yahoo.com>
2023-03-08 05:52:41 +03:00
Hannes Mehnert
4da674a3c5 Mirage: set Content-Length headers 2023-03-08 04:40:24 +03:00
Lucas Pluvinage
104859bc5f Mirage: separate TCP connection from TLS connection 2023-03-08 04:37:19 +03:00
Lucas Pluvinage
9cc4a6e76d Update paf commit (mirage-stack => tcpip) 2023-03-07 14:29:44 +03:00
Lucas Pluvinage
6361b0467e vendored paf requires emile 2023-03-07 14:05:37 +03:00
Lucas Pluvinage
831f32ba91 Mirage: reflect API changes 2023-03-07 13:46:10 +03:00
Lucas Pluvinage
c800706b74 Mirage: maximize shared API 2023-03-07 13:45:50 +03:00
Thibaut Mattio
f7b45a357e Add dependency to dream-pure in dream-httpaf
@aantron: This shouldn't be an = constraint, but that can be addressed
in a future commit. The dependency itself is already an improvement.
2023-03-07 13:45:25 +03:00
Thibaut Mattio
e75e50e70e dream-mirage: fix opam dependencies 2023-03-07 13:44:52 +03:00
Lucas Pluvinage
abaf7d551b Mirage: add all response helpers 2023-03-07 13:43:18 +03:00
Lucas Pluvinage
3eb7834bb1 Mirage: add mirage-stack dependency 2023-03-07 13:43:07 +03:00
Lucas Pluvinage
ca3faeaab9 Fix for Mirage again 2023-03-07 12:24:15 +03:00
Lucas Pluvinage
d26fd04cea Finish Mirage fix 2023-03-07 12:23:05 +03:00
Lucas Pluvinage
79201d7af9 Fix mirage 2023-03-07 12:21:59 +03:00
Anton Bachin
b3d1f9495d Build on OCaml 4.14, 5.0 2023-03-04 07:41:16 +03:00
Anton Bachin
c8286522b5 Clarify sorting of form fields
Prompted by #245.
2023-03-03 14:27:25 +03:00
Anton Bachin
7c0182215c Update copyright year 2023-03-03 12:56:53 +03:00
Anton Bachin
180da09056 Use Caqti infix operators for future-proofing 2023-03-03 10:59:36 +03:00
Anton Bachin
61fa8d7099 Update dependencies and README 2023-03-02 16:51:41 +03:00
Lauri Laaksonen
ef29ea9eb7 Fix build failure due to label warning 2023-03-02 16:51:41 +03:00
Thomas Coopman
105fc05b52
space-around-records was set twice (#225) 2023-03-02 16:24:07 +03:00
Anton Bachin
3eb6f38e4f Propagate preceding fix to all examples 2023-03-02 15:54:52 +03:00
Alain Armand
f088baecb7 Update "@opam/conf-libssl": "3" in esy.json (#224) 2023-03-02 15:54:46 +03:00
Anton Bachin
915e318496 Skip tests on <= 4.09 due to ppx_expect
See comment in .github/workflows/test.yml.
2023-03-02 15:54:41 +03:00
Anton Bachin
4294547f39 Adapt PostgreSQL example to recent Caqti
See recent commits for details.
2023-03-02 15:54:33 +03:00
Anton Bachin
645805b5ad Adapt GraphQL examples to graphql-server 0.14.0 2023-03-02 15:54:27 +03:00
Davi William Moraes Suga
e0ff41e70e Fixed typo on Fly.io guide link (#239, #232)
Co-authored-by: Patrick Kilgore <git@pck.email>
2023-03-02 15:53:17 +03:00
Anton Bachin
f31a2ca898 Adapt example/h-sql to Caqti deprecations
Caqti 1.8.0 deprecated Caqti_request.exec and other functions in favor
of the new convenience interface, which was added in Caqti 1.7.0.
2023-03-01 13:00:16 +03:00
Anton Bachin
4ced286937 Adapt to formatting changes in ppx_expect v0.15.0 2023-03-01 12:14:51 +03:00
Anton Bachin
fd784d9379 Adapt to deprecations in Caqti 1.8.0
The full fix is to switch to the infix operators added by the new
convenience interface in Caqti 1.7.0, which will be done in a later
commit. The purpose of the present commit is to get the build clean
again with the minimum reasonable changes.
2023-03-01 10:53:59 +03:00
Anton Bachin
cdd4a1bd9d Upgrade h2 for OCaml 5 compatibility 2023-02-28 16:59:43 +03:00
Anton Bachin
9439ca16b5 Adapt to mirage-crypto-rng 0.11.0 2023-02-28 16:58:59 +03:00
Alexander Skvortsov
2386083170
docs: Remove unnecessary @@ Dream.not_found from code sample (#213)
It doesn't seem to be necessary anymore, since `Dream.router` returns a handler, not a middleware.
2022-03-24 20:49:10 +03:00
Anton Bachin
3098d0a194 Update examples and metadata for alpha4 2022-03-09 19:47:51 +03:00
Anton Bachin
7f196a2573 Bump version in docs 2022-03-08 12:47:16 +03:00
Anton Bachin
b5d6561db3 Docs: Dream.run ?secret is now Dream.set_secret
Fixes #207.
2022-03-07 18:57:59 +03:00
Patrick Ferris
f93d09befd
Add camlp-streams dep for 5.00.0 (#210) 2022-03-07 18:45:32 +03:00
Yawar Amin
dcc351386e
Update docs for form_result `Expired (#206)
Since it now has two fields.
2022-02-26 21:33:37 +03:00
Thomas Haessle
9ac86d789f
Update router in examples for alpha3 (#205) 2022-02-22 15:55:40 +03:00
Anton Bachin
929a9042db Update .ocamlformat to 0.20.1
Dream was using some of the removed options based on misconceptions
about what they did. Others seem to have good substitutes among the
remaining options.

For if-then-else = fit-or-vertical, see

  https://github.com/ocaml-ppx/ocamlformat/issues/1997#issuecomment-1041201540
2022-02-16 10:44:34 +03:00
Anton Bachin
dc844913d7 Docs: fix formatting of Dream.set_secret 2022-02-16 08:19:23 +03:00
Anton Bachin
cfacc8469a Automatically close streams and WebSockets 2022-02-16 08:10:05 +03:00
Anton Bachin
3c44be0cea Cookies should have SameSite=Lax by default
Resolves #190.
2022-02-16 07:19:28 +03:00
Anton Bachin
ec9643b731 Improve examples 2022-02-15 10:38:44 +03:00
Anton Bachin
6009610e49 Clarify code after preceding and earlier commits
Function Form.form has received several edits over the past months, and
it needed an overall cleanup, especially since Dream itself has also
changed internal layout and some conventions.
2022-02-15 08:45:48 +03:00
Yawar Amin
3ada178030 Split content-type header value
Some clients add a suffix to the value, e.g.
`"application/x-www-form-urlencoded; charset=UTF-8"`. In this case we want to
throw away the extra data before checking the content-type.
2022-02-15 08:45:48 +03:00
Anton Bachin
67cd3b0168 Rename template logic examples 2022-02-14 10:35:51 +03:00
Anton Bachin
3d9c7c3346 s/m-mirage/w-mirage/ 2022-02-14 07:00:10 +03:00
Anton Bachin
a88a8cecbf Makefile: fix coverage cleaning in Dune workspace 2022-02-14 05:58:57 +03:00
Anton Bachin
515def2875 Clean up the docs build slightly 2022-02-13 22:42:30 +03:00
Anton Bachin
2162ec7e37 Delete request protocol version field 2022-02-13 16:56:29 +03:00
Anton Bachin
5f50acf779 Move header lowercasing to the HTTP/2 adapter 2022-02-13 16:49:58 +03:00
Anton Bachin
2621045100 Handle Content-Length at the HTTP/1 adapter 2022-02-13 16:45:27 +03:00
Anton Bachin
67e91f1501 Add Dream.set_status 2022-02-13 16:21:55 +03:00
Anton Bachin
55c4d0f836 message.ml: move WebSocket functions in the file 2022-02-13 16:19:25 +03:00
Anton Bachin
e76e3855ff Inline WebSocket field into response record 2022-02-13 16:18:29 +03:00
Anton Bachin
9f9caeab0d message.ml: move body functions in the file 2022-02-13 16:14:44 +03:00
Anton Bachin
a929404aef Inline body field into HTTP message record 2022-02-13 16:13:44 +03:00
Anton Bachin
38d89e4f23 Test Dream.pipeline 2022-02-13 16:09:05 +03:00
Anton Bachin
24dff54482 Tweak formats.ml 2022-02-13 16:01:33 +03:00
Anton Bachin
77fb36b1e8 Test and optimize Dream.normalize_method 2022-02-13 15:56:36 +03:00
Anton Bachin
e0388203f0 Update playground to alpha3 2022-02-13 11:59:15 +03:00
Anton Bachin
c82308b976 Update example esy.jsons to point to alpha3 2022-02-13 11:16:33 +03:00
Anton Bachin
bc3c00f700 Update README graphic 2022-02-12 04:54:22 +03:00
Anton Bachin
847acd2fa2 Require mirage-clock >= 3.0.0 2022-02-12 04:41:30 +03:00
Anton Bachin
c0aeaada68 Update release script and package metadata 2022-02-11 22:50:25 +03:00
Anton Bachin
cc10603064 Be consistent about method="POST" attribute 2022-02-11 15:59:24 +03:00
Anton Bachin
9bec26f837 Change query functions to use t-first style 2022-02-11 15:43:49 +03:00
Anton Bachin
940b07a78f Update all examples 2022-02-11 15:39:39 +03:00
Anton Bachin
a365a1762e Routers are now handlers rather than middleware 2022-02-11 14:03:21 +03:00
Anton Bachin
7320f875d1 Rename ~https to ~tls 2022-02-11 13:50:24 +03:00
Anton Bachin
30ef880708 Update some of the examples 2022-02-11 13:39:00 +03:00
Anton Bachin
80b2f60a92 Catch up renamings and deprecations 2022-02-11 13:03:35 +03:00
Anton Bachin
181175d3a9 Update docs and tweak signatures 2022-02-11 12:41:55 +03:00
Anton Bachin
2cb98ad0a6 Catch up the docs build 2022-02-11 10:14:41 +03:00
Anton Bachin
618a21dcdc Clarify Stream and WebSocket APIs 2022-02-11 08:51:11 +03:00
Anton Bachin
25c0d1ea39 Catch up Stream tests 2022-02-11 06:50:12 +03:00
Anton Bachin
ff9639dfaf Fix CI 2022-02-11 06:31:51 +03:00
Anton Bachin
11243faf70 README: refresh Discord invites 2022-02-09 18:05:06 +03:00
Anton Bachin
e533e70397 Move websocket/af type inequality workaround
See https://github.com/anmonteiro/websocketaf/issues/39.
2022-02-08 21:19:27 +03:00
Anton Bachin
f82a51b0d5 Use stream type at higher levels of the API 2022-02-08 13:23:17 +03:00
Anton Bachin
c7fb937a64 Don't reuse response streams for WebSockets
WebSockets should have their own pair of streams. That way, middlewares
that transform response bodies can transparently work on WebSocket
responses, without accidentally transforming WebSocket messages.
2022-02-08 12:53:24 +03:00
Yawar Amin
acc2a1695e
Add Dream.csrf_tag (#201)
This lets us easily inject a hidden field containing a CSRF token into
a form, while manually controlling all attributes of the form, e.g.
`name`, `id`, etc.

Fixes #199.
2022-02-08 08:45:18 +03:00
Anton Bachin
257f0e0d41 Makefile: respect workspace root in test targets 2022-02-04 11:10:13 +03:00
Anton Bachin
264e37d7fc Adapt to recent changes in multipart_form
Fixes #193.
Fixes #197.
2022-02-02 13:51:05 +03:00
Anton Bachin
b76ac67cba Transfer-Encoding: check for Content-Length 2022-01-27 14:34:38 +03:00
Anton Bachin
3d05ac6ed7 Stream: resume writer after ping, pong 2022-01-25 12:17:30 +03:00
Anton Bachin
7e18c4d2f4 stream.ml: fix whitespace from previous change 2022-01-22 22:14:22 +03:00
Anton Bachin
3705621262 Don't terminate convenience readers on pong events 2022-01-22 22:05:55 +03:00
Anton Bachin
9ee3e04481 Allow pushing exceptions into string streams 2022-01-22 22:04:43 +03:00
Anton Bachin
e20b0b4e18 Get rid of Stream.ready 2022-01-21 11:32:39 +03:00
Anton Bachin
5896c5a641 dream-pure: generalize higher-level stream I/O
...so that it can be used to perform operations on either the server's
stream or the client's stream.
2022-01-21 11:32:33 +03:00
Anton Bachin
acc2efc8fe Move WebSocket adapter to package dream-httpaf
It is needed by both the client and the server.
2022-01-19 16:23:54 +03:00
Anton Bachin
a8d6e5c06d WebSocket adapter should use bare stream
...so that it can be used on both the client and the server.
2022-01-19 15:42:44 +03:00
Anton Bachin
5cd57e1ea1 Forward exceptions across streams 2022-01-15 19:45:34 +03:00
Anton Bachin
4dce6a7a4d Tweak indentation 2022-01-11 19:54:52 +03:00
Anton Bachin
d418a79165 Update example esy.jsons 2022-01-05 00:42:06 +03:00
Anton Bachin
03e4d37cb5 ReScript example: needs an esy install 2022-01-01 05:58:41 +03:00
Glenn Slotte
024131b0eb
bs-platform, bs-webapi -> rescript, rescript-webapi (#188) 2022-01-01 05:53:08 +03:00
Anton Bachin
84128adee6 Expose dream-pure type equalities 2021-12-29 20:29:06 +03:00
Anton Bachin
0664abd933 Body caching for both requests and responses 2021-12-29 15:55:57 +03:00
Anton Bachin
fa815c0259 Add Message.set_target 2021-12-29 15:05:38 +03:00
Anton Bachin
536c4a41db Provide some common pre-allocated streams 2021-12-22 16:10:20 +03:00
Anton Bachin
2ecfc044d4 Package dream requires Alcotest for testing 2021-12-22 08:18:14 +03:00
Anton Bachin
3acb3cc799 Cache body promises when using Dream.body
Fixes #185.
2021-12-22 01:35:45 +03:00
Anton Bachin
56504439b6 Fix Dream.set_body 2021-12-22 01:26:04 +03:00
Anton Bachin
95f6a6f895 Restore multipart upload state 2021-12-22 01:05:02 +03:00
Anton Bachin
8e7c711dda Fix memory sessions (silly typo during refactor) 2021-12-22 01:04:33 +03:00
Anton Bachin
fe537f4aa9 dream-httpaf uses lwt_ppx 2021-12-22 00:28:19 +03:00
Felix Krull
a8357030aa
dream-pure depends on lwt_ppx (#186) 2021-12-22 00:26:16 +03:00
Anton Bachin
4fbb0c56f4 dream-pure does not depend on multipart_form 2021-12-22 00:10:44 +03:00
Anton Bachin
812bcad8c4 message.mli: prune type abbreviations 2021-12-21 13:41:33 +03:00
Anton Bachin
6f3b2a235a mv inmost.ml message.ml 2021-12-21 13:32:44 +03:00
Anton Bachin
9df46cb329 inmost.ml: clarify some record fields 2021-12-19 14:44:57 +03:00
Anton Bachin
553567f2d8 Sort inmost.ml to match all the .mli files 2021-12-19 14:41:17 +03:00
Anton Bachin
d2b8e0f7a0 Rename Dream__localhost to match its directory 2021-12-19 14:28:29 +03:00
Anton Bachin
85f3aec86e WebSocket write: set FIN bit by default 2021-12-18 22:58:53 +03:00
Anton Bachin
773c346416 Move cipher tests from pure to server tests 2021-12-18 22:47:33 +03:00
Anton Bachin
71e06b78eb Catch up the tests 2021-12-18 22:45:32 +03:00
Anton Bachin
bfa5ab1c5c Tweak deprecation message formatting 2021-12-18 22:31:36 +03:00
Anton Bachin
64d7df3538 mv test/expect/middleware test/expect/server 2021-12-18 22:25:45 +03:00
Anton Bachin
a680f4be41 Catch up most of the examples 2021-12-18 22:20:15 +03:00
Anton Bachin
d1ba236f1d Expose Stream API and reinterpret WebSockets 2021-12-18 18:18:19 +03:00
Anton Bachin
1da1452bfc Compose dream.ml explicitly (delete most includes) 2021-12-17 08:59:48 +03:00
Anton Bachin
ed4c24f6a8 Move helpers 2021-12-17 08:01:07 +03:00
Anton Bachin
2335f69fbd Rename dream.middleware to dream.server 2021-12-17 07:47:29 +03:00
Anton Bachin
9e8bc2fb8e mv src/middleware src/server 2021-12-17 07:31:52 +03:00
Anton Bachin
5a54d5c1ee Rename "locals" to "fields" 2021-12-17 07:26:57 +03:00
Anton Bachin
dd41df9e65 Break up dream-pure.mli 2021-12-16 22:46:50 +03:00
Anton Bachin
73c56ce1c4 Fix some warnings 2021-12-16 22:10:08 +03:00
Anton Bachin
110575db83 Factor out dream-httpaf 2021-12-16 22:05:42 +03:00
Anton Bachin
7aa5e7ba1c dream-pure no longer depends on multipart_form
The server and client will depend on multipart_form independently.
2021-12-16 21:33:11 +03:00
Anton Bachin
d7e81a28fe Convert to mutable requests and responses
Begin adopting a t-first style suitable for mutable objects.

Resolves #21.
2021-12-16 20:44:46 +03:00
Anton Bachin
865217859f Cut request_from_http from dream-pure
This completes an initial version of the refactoring mentioned in #8.
2021-12-14 19:44:10 +03:00
Anton Bachin
ba859abb23 Move error types from dream-pure to server 2021-12-14 19:34:26 +03:00
Anton Bachin
918cb3cb35 Move multipart state from dream-pure and break it
It will be much easier to reimplement multipart upload state once
requests become mutable, since the state can be simply written into the
request. For now, multipart uploads are broken.
2021-12-14 19:12:25 +03:00
Anton Bachin
5d391a62a2 Move all_cookies from dream-pure to server 2021-12-14 19:05:44 +03:00
Anton Bachin
267e2de87b Move html and json helpers from dream-pure 2021-12-14 19:03:24 +03:00
Anton Bachin
598367067b Move query strings from dream-pure to server 2021-12-14 18:56:20 +03:00
Anton Bachin
0c7b464f90 Move paths and prefixes from dream-pure to server 2021-12-14 18:47:08 +03:00
Anton Bachin
3dcb88d6ea Move https field from dream-pure to server 2021-12-14 13:40:24 +03:00
Anton Bachin
037645f5ff Move client field from dream-pure to server 2021-12-14 13:27:07 +03:00
Anton Bachin
af8085a5f1 Delete the "app" concept 2021-12-14 11:12:36 +03:00
Anton Bachin
b355e00f8f Pass error handlers around explicitly 2021-12-14 11:05:07 +03:00
Anton Bachin
640a1b218b Replace ~debug flag by separate error handler 2021-12-14 10:40:56 +03:00
Anton Bachin
6c726d5271 Move the https field to requests 2021-12-13 19:24:03 +03:00
Anton Bachin
ebeac7c735 Reorder dream-pure.mli a bit
Looks like a paste went to the wrong place before.
2021-12-13 19:17:05 +03:00
Anton Bachin
3da5e2354d Move site prefix handling to a middleware 2021-12-13 19:11:54 +03:00
Anton Bachin
2529b9adda Set secrets using a middleware 2021-12-13 18:59:42 +03:00
Anton Bachin
d81b1986b6 Delete per-server "global" variables as a concept 2021-12-13 17:51:48 +03:00
Anton Bachin
bb2924de0b Assign request ids lazily and implicitly 2021-12-13 17:45:43 +03:00
Anton Bachin
e106e6ec37 Fix .gitignore and commit dream-pure.opam 2021-12-13 14:54:16 +03:00
Anton Bachin
655be1f754 Begin delimiting dream-pure with an .mli file 2021-12-13 14:48:57 +03:00
Anton Bachin
3f50f75a01 Move dream-pure to its own opam package 2021-12-12 13:47:16 +03:00
Anton Bachin
2f40d67224 dream.pure should not depend on dream.cipher 2021-12-12 12:12:52 +03:00
Anton Bachin
ed1c949226 Add Dream.with_client_stream
Primarily useful for the client, so it should be moved to dream-core in
the future. Will also be useful for stream-transforming middlewares.
2021-12-11 23:40:21 +03:00
Anton Bachin
ce6c0084a0 Streams: expose Dream.client_stream and fix tests 2021-12-11 22:04:53 +03:00
Anton Bachin
ff6f1d2457 Rename phantom types to client/server
The names incoming/outgoing are no longer clear when they are also used
on the client. Another possibility would be to define

  type Hyper.outgoing = Dream.incoming
  type Hyper.incoming = Dream.outgoing

...but this would probably be quite frustrating when switching between
Dream and Hyper, reading error messages, etc. It's better to have
consistent naming.
2021-12-11 21:51:59 +03:00
Anton Bachin
1e74850608 Move the client to its own repository 2021-12-11 19:26:05 +03:00
Anton Bachin
f69b95644a Streams: split into client and server streams 2021-12-11 17:13:46 +03:00
Anton Bachin
4afbe19046 Streams: tweak writer continuation order, labels 2021-12-11 16:20:43 +03:00
Anton Bachin
faf81b4c2a Streams: don't buffer even one write 2021-12-11 16:09:45 +03:00
Anton Bachin
1e1e7b3958 Streams: separate read and write ends 2021-12-11 15:09:05 +03:00
Anton Bachin
38bdb60971 Client: sketch WebSocket client 2021-12-09 12:17:32 +03:00
Anton Bachin
457258e64c Client: sketch redirect loop 2021-12-09 08:26:18 +03:00
Anton Bachin
b178eda5c7 Client: sketch HTTP pipelining and multiplexing 2021-12-09 00:13:40 +03:00
Anton Bachin
e95f6be28c Client: bare-bones HTTP/2 support
There is no request multiplexing, and the code is generally very dirty.
Saving clarification for a separate refactoring step, after all that
needs to be in the client is sketched out.
2021-12-08 19:47:51 +03:00
Anton Bachin
c9ad93b7c9 Client: primitive HTTPS support
Currently not doing certificate validation. Also not shutting the
connection down very cleanly, as this is best figured out after the I/O
rework is finished (for which an approximate client is needed).
2021-12-08 17:44:33 +03:00
Anton Bachin
c98d11063c Client: proof-of-concept connection pooling 2021-12-06 21:36:29 +03:00
Anton Bachin
560ea7d999 Initial commit of a Dream client library
This is just the lowest-level, rough API, to begin exercising the new
streams API that is supposed to work on both client and server, and to
find out how to best simplify and expose it.
2021-12-05 19:48:43 +03:00
Romain Calascibetta
d94b4a2bf1 Update example about MirageOS 2021-11-29 17:28:52 +01:00
Romain Calascibetta
9743279d41 Update the MirageOS codebase 2021-11-29 17:28:48 +01:00
Romain Calascibetta
54c4600cb0 Update gluten & tls 2021-11-29 13:45:58 +01:00
Anton Bachin
bf710df1bc WebSocket: a bit of logging and internal docs 2021-11-29 12:26:25 +03:00
Anton Bachin
f1cec7222f WebSocket: better close handshake handling 2021-11-29 12:04:17 +03:00
Anton Bachin
873c048429 WebSocket: expose ping/pong payloads
It's not possible to send them at the moment, due to

  https://github.com/anmonteiro/websocketaf/issues/36

However, this change should be made now to future-proof the Dream API.
2021-11-29 11:00:50 +03:00
Anton Bachin
d21ca95501 WebSocket: read close codes 2021-11-29 09:39:02 +03:00
Anton Bachin
0613640568 WebSocket: drain all payloads 2021-11-29 09:14:50 +03:00
Anton Bachin
639d59dad1 WebSocket: tweak binary flag 2021-11-29 08:54:40 +03:00
Anton Bachin
b5c0e77450 Streams: document design decision about FIN bit 2021-11-28 22:03:31 +03:00
Anton Bachin
c7e37548da dream.ml: remove obsolete internal module 2021-11-27 20:35:46 +03:00
Anton Bachin
08fd6d0f64 Primitive WebSocket send backpressure
Fixes #27.
2021-11-27 19:48:53 +03:00
Anton Bachin
587d55b921 Primitive HTTP write backpressure
Part of #27.
2021-11-27 19:30:39 +03:00
Anton Bachin
a339ef917d WebSockets: restore and expose close code sending
Close codes still can't be received due to limitations of the
websocket/af API.
2021-11-27 17:33:28 +03:00
Anton Bachin
ec56e226f9 Restore WebSocket message kind handling 2021-11-27 17:00:39 +03:00
Anton Bachin
4e66f78a29 WebSockets: restore FIN handling 2021-11-27 16:39:52 +03:00
Anton Bachin
018b459658 Introduce Stream.write type abbreviation 2021-11-27 16:24:34 +03:00
Anton Bachin
1f0ef73845 Stream convenience readers: auto-reply to ping 2021-11-27 16:00:37 +03:00
Anton Bachin
fd0ba1fa59 Reorder stream.ml
In particular, the convenience readers need to be last, so that they can
respond to ping with pong automatically.
2021-11-27 15:56:37 +03:00
Anton Bachin
706810a95d WebSocket: pull style; expose ping, pong, flush 2021-11-27 15:53:07 +03:00
Anton Bachin
4813c07914 Implement WebSockets as streams 2021-11-27 15:17:22 +03:00
Anton Bachin
40bc994680 Streams: support FIN, ping, and pong 2021-11-26 00:09:08 +03:00
Anton Bachin
586f93bfc6 Stream: initial internal docs 2021-11-25 20:52:52 +03:00
Anton Bachin
9a426fa5e5 Test interactions between stream writers and close 2021-11-25 20:25:45 +03:00
Anton Bachin
bde5fc8285 Fail on writes to read-only streams 2021-11-25 20:17:55 +03:00
Anton Bachin
abeba7b4b8 Streams: clarify writer callbacks 2021-11-25 20:00:39 +03:00
Anton Bachin
2b57a463c6 Don't pass exceptions through streams for now 2021-11-25 19:15:27 +03:00
Anton Bachin
6ab46c3226 Stream.close shouldn't evaluate to a promise 2021-11-25 16:46:15 +03:00
Anton Bachin
df4f4b6300 Equip read-only streams with a close callback 2021-11-25 15:25:14 +03:00
Anton Bachin
6ece622f97 Stream: rename reader functions 2021-11-25 15:15:42 +03:00
Anton Bachin
f58b8b5cda Begin testing streams 2021-11-24 22:15:11 +03:00
Anton Bachin
4f5f3c4dcf Ability to run separate expect test suites 2021-11-24 22:02:24 +03:00
Anton Bachin
2075347172 Replace Body by simpler, clearer Stream module 2021-11-24 17:12:15 +03:00
Calascibetta Romain
5578b901ff
Mirage: fix make depends command on DreamOS (#175) 2021-11-15 16:44:24 +03:00
Joe Thomas
b4402449f1
Add additional instrumentation for flash messages (#173)
Resolves #90.
2021-11-11 21:31:26 +03:00
Michael Bacarella
8efb1adaff
Mirage: fix up and explain gcloud commands (#172) 2021-11-10 00:50:47 +03:00
Anton Bachin
f056d0b34d Simplify drop_cookie 2021-11-09 17:56:51 +03:00
Anton Bachin
3ae5855c0b CI: pin Reason
Needed until https://github.com/reasonml/reason/pull/2660 is released.
2021-11-09 17:17:17 +03:00
Anton Bachin
972d3a9ec0 CI: don't install deps of dream-mirage 2021-11-09 17:07:18 +03:00
Anton Bachin
264febe50c Upgrade h2 2021-11-09 16:35:36 +03:00
Anton Bachin
c1ca22d266 Upgrade http/af and websocket/af forks 2021-11-09 16:29:04 +03:00
Anton Bachin
0d7b042214 Upgrade gluten 2021-11-09 15:02:01 +03:00
Shawn McGinty
237acbbbe1
Add drop_cookie (#169) 2021-11-08 15:01:28 +03:00
Joe Thomas
440fa71d5b
Allow log levels to be configured per-source (#171) 2021-11-08 14:44:12 +03:00
Anton Bachin
b11f9f83b0 CI: simplify matrix and add 4.13 2021-11-08 11:50:54 +03:00
Anton Bachin
6225e2d4ab Get Formats coverage to 100%
Ptime.to_date_time does not return leap seconds.
2021-11-01 18:51:14 +03:00
Anton Bachin
f584c1a348 Add .vscode to .gitignore 2021-10-30 12:01:35 +03:00
José Eduardo
d54b466b4a
Add csrf option to Dream.form and Dream.multipart (#167) 2021-10-17 03:45:05 +03:00
Dennis Dang
250d973bfc
Add z-deploy-fly example (#161) 2021-10-17 03:30:27 +03:00
Anton Bachin
876933e174 CONTRIBUTING.md: a couple notes 2021-10-06 14:01:49 +03:00
Anton Bachin
431cf8c7a4 Pass Dream.error object to error templates
Resolves #162.
2021-09-28 16:09:24 +03:00
Anton Bachin
469db38d33 Fix docs build after Mirage commits 2021-09-28 16:06:24 +03:00
Anton Bachin
a1985d9ae8 Propagate recent commit to example/w-esy/README.md
See #160.
2021-09-28 13:37:09 +03:00
Anton Bachin
34bd2868b7 Propagate preceding commit to all examples
Resolves #160.
2021-09-28 13:06:20 +03:00
Peter Mondlock
923d0f4816
Set the resolutions for Apple M1 build, remove ocamlfind-secondary (#163) 2021-09-28 12:52:46 +03:00
Calascibetta Romain
52d4da207f
Be able to launch locally a DreamOS (Mirage) with TLS (#157) 2021-09-23 04:46:45 +03:00
Manas
fa3cf53492
Address missing SIGPIPE for Windows (#158) 2021-08-30 17:46:31 +03:00
Anton Bachin
ecf98bd4ed Re-send signals to get default behavior 2021-08-12 14:41:15 +03:00
Anton Bachin
31be59c4c5 Tweak formatting in http.ml 2021-08-12 12:44:43 +03:00
Anton
2714e1ce9b
Ensure that restore_terminal is called on SIGINT (#151)
Part of #93.
2021-08-10 11:12:45 +03:00
Anton Bachin
279802f9d0 Update Makefile and CONTRIBUTING.md
...to avoid requiring Mirage deps.
2021-08-10 10:57:47 +03:00
Anton
120fc9f6ec
eml: add command-line argument for generating Reason (#150) 2021-08-05 07:04:39 +03:00
Anton
22e936f7c0
Examples: show control flow in templates (#152)
Include if/match statement and for loop. Use different syntax styles to
illustrate the range of possibilities.

Resolves #87.
Resolves #153.
2021-08-04 10:39:59 +03:00
Calascibetta Romain
ae3b5d24d3
Upgrade mirage (#146) 2021-08-01 09:20:27 +03:00
Anton Bachin
2d2083702c Tweak formatting 2021-07-29 12:12:34 +03:00
Anton Bachin
ead188384b Standardize indentation in docker-compose.yml 2021-07-29 11:44:14 +03:00
Anton Bachin
47718666e4 Clarify the nginx example
- Simplify nginx.conf, taking advantage of defaults.
- Do not expose the app server directly by default.
- Replace OCaml logo by completely unencumbered image.
- Use a directory for assets, since users will want to add more than one
  file.
- Some more hyperlinks.
2021-07-29 11:39:04 +03:00
Anton Bachin
3e3ce68893 Review CONTRIBUTING.md 2021-07-29 09:52:55 +03:00
Anton Bachin
8a0759b3a2 Add links to README
Part of #138.
2021-07-29 09:45:05 +03:00
Anton
995c3e08e5
Add info about creating local Dream dependency from external dir (#141) 2021-07-24 15:33:09 +03:00
Joe Thomas
b8befbb8bb
Add an example showing how to use nginx as a reverse proxy (#140) 2021-07-22 18:19:43 +03:00
Calascibetta Romain
1fb90c83c2
DreamOS [initial Mirage support] (#119) 2021-07-21 20:48:51 +03:00
Anton Bachin
62d7cd4832 dream.mli: unify with row-subtypes
Resolves #131.
2021-07-21 20:24:16 +03:00
Anton Bachin
669d2f6997 Update for OCamlFormat 0.19.0 2021-07-20 19:29:09 +03:00
Anton Bachin
b162944fa1 Adjust whitespace and variables 2021-07-20 18:28:10 +03:00
Joe Thomas
47f4ed5056
Tidy up flash message cookies (#137)
Fixes #134.
2021-07-20 18:26:34 +03:00
Anton Bachin
b046bca1b8 Test on 4.09, 4.10, 4.11
Resolves #121.
2021-07-19 08:19:20 +03:00
Anton Bachin
3dc2ac01c1 s/Dream.catch/Dream.catch_errors
To leave the short name for potential future use in something less
obscure than an optional built-in middleware.
2021-07-18 21:12:46 +03:00
Anton Bachin
8e1fe6a170 Dream.chop_site_prefix: pass prefix throguh app 2021-07-18 21:05:41 +03:00
Anton Bachin
9913ad2cf8 Dream.catch: pass error handler through app config 2021-07-18 20:55:28 +03:00
Anton Bachin
afc9cbfc5e Comment on the race condition safety of sql_pool 2021-07-18 20:22:02 +03:00
Anton Bachin
5f6b7f5081 Flash messages: finish example, docs
Resolves #43.
2021-07-18 17:20:59 +03:00
Anton Bachin
e78c8dc8fd s/get_flash/flash 2021-07-18 10:13:20 +03:00
Anton Bachin
4f38c24659 Format flash message code 2021-07-18 10:11:53 +03:00
Anton Bachin
bf0bda92d0 Rename flash-related files 2021-07-18 09:53:18 +03:00
Anton Bachin
6ec88be579 Tweak SQL examples 2021-07-18 04:59:52 +03:00
Anton Bachin
a44493dc82 Update example/w-postgres 2021-07-18 04:53:35 +03:00
Anton Bachin
a22d7f7a0c example/w-postgres: set Postgres password 2021-07-18 04:23:42 +03:00
Anton Bachin
dd4160da72 example/w-postgres: convert to esy and debian-slim 2021-07-18 04:08:36 +03:00
Anton Bachin
277eeff5c8 Postgres example: mv app.eml.ml postgres.eml.ml 2021-07-18 03:36:14 +03:00
Anton Bachin
41789365da example/z-docker-esy: bump Docker Compose version 2021-07-18 03:35:34 +03:00
Anton Bachin
ce2646247d Playground: s/Change View/Expand editor
Part of #105.
2021-07-17 04:48:54 +03:00
Anton Bachin
3a33705829 mv example/w-docker-postgres example/w-postgres 2021-07-17 04:39:11 +03:00
Anton Bachin
a169c107b0 Add ocamlformat test case
Part of #94.
2021-07-17 04:19:37 +03:00
Anton Bachin
32bbf56de8 README: simplify Community projects section 2021-07-16 22:31:43 +03:00
Anton Bachin
3d566d2ba7 Playground: fix log height 2021-07-16 22:27:05 +03:00
Anton Bachin
f14c38a46d Dream.redirect: update docs 2021-07-16 09:32:33 +03:00
Anton Bachin
b0f64df675 Dream.redirect: don't write location to body 2021-07-16 09:26:08 +03:00
Anton Bachin
ee08358bec GHA: try setup-ocaml@v2 for caching
Part of #132.
2021-07-16 08:59:44 +03:00
Khoa Nguyen
0818d2fdd8
Limit Dream.redirect ?status to redirections (#130) 2021-07-15 06:12:41 +03:00
Khoa Nguyen
48cc4d4484
Playground: refactoring CSS (#128) 2021-07-13 07:17:26 +03:00
Khoa Nguyen
a8b2e5aa72
Prevent Codemirror to grow (#127)
When there're too many lines, the editor would grow to fit the whole content.
The usual fix would be defining a maximum height on parent container of `.CodeMirror` 
and `position: relative`.

Since parent container is this case (`#textarea`) grow with its container (`#editor`), 
maximum height can't be set without resorting to manual `calc` .

This PR implement a hacks documented here: https://discuss.codemirror.net/t/size-inside-flexbox/1359/5

You can test this by making the editor has more lines than its parent container.
For example: http://dream.as/k-websocket
2021-07-10 20:11:04 +03:00
Khoa Nguyen
1a865b9dd7
Playground: goodbye float, flexbox all the way (#126) 2021-07-10 19:32:30 +03:00
artileda
027f7b4c64
Playground style improvement (#124)
Co-authored-by: Elsa Purwani <47468136+ywnn@users.noreply.github.com>
2021-07-10 17:39:15 +03:00
Calascibetta Romain
8612f6a661
Fix the compilation of Dream on OCaml 4.11 (#117) 2021-07-08 22:15:59 +03:00
Thibaut Mattio
a43a591b3f
Add community projects list to README (#58) 2021-07-08 08:03:13 +03:00
Calascibetta Romain
80d6c09756
Move the TTY initializer into the main dream module (#116) 2021-07-07 22:47:48 +03:00
Calascibetta Romain
5d5c6826ba
Make dream.middleware, dream.cipher MirageOS-compatible (#115) 2021-07-07 18:17:37 +03:00
Khoa Nguyen
f01aca54ff ocamlformat: improve match...with formatting
See https://github.com/aantron/dream/issues/94#issuecomment-875272231.
2021-07-07 14:23:28 +03:00
Khoa Nguyen
af2421cec1 Get started with an .ocamlformat
Resolves #94.
2021-07-07 06:32:54 +03:00
Anton Bachin
1b2384b461 Whitespace and nits after recent commits 2021-07-07 05:19:23 +03:00
Anton Bachin
c5ffe90631 Logger: flush stderr
...or nothing is shown. Follow-on to #108. cc @dinosaure
2021-07-07 05:11:51 +03:00
Calascibetta Romain
c06394c2c3
dream.pure is MirageOS compatible (#114)
Dream__pure: replace Lwt_bytes by Bigstringaf
2021-07-07 04:46:58 +03:00
Joe Thomas
cac2db79bd
Add an example with PostgreSQL and Docker Compose. (#112)
Resolves #99.
2021-07-06 20:27:37 +03:00
Hannes Mehnert
581ecaac1b
Log: avoid Lwt.async (#113)
Now that the reporter does not use Lwt anymore, remove the Lwt.async call.
2021-07-06 19:55:46 +03:00
Calascibetta Romain
dd2b8dcdf4
Use bigstringaf instead of Lwt_bytes to remove unix dependencies (#107) 2021-07-05 23:55:28 +03:00
Khoa Nguyen
8b3300792c
Playground CSS improvements (#109)
This PR addresses #105 in attempt to make the playground looks nicer.
Things done:
- Vertically aligned headers and items inside it
- Change Run button color + add border radius
2021-07-05 22:43:14 +03:00
Calascibetta Romain
cc172c5813
MirageOS: use prerr_string instead of Lwt_io (#108) 2021-07-05 21:15:53 +03:00
Ulrik Strid
7e4dae59fd
Fix sandbox issue on jsoo example (#103)
Allow creating folders in root of project by setting `buildsInSource` to `unsafe`
2021-07-05 15:24:20 +03:00
Calascibetta Romain
cc19ad564f
Avoid Unix.gettimeofday, for MirageOS compatibility (#102) 2021-07-05 15:21:29 +03:00
Anton Bachin
65738dfbf1 Tweak docs 2021-07-04 10:19:11 +03:00
Calascibetta Romain
5862115ad2
Use ptime instead of Unix to compute the date (MirageOS support) (#100) 2021-07-03 23:52:15 +03:00
Anton
b8a46f4649
Add warning about common sqlite scheme mistake (#92) 2021-07-02 21:42:35 +03:00
Anton Bachin
809835dcfe Static: don't set Content-Type on error responses
Fixes #88.
2021-07-02 12:58:43 +03:00
Anton Bachin
cd8464e642 dune: avoid scanning node_modules in all examples
Fixes #85.
2021-07-02 12:05:41 +03:00
Anton Bachin
795f824490 Tweak and hyperlink example/w-template-files
Part of #68.
See https://github.com/aantron/dream/issues/55#issuecomment-830753551.
2021-07-02 07:41:05 +03:00
Anton Bachin
65e104d9ec README: restore contact info.
This reverts commit b359934259f33f5473e2f88e1ab9f2de1f0807c6 with some
updates.
2021-07-01 18:58:29 +03:00
Khoa Nguyen
500f4d0d37
Remove double slashes from sqlite3 example (#80)
Without it, it throws `Sqlite URI cannot contain user or host components`
2021-06-29 10:23:50 +03:00
Anton Bachin
de3310a8f8 example/w-chat: README, playground, link 2021-06-28 09:20:42 +03:00
Anton Bachin
8233243689 Simplify example/w-chat 2021-06-28 08:42:21 +03:00
Anton Bachin
970e964fe5 mv z-websocket-chat w-chat 2021-06-28 08:13:33 +03:00
Thomas Coopman
9f6ae7573c
Create chat example (#77) 2021-06-25 07:57:20 +03:00
Anton Bachin
e325d9920c Add form_tag ?method_ and ?csrf_token
Resolves #74.
2021-06-19 19:28:37 +03:00
Anton Bachin
093cd38eb1 Add form_tag ?target
Resolves #73.
2021-06-19 08:13:01 +03:00
Anton Bachin
d67ed02073 Require Caqti 1.6.0, with latest security patches
Resolves #44.
2021-06-16 07:10:03 +03:00
Anton Bachin
62e4add848 Drop exclusion of ppxlib 0.21.0, 0.22.0
...because 0.21.1 and 0.22.1 are now available.

Resolves #56.
2021-06-15 21:52:06 +03:00
Anton Bachin
481e293fd7 ReScript example: s/server side/native/
Fixes #70.
2021-06-15 18:27:44 +03:00
Ryan Moore
5a5046496a
Add template files example (#68)
This example shows the user how to put templates in their own source
files as well as how to adjust the dune file to ensure the templates
are run the template preprocessor.
2021-06-13 15:46:53 +03:00
Kate
034a712d58 Constrain digestif (< 0.7.2 has no default implementation)
See https://github.com/ocaml/opam-repository/pull/18833.
2021-06-11 18:36:52 +03:00
Anton Bachin
7715e62248 Docs: adjust indentation in all templates 2021-06-09 10:55:01 +03:00
Anton Bachin
347d615bd6 Don't propagate misspelling of "referer" 2021-06-09 10:54:47 +03:00
Anton Bachin
2eddc7b3b5 Add example/w-content-security-policy
Resolves #48.
Resolves #49.
2021-06-09 10:25:12 +03:00
Joe Thomas
bbf9822f3f
Add support for flash messages (#62) 2021-06-07 08:26:27 +03:00
Anton Bachin
0d22bea1cd Document session expiration auto-refresh 2021-05-31 15:48:32 +03:00
Anton Bachin
2dcc6c0f4c OCaml-LSP+esy: examples must be opened as root
Found by @dangdennis during #65.
2021-05-31 15:14:12 +03:00
Anton Bachin
06167cd539 Add VSCode devDependencies to all esy.json files
Follow-on to 6f472aafc4b166d261d3295043e8f45653e7197e. See #65.

Co-authored-by: Dennis Dang <dangggdennis@gmail.com>
2021-05-31 07:28:54 +03:00
Anton Bachin
328c7575b9 chmod a+x example/quickstart.sh
Spotted by @dangdennis during #65.
2021-05-31 07:16:32 +03:00
Dennis Dang
6f472aafc4
Add esy dependencies to enable VSCode intellisense (#65) 2021-05-31 07:10:30 +03:00
Anton Bachin
cc691bd37a Router tests: test IRIs 2021-05-29 13:14:57 +03:00
Anton Bachin
88b37398a1 docs.css: adjust external link symbol 2021-05-26 08:27:58 +03:00
Anton Bachin
fa20aebf36 README: temporarily force Dream version in install
This is due to opam having the tendency to hold back package dream due
to the conflict with the broken ppxlib.

See #56.
2021-05-25 14:57:34 +03:00
Anton Bachin
b79b06dd6a Tweak scripts 2021-05-18 06:16:07 +03:00
Anton Bachin
9f06ce54a2 Point examples to release version 2021-05-18 05:53:49 +03:00
Anton Bachin
21f3ed5d2c Playground: improve mobile-friendliness 2021-05-18 05:12:30 +03:00
Kate
f08a2fa37d dream.opam: add constraints
See https://github.com/ocaml/opam-repository/pull/18687.
2021-05-17 15:57:26 +03:00
Anton Bachin
b3c1fd97b8 Playground: tweak whitespace in client.eml.html 2021-05-17 07:16:20 +03:00
483 changed files with 19195 additions and 6833 deletions

View File

@ -1,9 +1,9 @@
name: docker-esy name: docker-esy
on: on: workflow_call
push: # push:
paths: # paths:
- 'example/z-docker-esy/**' # - 'example/z-docker-esy/**'
- .github/workflows/docker-esy.yml # - .github/workflows/docker-esy.yml
jobs: jobs:
deploy: deploy:

View File

@ -1,9 +1,9 @@
name: docker-opam name: docker-opam
on: on: workflow_call
push: # push:
paths: # paths:
- 'example/z-docker-opam/**' # - 'example/z-docker-opam/**'
- .github/workflows/docker-opam.yml # - .github/workflows/docker-opam.yml
jobs: jobs:
deploy: deploy:

View File

@ -1,9 +1,9 @@
name: systemd name: systemd
on: on: workflow_call
push: # push:
paths: # paths:
- 'example/z-systemd/**' # - 'example/z-systemd/**'
- .github/workflows/systemd.yml # - .github/workflows/systemd.yml
jobs: jobs:
deploy: deploy:

View File

@ -7,40 +7,71 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- ubuntu-latest # Until https://github.com/ocaml/setup-ocaml/issues/872.
- macos-latest # When fixing, search for other instances of this string in this file.
# - windows-latest - ubuntu-22.04
# Blocked until we no longer require libev; Dream still works on
# Windows, but testing it is awkward at the moment.
ocaml: ocaml:
- 4.12.0 - 5.2.x
- 4.14.x
include: include:
- os: ubuntu-latest - os: macos-latest
ocaml: 4.08.1 ocaml: 4.14.x
- os: windows-latest
ocaml: 4.14.x
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- uses: avsm/setup-ocaml@v1 - uses: ocaml/setup-ocaml@v3
with: with:
ocaml-version: ${{matrix.ocaml}} ocaml-compiler: ${{matrix.ocaml}}
dune-cache: true
- run: opam depext --yes conf-libev # For Caqti PostgreSQL examples. opam does actually install PostgreSQL for
- run: opam install --yes --deps-only --with-test . # us. However, Homebrew doesn't link it by default, so we have to install
- run: opam exec -- dune runtest # and link it manually.
- run: | - run: brew install postgresql@15 && brew link --overwrite postgresql@15
if: runner.os == 'macOS'
# Workaround https://github.com/savonet/ocaml-ssl/issues/155 and/or
# https://github.com/ocaml/setup-ocaml/issues/856.
- run: opam pin add ssl 0.6.0 --no-action
if: runner.os == 'Windows'
- run: opam exec -- make deps
- run: opam exec -- make
# Tests on Windows are disabled because of a difference in ppx_expect
# output. See https://github.com/aantron/dream/pull/282. This difference
# remains as of ppx_expect 0.16.
- run: opam exec -- make test
if: runner.os != 'Windows'
- run: opam lint --recursive example
- name: Build examples
if: runner.os != 'Windows'
run: |
set -e set -e
set -x set -x
EXCLUDED_EXAMPLES='w-mirage*|r-tyxml|w-dream-html'
EXAMPLES=$(find example -maxdepth 1 -type d | grep -v "^example/0" | grep -v "^example$" | sort) EXAMPLES=$(find example -maxdepth 1 -type d | grep -Ev $EXCLUDED_EXAMPLES | grep -v "^example/0" | grep -v "^example$" | sort)
shopt -s nullglob shopt -s nullglob
for EXAMPLE in $EXAMPLES for EXAMPLE in $EXAMPLES
do do
FILE=$(ls $EXAMPLE/*.ml $EXAMPLE/*.re $EXAMPLE/server/*.ml $EXAMPLE/server/*.re) FILE=$(find $EXAMPLE -maxdepth 1 -type f -and -path "${EXAMPLE}/*.ml")
FILE+=$(find $EXAMPLE -maxdepth 1 -type f -and -path "${EXAMPLE}/*.re")
FILE+=$(find $EXAMPLE -maxdepth 2 -type f -and -path "${EXAMPLE}/server/*.ml")
FILE+=$(find $EXAMPLE -maxdepth 2 -type f -and -path "${EXAMPLE}/server/*.re")
if [[ "$FILE" == "" ]]; then
continue
fi
EXE=$(echo $FILE | sed 's/\..*$/.exe/g') EXE=$(echo $FILE | sed 's/\..*$/.exe/g')
echo dune build $EXE echo dune build $EXE
opam exec -- dune build $EXE opam exec -- dune build $EXE
@ -51,12 +82,23 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- ubuntu-latest - ubuntu-22.04
- macos-latest ocaml:
- 5.2.x
- 4.14.x
include:
- os: macos-latest
ocaml: 4.14.x
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- name: Quick start - uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{matrix.ocaml}}
dune-cache: true
- name: Run quickstart.sh
shell: bash
run: | run: |
set -x set -x
touch output touch output
@ -70,3 +112,33 @@ jobs:
else else
exit 1 exit 1
fi fi
mirage:
if: false
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- run: mkdir ../repo-copy
- run: cp -r * ../repo-copy/
- uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: 4.14.x
dune-cache: true
# Needed until https://github.com/robur-coop/ocaml-letsencrypt/pull/34.
- run: opam pin add letsencrypt git+https://github.com/hannesm/ocaml-letsencrypt.git#no-cstruct --no-action
- run: opam install --yes --deps-only ./dream-pure.opam ./dream-httpaf.opam ./dream.opam ./dream-mirage.opam
- run: opam install --yes mirage mirage-clock-unix mirage-crypto-rng-mirage
- run: cd example/w-mirage && mv config.ml config.ml.backup
- run: cd example/w-mirage && sed -e 's/package "dream-mirage"//' < config.ml.backup > config.ml
- run: cd example/w-mirage && opam exec -- mirage configure -t unix
- run: cd example/w-mirage && opam exec -- make depends
- run: cd example/w-mirage && ls duniverse
- run: cp -r ../repo-copy example/w-mirage/duniverse/dream
- run: cd example/w-mirage/duniverse && rm -rf ocaml-cstruct logs ke fmt lwt bytes seq mirage-flow sexplib0 ptime tls domain-name ocaml-ipaddr mirage-clock ocplib-endian digestif eqaf mirage-crypto mirage-runtime
- run: cd example/w-mirage && mv config.ml.backup config.ml
- run: cd example/w-mirage && sed -e 's/(libraries/(libraries dream-mirage/' < dune.build > dune.build.2
- run: cd example/w-mirage && mv dune.build.2 dune.build
- run: cd example/w-mirage && opam exec -- dune build
- run: file example/w-mirage/_build/default/main.exe

7
.gitignore vendored
View File

@ -15,10 +15,15 @@ _esy/
esy.lock esy.lock
# Release script # Release script
dream-* dream-*.gz
dream-*/
# Bisect_ppx # Bisect_ppx
_coverage/ _coverage/
# Humans # Humans
scratch/ scratch/
# Editors
.vscode/
*.swp

12
.gitmodules vendored
View File

@ -1,12 +0,0 @@
[submodule "src/vendor/httpaf"]
path = src/vendor/httpaf
url = https://github.com/aantron/httpaf.git
[submodule "src/vendor/gluten"]
path = src/vendor/gluten
url = https://github.com/aantron/gluten.git
[submodule "src/vendor/websocketaf"]
path = src/vendor/websocketaf
url = https://github.com/aantron/websocketaf.git
[submodule "src/vendor/h2"]
path = src/vendor/h2
url = https://github.com/aantron/ocaml-h2.git

16
.ocamlformat Normal file
View File

@ -0,0 +1,16 @@
version = 0.25.1
profile = conventional
leading-nested-match-parens = false
space-around-variants = false
space-around-arrays = false
space-around-lists = false
space-around-records = false
break-infix = fit-or-vertical
break-separators = after
break-cases = fit-or-vertical
cases-exp-indent = 2
exp-grouping = preserve
if-then-else = fit-or-vertical
let-and = sparse
type-decl = sparse

View File

@ -1,4 +1,4 @@
Copyright (c) 2021, Anton Bachin Copyright (c) 2021-2024, Anton Bachin
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,31 +1,41 @@
PACKAGES := dream-pure,dream-httpaf,dream
.PHONY : build .PHONY : build
build : build :
@dune build --no-print-directory @install @dune build --only-packages $(PACKAGES) --no-print-directory @install
.PHONY : watch .PHONY : watch
watch : watch :
@dune build --no-print-directory -w @dune build --only-packages $(PACKAGES) --no-print-directory @install -w
.PHONY : deps
deps :
opam install --deps-only --with-test --with-doc \
./dream-pure.opam ./dream-httpaf.opam ./dream.opam
TEST ?= test
ROOT := $(shell [ -f ../dune-workspace ] && echo .. || echo .)
.PHONY : test .PHONY : test
test : test :
@find . -name '*.coverage' | xargs rm -f @find $(ROOT) -name '*.coverage' | xargs rm -f
@dune build --no-print-directory \ @dune build --no-print-directory \
--instrument-with bisect_ppx --force @test/runtest --instrument-with bisect_ppx --force @$(TEST)/runtest
@bisect-ppx-report html @bisect-ppx-report html
@bisect-ppx-report summary @bisect-ppx-report summary
@echo See _coverage/index.html @echo See _coverage/index.html
.PHONY : test-watch .PHONY : test-watch
test-watch : test-watch :
@dune build --no-print-directory -w --root . @test/runtest @dune build --no-print-directory -w @$(TEST)/runtest
.PHONY : coverage-serve .PHONY : coverage-serve
coverage-serve : coverage-serve :
cd _coverage && dune exec -- serve -p 8082 cd _coverage && dune exec -- dream-serve -p 8082
.PHONY : promote .PHONY : promote
promote : promote :
dune promote --root . dune promote
@make --no-print-directory test @make --no-print-directory test
.PHONY : docs .PHONY : docs
@ -66,7 +76,17 @@ clean : clean-coverage
dune clean dune clean
dune clean --root . dune clean --root .
make --no-print-directory -C docs/web clean make --no-print-directory -C docs/web clean
rm -rf src/graphiql/node_modules dream-* _release rm -rf src/graphiql/node_modules
.PHONY : test-ocamlformat
test-ocamlformat :
touch test/ocamlformat/test.expect.ml
ocamlformat test/ocamlformat/test.ml > test/ocamlformat/test.actual.ml
diff -u3 test/ocamlformat/test.expect.ml test/ocamlformat/test.actual.ml
.PHONY : test-ocamlformat-promote
test-ocamlformat-promote :
ocamlformat test/ocamlformat/test.ml > test/ocamlformat/test.expect.ml
.PHONY : utop .PHONY : utop
utop : utop :
@ -82,21 +102,25 @@ todo-all :
VERSION := $(shell git describe --abbrev=0) VERSION := $(shell git describe --abbrev=0)
RELEASE := dream-$(VERSION) RELEASE := dream-$(VERSION)
FILES := src dream.opam dune-project LICENSE.md README.md FILES := \
src dream.opam dream-httpaf.opam dream-pure.opam dream-mirage.opam \
dune-project LICENSE.md README.md
.PHONY : release .PHONY : release
release : clean release : clean
rm -rf $(RELEASE) $(RELEASE).tar $(RELEASE).tar.gz _release rm -rf $(RELEASE) $(RELEASE).tar $(RELEASE).tar.gz _release
mkdir $(RELEASE) mkdir -p $(RELEASE)
cp -r $(FILES) $(RELEASE) cp -r $(FILES) $(RELEASE)
rm -rf $(RELEASE)/src/vendor/gluten/.github rm -rf $(RELEASE)/src/vendor/gluten/.github
rm -rf $(RELEASE)/src/vendor/gluten/async rm -rf $(RELEASE)/src/vendor/gluten/async
rm -rf $(RELEASE)/src/vendor/gluten/eio
rm -rf $(RELEASE)/src/vendor/gluten/mirage rm -rf $(RELEASE)/src/vendor/gluten/mirage
rm -rf $(RELEASE)/src/vendor/gluten/nix rm -rf $(RELEASE)/src/vendor/gluten/nix
rm -rf $(RELEASE)/src/vendor/httpaf/.github rm -rf $(RELEASE)/src/vendor/httpaf/.github
rm -rf $(RELEASE)/src/vendor/httpaf/async rm -rf $(RELEASE)/src/vendor/httpaf/async
rm -rf $(RELEASE)/src/vendor/httpaf/benchmarks rm -rf $(RELEASE)/src/vendor/httpaf/benchmarks
rm -rf $(RELEASE)/src/vendor/httpaf/certificates rm -rf $(RELEASE)/src/vendor/httpaf/certificates
rm -rf $(RELEASE)/src/vendor/httpaf/eio
rm -rf $(RELEASE)/src/vendor/httpaf/examples rm -rf $(RELEASE)/src/vendor/httpaf/examples
rm -rf $(RELEASE)/src/vendor/httpaf/images rm -rf $(RELEASE)/src/vendor/httpaf/images
rm -rf $(RELEASE)/src/vendor/httpaf/lib_test rm -rf $(RELEASE)/src/vendor/httpaf/lib_test
@ -105,6 +129,7 @@ release : clean
rm -rf $(RELEASE)/src/vendor/h2/.github rm -rf $(RELEASE)/src/vendor/h2/.github
rm -rf $(RELEASE)/src/vendor/h2/async rm -rf $(RELEASE)/src/vendor/h2/async
rm -rf $(RELEASE)/src/vendor/h2/certificates rm -rf $(RELEASE)/src/vendor/h2/certificates
rm -rf $(RELEASE)/src/vendor/h2/eio
rm -rf $(RELEASE)/src/vendor/h2/examples rm -rf $(RELEASE)/src/vendor/h2/examples
rm -rf $(RELEASE)/src/vendor/h2/lib_test rm -rf $(RELEASE)/src/vendor/h2/lib_test
rm -rf $(RELEASE)/src/vendor/h2/mirage rm -rf $(RELEASE)/src/vendor/h2/mirage
@ -113,20 +138,34 @@ release : clean
rm -rf $(RELEASE)/src/vendor/h2/vegeta-plot.png rm -rf $(RELEASE)/src/vendor/h2/vegeta-plot.png
rm -rf $(RELEASE)/src/vendor/websocketaf/.github rm -rf $(RELEASE)/src/vendor/websocketaf/.github
rm -rf $(RELEASE)/src/vendor/websocketaf/async rm -rf $(RELEASE)/src/vendor/websocketaf/async
rm -rf $(RELEASE)/src/vendor/websocketaf/eio
rm -rf $(RELEASE)/src/vendor/websocketaf/examples rm -rf $(RELEASE)/src/vendor/websocketaf/examples
rm -rf $(RELEASE)/src/vendor/websocketaf/lib_test rm -rf $(RELEASE)/src/vendor/websocketaf/lib_test
rm -rf $(RELEASE)/src/vendor/websocketaf/mirage rm -rf $(RELEASE)/src/vendor/websocketaf/mirage
rm -rf $(RELEASE)/src/vendor/websocketaf/nix rm -rf $(RELEASE)/src/vendor/websocketaf/nix
rm -rf $(RELEASE)/src/vendor/paf
tar cf $(RELEASE).tar $(RELEASE) tar cf $(RELEASE).tar $(RELEASE)
ls -l $(RELEASE).tar ls -l $(RELEASE).tar
gzip -9 $(RELEASE).tar gzip -9 $(RELEASE).tar
mkdir -p _release mkdir -p _release
cp $(RELEASE).tar.gz _release cp $(RELEASE).tar.gz _release
(cd _release && tar xf $(RELEASE).tar.gz) (cd _release && tar xf $(RELEASE).tar.gz)
opam pin add -y --no-action dream _release/$(RELEASE) --kind=path opam remove -y dream-pure dream-httpaf dream gluten httpaf h2 websocketaf paf
opam pin remove -y dream-pure dream-httpaf dream
opam pin add -y --no-action dream-pure.dev _release/$(RELEASE) --kind=path
opam pin add -y --no-action dream-httpaf.dev _release/$(RELEASE) --kind=path
opam pin add -y --no-action dream.dev _release/$(RELEASE) --kind=path
opam reinstall -y --verbose dream opam reinstall -y --verbose dream
@echo Run make release-finish to complete after killing the server
cd example/1-hello && dune exec --root . ./hello.exe || true cd example/1-hello && dune exec --root . ./hello.exe || true
opam remove -y dream
opam pin remove -y dream .PHONY : release-finish
md5sum $(RELEASE).tar.gz release-finish :
opam remove -y dream-pure dream-httpaf dream
opam pin remove -y dream-pure dream-httpaf dream
sha256sum $(RELEASE).tar.gz
ls -l $(RELEASE).tar.gz ls -l $(RELEASE).tar.gz
.PHONY : release-clean
release-clean :
rm -rf $(RELEASE) $(RELEASE).tar.gz _release

147
README.md
View File

@ -12,7 +12,6 @@ Easy-to-use, feature-complete Web framework without boilerplate.
<p align="center"> <p align="center">
<a href="#quick-start">Quick Start</a> | <a href="#quick-start">Quick Start</a> |
<a href="http://dream.as">Playground</a> |
<a href="https://github.com/aantron/dream/tree/master/example#readme"> <a href="https://github.com/aantron/dream/tree/master/example#readme">
Tutorial</a> | Tutorial</a> |
<a href="https://aantron.github.io/dream/">Reference</a> <a href="https://aantron.github.io/dream/">Reference</a>
@ -47,8 +46,8 @@ Dream is **one flat module** in **one package**, documented on
- [**Cryptography**][crypto] helpers, key rotation, and a chosen cipher. - [**Cryptography**][crypto] helpers, key rotation, and a chosen cipher.
- A neat [**logger**][logging], and attention to configuring the OCaml runtime - A neat [**logger**][logging], and attention to configuring the OCaml runtime
nicely. nicely.
- [**Deployment**][deploy] instructions for **Digital Ocean** and **Heroku**, - [**Deployment**][deploy] instructions for **Digital Ocean**, **Heroku**, and
with sample CI scripts. **Fly.io**, with sample CI scripts.
<br> <br>
@ -78,24 +77,24 @@ Dream binary][one-binary], or use Dream in a subcommand. Dream tries to be as
functional as possible, touching global runtime state only lazily, when called functional as possible, touching global runtime state only lazily, when called
into. into.
[https]: https://github.com/aantron/dream/tree/master/example/l-https#files [https]: https://github.com/aantron/dream/tree/master/example/l-https#folders-and-files
[websocket]: https://github.com/aantron/dream/tree/master/example/k-websocket#files [websocket]: https://github.com/aantron/dream/tree/master/example/k-websocket#folders-and-files
[graphql]: https://github.com/aantron/dream/tree/master/example/w-graphql-subscription#files [graphql]: https://github.com/aantron/dream/tree/master/example/w-graphql-subscription#folders-and-files
[templates]: https://github.com/aantron/dream/tree/master/example/7-template#files [templates]: https://github.com/aantron/dream/tree/master/example/7-template#folders-and-files
[reason-templates]: https://github.com/aantron/dream/tree/master/example/r-template#files [reason-templates]: https://github.com/aantron/dream/tree/master/example/r-template#folders-and-files
[middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#files [middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files
[handler]: https://aantron.github.io/dream/#type-handler [handler]: https://aantron.github.io/dream/#type-handler
[routing]: https://github.com/aantron/dream/tree/master/example/3-router#files [routing]: https://github.com/aantron/dream/tree/master/example/3-router#folders-and-files
[cookies]: https://aantron.github.io/dream/#cookies [cookies]: https://aantron.github.io/dream/#cookies
[forms]: https://aantron.github.io/dream/#forms [forms]: https://aantron.github.io/dream/#forms
[sessions]: https://github.com/aantron/dream/tree/master/example/b-session#files [sessions]: https://github.com/aantron/dream/tree/master/example/b-session#folders-and-files
[back-ends]: https://aantron.github.io/dream/#back-ends [back-ends]: https://aantron.github.io/dream/#back-ends
[errors]: https://github.com/aantron/dream/tree/master/example/9-error#files [errors]: https://github.com/aantron/dream/tree/master/example/9-error#folders-and-files
[crypto]: https://aantron.github.io/dream/#cryptography [crypto]: https://aantron.github.io/dream/#cryptography
[logging]: https://github.com/aantron/dream/tree/master/example/2-middleware#files [logging]: https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files
[melange]: https://github.com/aantron/dream/tree/master/example/r-fullstack-melange#files [melange]: https://github.com/aantron/dream/tree/master/example/r-fullstack-melange#folders-and-files
[rescript]: https://github.com/aantron/dream/tree/master/example/w-fullstack-rescript#files [rescript]: https://github.com/aantron/dream/tree/master/example/w-fullstack-rescript#folders-and-files
[jsoo]: https://github.com/aantron/dream/tree/master/example/w-fullstack-jsoo#files [jsoo]: https://github.com/aantron/dream/tree/master/example/w-fullstack-jsoo#folders-and-files
[types]: https://aantron.github.io/dream/#types [types]: https://aantron.github.io/dream/#types
[basic-read]: https://aantron.github.io/dream/#val-body [basic-read]: https://aantron.github.io/dream/#val-body
[streaming]: https://aantron.github.io/dream/#streaming [streaming]: https://aantron.github.io/dream/#streaming
@ -103,62 +102,55 @@ into.
[alpn]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation [alpn]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
[libs]: https://github.com/aantron/dream/tree/master/src [libs]: https://github.com/aantron/dream/tree/master/src
[deploy]: https://github.com/aantron/dream/tree/master/example#deploying [deploy]: https://github.com/aantron/dream/tree/master/example#deploying
[jsx]: https://github.com/aantron/dream/tree/master/example/r-tyxml#files [jsx]: https://github.com/aantron/dream/tree/master/example/r-tyxml#folders-and-files
[one-binary]: https://github.com/aantron/dream/tree/master/example/w-one-binary#files [one-binary]: https://github.com/aantron/dream/tree/master/example/w-one-binary#folders-and-files
<br> <br>
## Quick start ## Quick start
<br> You can get
[one](https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files)
of the first [tutorials][tutorial] and build it locally with:
<pre><b>bash -c "$(curl -fsSL https://raw.githubusercontent.com/aantron/dream/master/example/quickstart.sh)"</b></pre> <pre><b>bash -c "$(curl -fsSL https://raw.githubusercontent.com/aantron/dream/master/example/quickstart.sh)"</b></pre>
<br>
This downloads and runs [`quickstart.sh`][quickstart.sh], which does a
sandboxed build of one of the first [tutorials][tutorial],
[**`2-middleware`**][2-middleware]. It's mostly the same as:
```
git clone https://github.com/aantron/dream.git --recursive
cd dream/example/2-middleware
npm install esy && npx esy
npx esy start
```
Knowing that, you can start from any other [example][tutorial]. All of them
include their own build commands. They don't have to be subdirectories of
`dream` &mdash; you can copy them out to start your own project directory.
Especially consider starting with the [full-stack examples][fullstack], which
build both a Dream server and a JavaScript client.
### opam ### opam
Create a project directory with an optional local switch:
```
mkdir project
cd project
opam switch create . 5.1.0
eval $(opam env)
```
Install Dream:
``` ```
opam install dream opam install dream
``` ```
After that, go to one of the examples, such as [**`1-hello`**][1-hello], and After that, go to any of the [examples][tutorial], such as
build it: [**`2-middleware`**][2-middleware], re-create the files locally, and run it:
``` ```
cd example/1-hello dune exec ./middleware.exe
dune exec --root . ./hello.exe
``` ```
### Playground [esy-example]: https://github.com/aantron/dream/tree/master/example/w-esy#folders-and-files
Most of the examples are loaded into the [playground][playground]. For instance,
[**`2-middleware`**][2-middleware] is at
[http://dream.as/2-middleware][2-middleware-playground].
[esy-example]: https://github.com/aantron/dream/tree/master/example/w-esy#files
[quickstart.sh]: https://github.com/aantron/dream/blob/master/example/quickstart.sh [quickstart.sh]: https://github.com/aantron/dream/blob/master/example/quickstart.sh
[esy]: https://esy.sh/ [esy]: https://esy.sh/
[2-middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#files [2-middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files
[playground]: http://dream.as
[2-middleware-playground]: http://dream.as/2-middleware ## esy
Visit any of the [examples][tutorial], such as
[**`2-middleware`**][2-middleware], and re-create the files locally. The file
[`esy.json`](https://github.com/aantron/dream/blob/master/example/2-middleware/esy.json)
shows how to depend on Dream. All of the examples are installed by running `npx
esy`, and started with `npx esy start`.
<br> <br>
@ -177,18 +169,59 @@ Most of the examples are loaded into the [playground][playground]. For instance,
small-to-medium deployments. small-to-medium deployments.
- [**Examples**][examples] &mdash; These cover various HTTP scenarios. - [**Examples**][examples] &mdash; These cover various HTTP scenarios.
- [**API reference**][api-main] - [**API reference**][api-main]
- [Watching][fswatch] and [live reloading][reload]. - [Watching][watch] and [live reloading][reload].
[tutorial]: https://github.com/aantron/dream/tree/master/example#readme [tutorial]: https://github.com/aantron/dream/tree/master/example#readme
[examples]: https://github.com/aantron/dream/tree/master/example#examples [examples]: https://github.com/aantron/dream/tree/master/example#examples
[1-hello]: https://github.com/aantron/dream/tree/master/example/1-hello#files [1-hello]: https://github.com/aantron/dream/tree/master/example/1-hello#folders-and-files
[r-hello]: https://github.com/aantron/dream/tree/master/example/r-hello#files [r-hello]: https://github.com/aantron/dream/tree/master/example/r-hello#folders-and-files
[reason-examples]: https://github.com/aantron/dream/tree/master/example#reason [reason-examples]: https://github.com/aantron/dream/tree/master/example#reason
[deploying]: https://github.com/aantron/dream/tree/master/example#deploying [deploying]: https://github.com/aantron/dream/tree/master/example#deploying
[api-main]: https://aantron.github.io/dream/#types [api-main]: https://aantron.github.io/dream/#types
[fullstack]: https://github.com/aantron/dream/tree/master/example#full-stack [fullstack]: https://github.com/aantron/dream/tree/master/example#full-stack
[fswatch]: https://github.com/aantron/dream/tree/master/example/w-fswatch#files [watch]: https://github.com/aantron/dream/tree/master/example/w-watch#folders-and-files
[reload]: https://github.com/aantron/dream/tree/master/example/w-live-reload#files [reload]: https://github.com/aantron/dream/tree/master/example/w-live-reload#folders-and-files
<br>
## Recommended projects
- [`dream-cli`](https://github.com/tmattio/dream-cli) &nbsp;&mdash;&nbsp;
command-line interface for Dream applications.
- [`dream-encoding`](https://github.com/tmattio/dream-encoding) &nbsp;&mdash;
&nbsp; compression middleware.
- [`dream-livereload`](https://github.com/tmattio/dream-livereload)
&nbsp;&mdash;&nbsp; live reloading.
- [`emile`](https://github.com/dinosaure/emile) &nbsp;&mdash;&nbsp; email
address syntax validation.
- [`letters`](https://github.com/oxidizing/letters) &nbsp;&mdash;&nbsp; SMTP
client.
<br>
## Example repositories
- [`dream-mail-example`](https://github.com/jsthomas/dream-email-example)
&nbsp;&mdash;&nbsp; sends email using RabbitMQ and Mailgun
[[blog post](https://jsthomas.github.io/ocaml-email.html),
[discuss](https://discuss.ocaml.org/t/how-to-send-email-from-dream/8201)].
- [`dream-melange-tea-tailwind`](https://github.com/tcoopman/dream-melange-tea-tailwind)
&nbsp;&mdash;&nbsp; The Elm Architecture with a Dream server, client compiled
by Melange.
<br>
## Contact
Apart from the [issues](https://github.com/aantron/dream/issues), good places
to discuss Dream are...
- #dream on the [Reason Discord](https://discord.gg/2JTYRq2rYh).
- #webdev on the [OCaml Discord](https://discord.gg/sx45hPkkWV).
- The [OCaml Discuss forum](https://discuss.ocaml.org/).
- The development stream on [Twitch](https://www.twitch.tv/antron_ML).
Highlight `@antron` to poke @aantron specifically.
<br> <br>

View File

@ -5,9 +5,11 @@ Contributions are very welcome. This includes not only code PRs, but also:
- [Examples](https://github.com/aantron/dream/tree/master/example#readme) - [Examples](https://github.com/aantron/dream/tree/master/example#readme)
- [Docs fixes](https://aantron.github.io/dream/) - [Docs fixes](https://aantron.github.io/dream/)
- [Bug reports](https://github.com/aantron/dream/issues) - [Bug reports](https://github.com/aantron/dream/issues)
- Links to blogs &mdash; different people benefit from different presentations! - Links to [blogs](https://github.com/aantron/dream#example-repositories)
- Links to projects that use Dream &mdash; to serve as large examples. &mdash; different people benefit from different presentations!
- Links to libraries to use with Dream. - Links to projects that use Dream &mdash; to serve as large examples
- Links to [libraries](https://github.com/aantron/dream#recommended-projects)
to use with Dream
- And more! - And more!
<br> <br>
@ -17,13 +19,13 @@ Contributions are very welcome. This includes not only code PRs, but also:
To get the version of Dream installed in a project that uses it, run To get the version of Dream installed in a project that uses it, run
``` ```
npx esy ls-builds opam list dream
``` ```
or or
``` ```
opam list dream npx esy ls-builds
``` ```
<br> <br>
@ -38,35 +40,42 @@ cd dream
``` ```
Note: the clone *must* be `--recursive`, because Dream several dependencies Note: the clone *must* be `--recursive`, because Dream several dependencies
vendored as [submodules](https://github.com/aantron/dream/tree/master/src/vendor)! vendored as
[submodules](https://github.com/aantron/dream/tree/master/src/vendor).
Later, you'll need to fork the repository on GitHub, and add your fork as a Later, you'll need to fork the repository on GitHub, and add your fork as a
remote: remote:
``` ```
git remote add fork git@github.com/my-github-name/dream.git git remote add fork git@github.com:my-github-name/dream.git
``` ```
Install Dream's dependencies: Install Dream's dependencies:
``` ```
opam install --deps-only . --with-test make deps
``` ```
If you don't have an opam switch ready, first create one with If you don't have an opam switch ready, first create one with
``` ```
opam switch create . 4.12.0 opam switch create . 4.14.1 --no-install
``` ```
You can now add some code that will exercise your change, so you can test it as You can now add some code that will exercise your change, so you can test it as
you work. There are two main places for this: you work. There are two main places for this:
1. The tests in `test/`. They can be run with `make test`. View the generated 1. The tests in `test/`. They can be run with `make test`. View the generated
coverage report in `_coverage/index.html` to see how much the tests exercies coverage report in `_coverage/index.html` to see how much the tests exercise
your changes. your changes.
2. The examples in `example/`. I often test changes by modifying an example that To run tests from a single directory, for example `test/expect/pure`, run
`make test TEST=test/expect/pure`.
2. The tests can also be run in watch mode using `make test-watch`. This is not
compatible with coverage reports at the moment.
3. The examples in `example/`. I often test changes by modifying an example that
is almost on topic for the code I'm changing, and then not committing the is almost on topic for the code I'm changing, and then not committing the
example. In some cases, though, it's easiest to fork or write a new example example. In some cases, though, it's easiest to fork or write a new example
for some new code, and commit it. New examples greatly appreciated! To build for some new code, and commit it. New examples greatly appreciated! To build
@ -99,6 +108,37 @@ If you want to work again later, be sure to use `--recurse-submodules` during
git pull --recurse-submodules git pull --recurse-submodules
``` ```
**Note:** Please don't force-push into a PR &mdash; it makes incremental review
very difficult, and we will squash-merge most PRs anyway!
**Note:** Please don't resolve conversations in PRs. Reviewers use resolving
conversations to keep track of what has been addressed.
<br>
If you need to link to the local version of Dream from a project that lives in
a different directory, and you are using esy, add this line to your `esy.json`:
```json
{
...
"resolutions": {
...
"@opam/dream": "link:path/to/dream.opam"
},
}
```
Then, run
```
npx esy install
npx esy build
npx esy start
```
Don't forget the `esy build` step, which is necessary to build the local
dependency.
<br> <br>
## Docs ## Docs
@ -110,8 +150,8 @@ To build the docs, go to
make deps make deps
``` ```
This will install npm packages and opam packages (some of which are pinned to This will install npm and opam packages. In particular, the site currently
git commits). requires odoc 2.0.2, Soupault, and a specific version of Highlight.js.
After that, back in the project root, After that, back in the project root,
@ -126,3 +166,11 @@ make docs
``` ```
to build the docs locally. They are output to `docs/web/build/index.html`. to build the docs locally. They are output to `docs/web/build/index.html`.
You can also use
```
make docs-watch
```
to rebuild the docs automatically as you write them.

View File

@ -39,8 +39,8 @@ b {
<body> <body>
<pre><code><b>$ cd example/2-middleware</b> <pre><code><b>$ cd example/2-middleware</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b> <b>$ dune exec --root . ./middleware.exe</b>
<span class="dim">08.03.21 22:19:21.126</span> Running at http://localhost:8080 <span class="dim">08.03.21 22:19:21.126</span> Running at http://localhost:8080
<span class="dim">08.03.21 22:19:21.126</span> Type Ctrl+C to stop <span class="dim">08.03.21 22:19:21.126</span> Type Ctrl+C to stop
<span class="dim">08.03.21 22:19:24.927</span> dream.log <span class="info">INFO</span> <span class="odd">REQ 1</span> GET / 127.0.0.1:58549 Mozilla/5.0 ... <span class="dim">08.03.21 22:19:24.927</span> dream.log <span class="info">INFO</span> <span class="odd">REQ 1</span> GET / 127.0.0.1:58549 Mozilla/5.0 ...

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -69,7 +69,6 @@ pre {
<span class="apply">@@</span> <span class="module">Dream</span>.router <span class="punct">[</span> <span class="apply">@@</span> <span class="module">Dream</span>.router <span class="punct">[</span>
<span class="module">Dream</span>.get <span class="string">"/"</span> (<span class="keyword fun">fun</span> _ <span class="punct">-></span> <span class="module">Dream</span>.html (hello <span class="string">"world"</span>))<span class="punct">;</span> <span class="module">Dream</span>.get <span class="string">"/"</span> (<span class="keyword fun">fun</span> _ <span class="punct">-></span> <span class="module">Dream</span>.html (hello <span class="string">"world"</span>))<span class="punct">;</span>
<span class="punct">]</span> <span class="punct">]</span>
<span class="apply">@@</span> <span class="module">Dream</span>.not_found
</pre> </pre>
</body> </body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,9 +1,10 @@
ROOT := ../.. ROOT := ../..
ODOC := odoc/default/_doc/_html ODOC := odoc/default/_doc/_html
.PHONY : build .PHONY : build
build : build :
dune build @doc --root $(ROOT) --no-print-directory --build-dir `pwd`/odoc dune build @doc --root $(ROOT) --no-print-directory --build-dir `pwd`/odoc \
--only-packages dream-pure,dream-httpaf,dream
rm -f site/index.html rm -f site/index.html
dune exec -- postprocess/index.exe \ dune exec -- postprocess/index.exe \
$(ODOC)/dream/Dream/index.html site/index.html $(ODOC)/dream/Dream/index.html site/index.html

View File

@ -26,6 +26,6 @@ lockfile.
Useful links: Useful links:
- OCaml [*Syntax of documentation comments*](http://caml.inria.fr/pub/docs/manual-ocaml/ocamldoc.html#ss:ocamldoc-syntax) - OCaml [*Syntax of documentation comments*](https://v2.ocaml.org/manual/ocamldoc.html#ss:ocamldoc-syntax)
- Lambda Soup [*Module Soup*](https://aantron.github.io/lambdasoup/) - Lambda Soup [*Module Soup*](https://aantron.github.io/lambdasoup/)
- Soupault [*Tips and tricks*](https://soupault.app/tips-and-tricks/) - Soupault [*Tips and tricks*](https://soupault.app/tips-and-tricks/)

View File

@ -13,8 +13,35 @@ let if_expected expected test f =
f () f ()
else begin else begin
Soup.write_file "actual" actual; Soup.write_file "actual" actual;
Printf.ksprintf failwith "Mismatch; wrote %s" prerr_newline ();
(Filename.concat (Sys.getcwd ()) "actual") prerr_newline ();
prerr_endline "Mismatch with expected initial HTML content.";
prerr_newline ();
prerr_endline
"The Dream docs build rewrites HTML emitted by odoc to make it neater.";
prerr_endline
"Each rewritten tag has an expected initial content for sanity checking.";
prerr_endline "The actual found content has been written to";
prerr_newline ();
prerr_endline (" " ^ (Filename.concat (Sys.getcwd ()) "actual"));
prerr_newline ();
begin match String.split_on_char '\n' actual with
| [] -> ()
| first_line::_ ->
prerr_endline "Hint:";
prerr_newline ();
prerr_endline (" " ^ first_line);
prerr_newline ()
end;
prerr_endline "Hint: make sure odoc 2.0.2 is installed.";
prerr_endline
"Other versions of odoc generate markup that doesn't match the expected.";
prerr_newline ();
Printf.ksprintf failwith "Mismatch"
end end
let add_backing_lines soup = let add_backing_lines soup =

View File

@ -1,7 +1,7 @@
(executable (executable
(name index) (name index)
(modules index) (modules index)
(libraries common lambdasoup)) (libraries common lambdasoup str))
(library (library
(name common) (name common)

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,49 @@
src: url('tenor-sans-v12-latin-regular.woff2') format('woff2'); src: url('tenor-sans-v12-latin-regular.woff2') format('woff2');
} }
/* Theme */
/* Dark theme (default) */
:root, body:not([data-theme="light"]) {
--bg-color: #131618;
--text-color: #c9d1d9;
--code-bg-color: #2c333b;
--border-color: #282828;
--link-color: #8dc5ff;
--external-link-color: #5d7fcd;
--anchor-color: #bfcdea;
--of-color: #bec5cd;
--target-backing-color: #390022;
--hljs-keyword-color: #ff6c9b;
--hljs-identifier-color: #70df5c;
--hljs-tag-color: #c28eff;
--hljs-string-color: #e3db7a;
}
/* Light theme */
:root, body[data-theme="light"] {
--bg-color: #f5f7fa;
--text-color: #1f2937;
--code-bg-color: #eef1f6;
--header-bg-color: #f5f7fa;
--border-color: #e0e0e0;
--link-color: #1c7ed6;
--external-link-color: #1d4ed8;
--anchor-color: #888;
--of-color: #6b7280;
--target-backing-color: #f7f6f3;
--hljs-keyword-color: #d94879;
--hljs-identifier-color: #22863a;
--hljs-tag-color: #6f42c1;
--hljs-string-color: #b94e48;
}
body { body {
font-family: Lato, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue, Helvetica, Arial, sans-serif; font-family: Lato, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 16px; font-size: 16px;
@ -101,15 +144,15 @@ h6 {
/* Colors and presentation styles. */ /* Colors and presentation styles. */
body { body {
background-color: #131618; background-color: var(--bg-color);
color: #c9d1d9; color: var(--text-color);
} }
.odoc-content pre { .odoc-content pre {
background-color: #1a1f26; background-color: var(--code-bg-color);
margin-left: 1em; margin-left: 1em;
margin-right: 1em; margin-right: 1em;
border: 1px solid #111; border: 1px solid var(--border-color);
} }
.odoc-content .spec > pre { .odoc-content .spec > pre {
background: none; background: none;
@ -119,7 +162,7 @@ body {
.odoc-content code { .odoc-content code {
/* color: #ddd; */ /* color: #ddd; */
background-color: #2c333b; background-color: var(--code-bg-color);
padding: 0 5px; padding: 0 5px;
margin: 0 1px; margin: 0 1px;
white-space: nowrap; white-space: nowrap;
@ -150,17 +193,40 @@ body {
} */ } */
header { header {
background-color: #131618; background-color: var(--bg-color);
border-bottom: 1px solid #282828; border-bottom: 1px solid var(--border-color);
} }
header .topmost { header .topmost {
/* background-color: #0f131a; */ /* background-color: #0f131a; */
border-bottom: 1px solid #282828; border-bottom: 1px solid var(--border-color);
} }
h1 { .topmost .toolbar {
text-shadow: -2px 2px black; float: right;
}
.topmost .toggle-theme-btn {
all: unset;
position: relative;
}
.topmost .toggle-theme-btn::before {
content: "\F185"; /* sun */
position: absolute;
left: calc(0% - 16px + -8px);
top: calc(0% + 4px);
width: 16px;
height: 16px;
display: flex;
justify-content: center;
align-items: center;
font-family: FontAwesome, FontAwesomeBrands;
font-size: 15px;
}
body:not([data-theme="light"]) .topmost .toggle-theme-btn::before {
content: "\F186"; /* moon */
} }
header pre { header pre {
@ -191,7 +257,7 @@ footer {
} }
:target .backing { :target .backing {
background-color: #390022; background-color: var(--target-backing-color);
} }
nav ~ * a[href="#builtin"], nav ~ * a[href="#builtin"],
@ -205,18 +271,18 @@ nav ~ * a[href="#templates"] {
font-style: italic; font-style: italic;
} }
a[href*=example] { header a[href*=example], .spec-doc a[href*=example] {
font-weight: bold; font-weight: bold;
} }
a[href^=http]::after { header a[href^=http]::after, .spec-doc a[href^=http]::after {
content: "\f35d"; content: "\f35d";
font-family: FontAwesome; font-family: FontAwesome;
font-size: 10px; font-size: 10px;
line-height: 18px; line-height: 18px;
color: #5d7fcd; color: var(--external-link-color);
position: relative; position: relative;
top: -0.5px; top: -1px;
margin-left: 2px; margin-left: 2px;
margin-right: 3px; margin-right: 3px;
} }
@ -225,7 +291,7 @@ a[href^=http]::after {
} }
a, a:visited, a:active { a, a:visited, a:active {
color: #8dc5ff; color: var(--link-color);
text-decoration: none; text-decoration: none;
} }
@ -234,27 +300,27 @@ a:hover {
} }
.odoc-content a > code { .odoc-content a > code {
color: #8dc5ff; color: var(--link-color);
} }
.hljs-module-access, .hljs-keyword, .keyword { .hljs-module-access, .hljs-keyword, .keyword {
color: #ff6c9b; color: var(--hljs-keyword-color);
} }
.hljs-identifier, .hljs-literal, .hljs-type { .hljs-identifier, .hljs-literal, .hljs-type {
color: #70df5c; color: var(--hljs-identifier-color);
} }
.hljs-tag { .hljs-tag {
color: #c28eff; color: var(--hljs-tag-color);
} }
.hljs-string { .hljs-string {
color: #e3db7a; color: var(--hljs-string-color);
} }
.of { .of {
color: #bec5cd; color: var(--of-color);
} }
.topmost ul { .topmost ul {
@ -365,10 +431,9 @@ p + .odoc-spec {
} }
#type-bigstring + .spec-doc li + li, #type-bigstring + .spec-doc li + li,
#val-next + .spec-doc li + li, #val-next + .spec-doc li + li,
#val-origin_referer_check + .spec-doc li + li, #val-origin_referrer_check + .spec-doc li + li,
#val-form + .spec-doc li + li, #val-form + .spec-doc li + li,
#type-part + .spec-doc li + li, #type-part + .spec-doc li + li,
#type-upload_event + .spec-doc li + li,
#val-upload + .spec-doc li + li, #val-upload + .spec-doc li + li,
#val-static + .spec-doc li + li, #val-static + .spec-doc li + li,
#val-from_path + .spec-doc li + li { #val-from_path + .spec-doc li + li {
@ -407,7 +472,7 @@ ul ul li {
height: 100%; height: 100%;
width: 43rem; width: 43rem;
/* background-color: #262626; */ /* background-color: #262626; */
border-right: 1px solid #282828; border-right: 1px solid var(--border-color);
} }
h2, h2 ~ :not(.odoc-spec):not(nav), footer { h2, h2 ~ :not(.odoc-spec):not(nav), footer {
@ -462,8 +527,8 @@ ul ul li {
margin-bottom: 24px; margin-bottom: 24px;
} }
#type-outgoing + .spec-doc { #type-server + .spec-doc {
margin-top: -1.5rem; margin-top: -26px;
margin-bottom: 48px; margin-bottom: 48px;
} }
#val-patch + .spec-doc { #val-patch + .spec-doc {
@ -582,8 +647,8 @@ h2:first-of-type {
overflow-y: scroll; overflow-y: scroll;
scrollbar-width: none; scrollbar-width: none;
line-height: 30px; line-height: 30px;
border-right: 1px solid #262626; border-right: 1px solid var(--border-color);
background-color: #131618; background-color: var(--bg-color);
/* color: #ddd; */ /* color: #ddd; */
} }
.odoc-toc::-webkit-scrollbar { .odoc-toc::-webkit-scrollbar {
@ -674,7 +739,7 @@ h2 > .anchor, h3 > .anchor {
font-family: FontAwesome; font-family: FontAwesome;
font-size: 10px; font-size: 10px;
font-style: oblique; font-style: oblique;
color: #bfcdea; color: var(--anchor-color);
position: relative; position: relative;
top: -1.75px; top: -1.75px;
left: -4px; left: -4px;

View File

@ -4,8 +4,7 @@
// Copyright 2021 Anton Bachin *) // Copyright 2021 Anton Bachin *)
/* Scrolling */
console.log("foo");
function current_section() { function current_section() {
var threshold = window.innerHeight / 2; var threshold = window.innerHeight / 2;
@ -49,3 +48,38 @@ function scroll() {
}; };
window.onscroll = scroll; window.onscroll = scroll;
/* Theme mode */
var THEME_MODE_KEY = "dream-theme"
function apply_theme(theme) {
if (theme === "light") {
document.body.setAttribute("data-theme", "light");
} else {
document.body.removeAttribute("data-theme");
}
}
function toggle_theme() {
var current_theme = localStorage.getItem(THEME_MODE_KEY);
var new_theme = current_theme === "dark" ? "light" : "dark";
localStorage.setItem(THEME_MODE_KEY, new_theme);
apply_theme(new_theme);
}
function init_theme() {
var default_theme = "dark";
var stored_theme = localStorage.getItem(THEME_MODE_KEY) || default_theme;
apply_theme(stored_theme);
}
function prepare_button() {
var theme_toggle_button = document.querySelector(".toggle-theme-btn");
if (theme_toggle_button) {
theme_toggle_button.addEventListener("click", toggle_theme);
}
}
document.addEventListener("DOMContentLoaded", prepare_button);

View File

@ -24,6 +24,10 @@
</head> </head>
<body class="index"> <body class="index">
<script>
init_theme();
</script>
<header> <header>
<div class="topmost"> <div class="topmost">
<div class="titles"> <div class="titles">
@ -32,18 +36,22 @@
</div> </div>
<ul> <ul>
<li><code>1.0.0~alpha2</code></li> <li><code>1.0.0~alpha7</code></li>
<li><code>opam install dream</code></li> <li><code>opam install dream</code></li>
<li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream">GitHub</a></li> <li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream">GitHub</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/blob/master/src/dream.mli">Edit these docs</a></li> <li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/edit/master/src/dream.mli">Edit these docs</a></li>
</ul> </ul>
<div class="toolbar">
<button class="toggle-theme-btn">&nbsp;</button>
</div>
</div> </div>
<pre><span class="keyword">let</span> hello who = <pre><span class="keyword">let</span> hello who =
<span class="hljs-tag">&lt;html></span> <span class="hljs-tag">&lt;html></span>
<span class="hljs-tag">&lt;body></span> <span class="hljs-tag">&lt;body></span>
<span class="hljs-tag">&lt;h1></span><span class="hljs-string">Hello, </span><span class="hljs-keyword">&lt;%s</span> who <span class="hljs-keyword">%></span><span class="hljs-string">!</span><span class="hljs-tag">&lt;/h1></span> <span class="hljs-tag">&lt;h1></span><span class="hljs-string">Hello, </span><span class="hljs-keyword">&lt;%s</span> who <span class="hljs-keyword">%></span><span class="hljs-string">!</span><span class="hljs-tag">&lt;/h1></span>
<span class="hljs-tag">&lt;/body></span> <span class="hljs-tag">&lt;/body></span>
<span class="hljs-tag">&lt;/html></span> <span class="hljs-tag">&lt;/html></span>
<span class="keyword">let</span> <span class="hljs-string">()</span> = <span class="keyword">let</span> <span class="hljs-string">()</span> =
@ -52,8 +60,7 @@
@@ <span class="hljs-type">Dream</span>.router <span class="hljs-string">[</span> @@ <span class="hljs-type">Dream</span>.router <span class="hljs-string">[</span>
<span class="hljs-type">Dream</span>.get <span class="hljs-string">"/"</span> (<span class="keyword">fun</span> _ -> <span class="hljs-type">Dream</span>.get <span class="hljs-string">"/"</span> (<span class="keyword">fun</span> _ ->
<span class="hljs-type">Dream</span>.html (hello <span class="hljs-string">"world"</span>)); <span class="hljs-type">Dream</span>.html (hello <span class="hljs-string">"world"</span>));
<span class="hljs-string">]</span> <span class="hljs-string">]</span></pre>
@@ <span class="hljs-type">Dream</span>.not_found</pre>
<!-- Send TLS link to HTTPS example. --> <!-- Send TLS link to HTTPS example. -->
@ -116,18 +123,13 @@
<li> <li>
A <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#readme"> A <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#readme">
Tutorial</a> &mdash; get started at Tutorial</a> &mdash; get started at
<a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example/1-hello#files"> <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example/1-hello#folders-and-files">
<code>1-hello</code></a>! <code>1-hello</code></a>!
</li> </li>
<li> <li>
Many <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#reason"> Many <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#reason">
Examples</a>, covering all kinds of scenarios. Examples</a>, covering all kinds of scenarios.
</li> </li>
<li>
An online <a target="_blank" rel="noreferrer noopener" href="http://dream.as/">
<b>Playground</b></a>, where you can try Dream without installing
anything!
</li>
</ul> </ul>
</div> </div>
</header> </header>
@ -136,7 +138,7 @@
<div id="api"></div> <div id="api"></div>
<footer> <footer>
Copyright © 2021 Anton Bachin. Copyright © 2021-2024 Anton Bachin.
<br> <br>
Released under the MIT license. See Released under the MIT license. See
<a href="https://github.com/aantron/dream/blob/master/LICENSE.md"> <a href="https://github.com/aantron/dream/blob/master/LICENSE.md">

View File

@ -1,11 +1,9 @@
opam-version: "2.0" opam-version: "2.0"
synopsis: "Dream docs"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [ depends: [
"lambdasoup" "lambdasoup"
"odoc" "odoc" {= "2.0.2"}
"soupault" {>= "2.5.0"} "soupault" {>= "2.5.0"}
] ]
pin-depends: [
["odoc.2.0.0~master" "git+https://github.com/aantron/odoc.git#dbb37e20717985edfd8f734e00b9ab6f705d81a4"]
]

View File

@ -1,71 +1,78 @@
opam-version: "2.0" opam-version: "2.0"
depends: [ depends: [
"ISO8601" {= "0.2.6"}
"astring" {= "0.8.5"} "astring" {= "0.8.5"}
"base-bigarray" {= "base"} "base-bigarray" {= "base"}
"base-bytes" {= "base"} "base-bytes" {= "base"}
"base-threads" {= "base"} "base-threads" {= "base"}
"base-unix" {= "base"} "base-unix" {= "base"}
"base64" {= "3.5.0"} "base64" {= "3.5.1"}
"bigarray-compat" {= "1.0.0"} "bigarray-compat" {= "1.1.0"}
"cmdliner" {= "1.0.4"} "bos" {= "0.2.1"}
"conf-libev" {= "4-11"} "camlp-streams" {= "5.0.1"}
"containers" {= "3.3"} "camomile" {= "1.0.2"}
"cppo" {= "1.6.7"} "cmdliner" {= "1.1.1"}
"conf-libev" {= "4-12"}
"conf-pkg-config" {= "2"}
"containers" {= "3.11"}
"cppo" {= "1.6.9"}
"csexp" {= "1.5.1"} "csexp" {= "1.5.1"}
"cstruct" {= "6.0.0"} "cstruct" {= "6.1.1"}
"dune" {= "2.8.5"} "ctypes" {= "0.20.1"}
"dune-configurator" {= "2.8.5"} "digestif" {= "1.1.3"}
"ezjsonm" {= "1.2.0"} "dune" {= "3.7.0"}
"fileutils" {= "0.6.3"} "dune-configurator" {= "3.7.0"}
"fmt" {= "0.8.9"} "either" {= "1.0.0"}
"eqaf" {= "0.9"}
"ezjsonm" {= "1.3.0"}
"fileutils" {= "0.6.4"}
"fmt" {= "0.9.0"}
"fpath" {= "0.7.3"} "fpath" {= "0.7.3"}
"hex" {= "1.4.0"} "hex" {= "1.5.0"}
"jingoo" {= "1.4.3"} "integers" {= "0.7.0"}
"jsonm" {= "1.0.1"} "jingoo" {= "1.4.4"}
"lambdasoup" {= "0.7.2"} "jsonm" {= "1.0.2"}
"lambdasoup" {= "1.0.0"}
"logs" {= "0.7.0"} "logs" {= "0.7.0"}
"lua-ml" {= "0.9.2"} "lua-ml" {= "0.9.4"}
"lwt" {= "5.4.0"} "lwt" {= "5.6.1"}
"markup" {= "1.0.0-1"} "markup" {= "1.0.3"}
"menhir" {= "20210310"} "menhir" {= "20211128"}
"menhirLib" {= "20210310"} "menhirLib" {= "20211128"}
"menhirSdk" {= "20210310"} "menhirSdk" {= "20211128"}
"mmap" {= "1.1.0"} "ocaml" {= "4.14.1"}
"ocaml" {= "4.12.0"} "ocaml-base-compiler" {= "4.14.1"}
"ocaml-base-compiler" {= "4.12.0"} "ocaml-compiler-libs" {= "v0.12.4"}
"ocaml-compiler-libs" {= "v0.12.3"}
"ocaml-config" {= "2"} "ocaml-config" {= "2"}
"ocaml-migrate-parsetree" {= "2.1.0"} "ocaml-migrate-parsetree" {= "2.4.0"}
"ocaml-options-vanilla" {= "1"} "ocaml-options-vanilla" {= "1"}
"ocaml-syntax-shims" {= "1.0.0"} "ocamlbuild" {= "0.14.2"}
"ocamlbuild" {= "0.14.0"} "ocamlfind" {= "1.9.6"}
"ocamlfind" {= "1.9.1"} "ocplib-endian" {= "1.2"}
"ocplib-endian" {= "1.1"}
"odate" {= "0.6"} "odate" {= "0.6"}
"odoc" {= "2.0.0~master"} "odoc" {= "2.0.2"}
"odoc-parser" {= "1.0.1"}
"otoml" {= "1.0.4"}
"ppx_derivers" {= "1.2.1"} "ppx_derivers" {= "1.2.1"}
"ppx_deriving" {= "5.2.1"} "ppx_deriving" {= "5.2.1"}
"ppxlib" {= "0.22.0"} "ppxlib" {= "0.25.1"}
"re" {= "1.9.0"} "re" {= "1.10.4"}
"result" {= "1.5"} "result" {= "1.5"}
"rresult" {= "0.7.0"}
"seq" {= "base"} "seq" {= "base"}
"sexplib0" {= "v0.14.0"} "sexplib0" {= "v0.15.1"}
"soupault" {= "2.5.0"} "soupault" {= "4.4.0"}
"spelll" {= "0.3"} "spelll" {= "0.4"}
"stdlib-shims" {= "0.3.0"} "stdlib-shims" {= "0.3.0"}
"stringext" {= "1.6.0"} "topkg" {= "1.0.7"}
"toml" {= "7.0.0"} "tsort" {= "2.1.0"}
"topkg" {= "1.0.3"} "tyxml" {= "4.5.0"}
"tsort" {= "2.0.0"}
"tyxml" {= "4.4.0"}
"uchar" {= "0.0.2"} "uchar" {= "0.0.2"}
"uucp" {= "13.0.0"} "uucp" {= "15.0.0"}
"uutf" {= "1.0.2"} "uutf" {= "1.0.3"}
] "yaml" {= "3.1.0"}
pin-depends: [
["odoc.2.0.0~master" "git+https://github.com/aantron/odoc.git#dbb37e20717985edfd8f734e00b9ab6f705d81a4"]
] ]
name: "web" name: "web"
version: "dev" version: "~dev"
synopsis: "Dream docs"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

34
dream-httpaf.opam Normal file
View File

@ -0,0 +1,34 @@
opam-version: "2.0"
synopsis: "Internal: shared http/af stack for Dream (server) and Hyper (client)"
description: "This package does not have a stable API."
license: "MIT"
homepage: "https://github.com/aantron/dream"
doc: "https://aantron.github.io/dream"
bug-reports: "https://github.com/aantron/dream/issues"
dev-repo: "git+https://github.com/aantron/dream.git"
author: "Anton Bachin <antonbachin@yahoo.com>"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [
"dream-pure"
"dune" {>= "2.7.0"} # --instrument-with.
"gluten"
"gluten-lwt-unix"
"h2" {< "0.13.0"}
"h2-lwt-unix"
"httpun" {< "0.2.0"}
"httpun-lwt-unix"
"httpun-ws"
"lwt"
"lwt_ppx" {>= "1.2.2"}
"lwt_ssl"
"ocaml" {>= "4.08.0"}
"ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol.
]
build: [
["dune" "build" "-p" name "-j" jobs]
]

72
dream-mirage.opam Normal file
View File

@ -0,0 +1,72 @@
opam-version: "2.0"
synopsis: "Tidy, feature-complete Web framework"
tags: ["http" "web" "framework" "websocket" "graphql" "server" "http2" "tls"]
description: """
Dream is a feature-complete Web framework with a simple programming
model and no boilerplate. It provides only two data types, request and
response.
Almost everything else is either a built-in OCaml type, or an
abbreviation for a bare function. For example, a Web app, known in
Dream as a handler, is just an ordinary function from requests to
responses. And a middleware is then just a function from handlers to
handlers.
Within this model, Dream adds:
- Session management with pluggable back ends.
- A fully composable router.
- Support for HTTP/1.1, HTTP/2, and HTTPS.
- WebSockets.
- GraphQL, including subscriptions and a built-in GraphiQL editor.
- SQL connection pool helpers.
- Server-side HTML templates.
- Automatic secure handling of cookies and forms.
- Unified, internationalization-friendly error handling.
- A neat log, and OCaml runtime configuration.
- Helpers for Web formats, such as Base64url, and a modern cipher.
Because of the simple programming model, everything is optional and
composable. It is trivially possible to strip Dream down to just a
bare driver of the various HTTP protocols.
Dream is presented as a single module, whose API is documented on one
page. In addition, Dream comes with a large number of examples.
Security topics are introduced throughout, wherever they are
applicable."""
license: "MIT"
homepage: "https://github.com/aantron/dream"
doc: "https://aantron.github.io/dream"
bug-reports: "https://github.com/aantron/dream/issues"
dev-repo: "git+https://github.com/aantron/dream.git"
author: "Anton Bachin <antonbachin@yahoo.com>"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [
"bigarray-compat"
"bigstringaf"
"digestif" {>= "1.0.0"}
"dream"
"dream-httpaf"
"dream-pure"
"dune" {>= "2.7.0"}
"duration"
"emile" {>= "1.1"}
"ke" {>= "0.4"} # paf.
"letsencrypt" {>= "0.3.0"}
"lwt"
"lwt_ppx" {>= "1.2.2"}
"mimic" {>= "0.0.5"}
"mirage-time"
"rresult"
"tcpip"
"tls-mirage"
]
build: [
["dune" "build" "-p" name "-j" jobs]
]

35
dream-pure.opam Normal file
View File

@ -0,0 +1,35 @@
opam-version: "2.0"
synopsis: "Internal: shared HTTP types for Dream (server) and Hyper (client)"
description: "This package does not have a stable API."
license: "MIT"
homepage: "https://github.com/aantron/dream"
doc: "https://aantron.github.io/dream"
bug-reports: "https://github.com/aantron/dream/issues"
dev-repo: "git+https://github.com/aantron/dream.git"
author: "Anton Bachin <antonbachin@yahoo.com>"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [
"base64" {>= "3.1.0"} # Base64.encode_string.
"bigstringaf" {>= "0.5.0"} # Bigstringaf.to_string.
"dune" {>= "2.7.0"} # --instrument-with.
"hmap"
"lwt"
"lwt_ppx" {>= "1.2.2"}
"ocaml" {>= "4.08.0"}
"ptime" {>= "0.8.1"} # Ptime.weekday.
"uri" {>= "4.2.0"}
# Testing, development.
"alcotest" {with-test}
"bisect_ppx" {with-test & >= "2.5.0"} # --instrument-with.
"ppx_expect" {with-test}
"ppx_yojson_conv" {with-test}
]
build: [
["dune" "build" "-p" name "-j" jobs]
]

View File

@ -29,7 +29,7 @@ Within this model, Dream adds:
- Helpers for Web formats, such as Base64url, and a modern cipher. - Helpers for Web formats, such as Base64url, and a modern cipher.
Because of the simple programming model, everything is optional and Because of the simple programming model, everything is optional and
composable. It is trivailly possible to strip Dream down to just a composable. It is trivially possible to strip Dream down to just a
bare driver of the various HTTP protocols. bare driver of the various HTTP protocols.
Dream is presented as a single module, whose API is documented on one Dream is presented as a single module, whose API is documented on one
@ -48,65 +48,52 @@ maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [ depends: [
"base-unix" "base-unix"
"base64" {>= "3.1.0"} # Base64.encode_string.
"bigarray-compat" "bigarray-compat"
"caqti" {>= "1.4.0"} # ~post_connect. "camlp-streams"
"caqti-lwt" "caqti" {>= "2.0.0"}
"conf-libev" {os != "win32"} "caqti-lwt" {>= "2.0.0"}
("conf-libev" {os != "win32"} | "ocaml" {os = "win32"})
"cstruct" {>= "6.0.0"} "cstruct" {>= "6.0.0"}
"digestif" {>= "0.7"} # to_raw_string.
"dream-httpaf" {>= "1.0.0~alpha4"}
"dream-pure" {>= "1.0.0~alpha2"}
"dune" {>= "2.7.0"} # --instrument-with. "dune" {>= "2.7.0"} # --instrument-with.
"fmt" {>= "0.8.7"} # `Italic. "fmt" {>= "0.8.7"} # `Italic.
"graphql_parser" "graphql_parser"
"graphql-lwt" "graphql-lwt"
"hmap" "lambdasoup" {>= "0.6.1"}
"lwt" "lwt"
"lwt_ppx" "lwt_ppx" {>= "1.2.2"}
"lwt_ssl" "lwt_ssl"
"logs" {>= "0.5.0"} "logs" {>= "0.5.0"}
"magic-mime" "magic-mime"
"mirage-crypto" {>= "0.8.1"} # AES-256-GCM. "markup" {>= "1.0.2"}
"mirage-crypto-rng" {>= "0.8.0"} # Signature of initialize. "mirage-clock" {>= "3.0.0"} # now_d_ps : unit -> int * int64.
"multipart_form" {>= "0.3.0"} "mirage-crypto" {>= "1.0.0"}
"mirage-crypto-rng" {>= "1.0.0"}
"mirage-crypto-rng-lwt"
"multipart_form" {>= "0.4.0"}
"multipart_form-lwt"
"ocaml" {>= "4.08.0"} "ocaml" {>= "4.08.0"}
"ptime" {>= "0.8.1"} # Ptime.v.
"ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol.
"uri" {>= "4.2.0"} "uri" {>= "4.2.0"}
"yojson" # ... "yojson" # ...
# Currently vendored.
# "gluten"
# "gluten-lwt-unix"
# "httpaf"
# "httpaf-lwt-unix"
# "h2"
# "h2-lwt-unix"
# "hpack"
# "websocketaf"
# Dependencies of vendored packages.
"angstrom" {>= "0.14.0"}
"bigstringaf" {>= "0.4.0"}
"digestif" {>= "0.7"} # websocket/af, sha1.
"faraday" {>= "0.6.1"}
"faraday-lwt-unix"
"psq" # h2.
"result" # http/af, websocket/af.
# https://github.com/ocaml-ppx/ppxlib/issues/221.
# esy appears to ignore conflicts.
"ppxlib" {< "0.21.0" | > "0.22.0"}
# Testing, development. # Testing, development.
"alcotest" {with-test} "alcotest" {with-test}
# Commented out because of https://github.com/ocaml-ppx/ppxlib/issues/221. "bisect_ppx" {with-test & >= "2.5.0"} # --instrument-with.
# "bisect_ppx" {with-test & >= "2.5.0"} # --instrument-with. "caqti-driver-postgresql" {with-test}
"caqti-driver-sqlite3" {with-test} "caqti-driver-sqlite3" {with-test}
"crunch" {with-test} "crunch" {with-test}
"lambdasoup" {with-test} "html_of_jsx" {with-test}
"ppx_expect" {with-test} "js_of_ocaml" {with-test}
"js_of_ocaml-ppx" {with-test}
"ppx_expect" {with-test & >= "v0.15.0" & < "v0.17.0"} # Breaking changes.
"ppx_yojson_conv" {with-test} "ppx_yojson_conv" {with-test}
"reason" {with-test} "reason" {with-test}
"tyxml" {with-test & >= "4.5.0"} "tyxml" {with-test & >= "4.5.0"}
"tyxml-jsx" {with-test & >= "4.5.0"} "tyxml-jsx" {with-test}
"tyxml-ppx" {with-test & >= "4.5.0"}
] ]
build: [ build: [

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -12,26 +12,25 @@ let () =
<br> <br>
It's the absolute minimum Dream server. It responds to all requests with the It's the minimal Dream server. It responds to all requests with the same text.
same text. At startup, Dream prints a message to the log, telling you where to At startup, Dream prints a message to the log, telling you where to point your
point your browser. Your terminal probably makes the link clickable. browser. Your terminal probably makes the link clickable.
<pre><code><b>$ cd example/1-hello</b> <pre><code><b>$ cd example/1-hello</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b> <b>$ dune exec --root . ./hello.exe</b>
08.03.21 21:17:21.471 Running at http://localhost:8080 08.03.21 21:17:21.471 Running at http://localhost:8080
08.03.21 21:17:21.471 Type Ctrl+C to stop 08.03.21 21:17:21.471 Type Ctrl+C to stop
</code></pre> </code></pre>
If you go to [http://localhost:8080](http://localhost:8080), you will, of If you go to [http://localhost:8080](http://localhost:8080), you will, of
course, see `Good morning, world!`. You can also try it in the [Dream course, see `Good morning, world!`.
Playground](http://dream.as/1-hello).
<br> <br>
If you'd like to copy out the server binary, you can do it like this: If you'd like to copy out the server binary, you can do it like this:
<pre><code><b>$ npx esy cp '#{self.target_dir}/default/hello.exe' . <pre><code><b>$ cp _build/default/hello.exe .
</b></code></pre> </b></code></pre>
The name will change as you go through the tutorial examples. It's always the The name will change as you go through the tutorial examples. It's always the
@ -41,19 +40,17 @@ name of the `.ml` file, but with `.ml` changed to `.exe`.
**Next steps:** **Next steps:**
- The next example, [**`2-middleware`**](../2-middleware#files), adds a logger - The next example, [**`2-middleware`**](../2-middleware#folders-and-files), adds a logger
to the app. to the app.
- [**`3-router`**](../3-router#files) sends requests to different handlers, - [**`3-router`**](../3-router#folders-and-files) sends requests to different handlers,
depending on their path. depending on their path.
<br> <br>
**See also:** **See also:**
- [**`r-hello`**](../r-hello#files) is a Reason syntax version of this example. - [**`r-hello`**](../r-hello#folders-and-files) is a Reason syntax version of this example.
- [**`w-esy`**](../w-esy#files) gives more detail on the [esy](https://esy.sh/) - [**`w-watch`**](../w-watch#folders-and-files) sets up a development watcher.
packaging.
- [**`w-fswatch`**](../w-fswatch#files) sets up a primitive development watcher.
<br> <br>

View File

@ -1,5 +1,3 @@
(executable (executable
(name hello) (name hello)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./hello.exe"
}
}

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -4,7 +4,7 @@
*Middleware* is just functions that take handlers and wrap them, producing *Middleware* is just functions that take handlers and wrap them, producing
bigger handlers that do a little bit more. This example takes the handler from bigger handlers that do a little bit more. This example takes the handler from
[**`1-hello`**](../1-hello#files) and wraps it in one of the most useful [**`1-hello`**](../1-hello#folders-and-files) and wraps it in one of the most useful
middlewares, the [*logger*](https://aantron.github.io/dream/#val-logger): middlewares, the [*logger*](https://aantron.github.io/dream/#val-logger):
```ocaml ```ocaml
@ -19,7 +19,7 @@ let () =
However, as you can see, the more middlewares we stack on top of each other However, as you can see, the more middlewares we stack on top of each other
like this, the more parentheses and indentation we will end up with! To keep like this, the more parentheses and indentation we will end up with! To keep
the code tidy, we use `@@`, the the code tidy, we use `@@`, the
[standard OCaml operator](https://caml.inria.fr/pub/docs/manual-ocaml/libref/Stdlib.html#VAL(@@)) for calling functions without parentheses. So, the [actual [standard OCaml operator](https://v2.ocaml.org/api/Stdlib.html#VAL(@@)) for calling functions without parentheses. So, the [actual
code](https://github.com/aantron/dream/blob/master/example/2-middleware/middleware.ml) code](https://github.com/aantron/dream/blob/master/example/2-middleware/middleware.ml)
in this example looks like this: in this example looks like this:
@ -33,15 +33,14 @@ let () =
<br> <br>
When you run this server and visit When you run this server and visit
[http://localhost:8080](http://localhost:8080) [http://localhost:8080](http://localhost:8080), you get much more interesting
[[playground](http://dream.as/2-middleware)], you get much more interesting
(and colorful!) output: (and colorful!) output:
![Dream log example](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/log-sanitized.png) ![Dream log example](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/log-sanitized.png)
You can write your own messages to the log using You can write your own messages to the log using
[`Dream.log`](https://aantron.github.io/dream/#val-log). See example [`Dream.log`](https://aantron.github.io/dream/#val-log). See example
[**`a-log`**](../a-log#files) for more logging options. Now that we have the [**`a-log`**](../a-log#folders-and-files) for more logging options. Now that we have the
logger, we will use it in all other examples, even though it's not really logger, we will use it in all other examples, even though it's not really
necessary &mdash; it just makes it much easier to see what is going on. necessary &mdash; it just makes it much easier to see what is going on.
@ -49,14 +48,14 @@ necessary &mdash; it just makes it much easier to see what is going on.
There's not much else to middlewares &mdash; they are really just functions There's not much else to middlewares &mdash; they are really just functions
from handlers to handlers, so you can create them anywhere. Example from handlers to handlers, so you can create them anywhere. Example
[**`4-counter`**](../4-counter#files) already shows a simple custom middleware. [**`4-counter`**](../4-counter#folders-and-files) already shows a simple custom middleware.
<!-- <!--
There are also more complicated middlewares defined in There are also more complicated middlewares defined in
- [**`m-locals`**](../m-locals/#files), - [**`m-locals`**](../m-locals#folders-and-files),
- [**`w-auto-reload`**](../w-auto-reload/#files), and - [**`w-auto-reload`**](../w-auto-reload#folders-and-files), and
- [**`w-index-html`**](../w-index-html/#files). - [**`w-index-html`**](../w-index-html#folders-and-files).
--> -->
<!-- TODO Fill out this list; probably a-promise belongs here. --> <!-- TODO Fill out this list; probably a-promise belongs here. -->
@ -65,10 +64,10 @@ There are also more complicated middlewares defined in
**Next steps:** **Next steps:**
- The next example, [**`3-router`**](../3-router#files), shows - The next example, [**`3-router`**](../3-router#folders-and-files), shows
[*routes*](https://aantron.github.io/dream/#routing), the other way to build [*routes*](https://aantron.github.io/dream/#routing), the other way to build
up handlers in Dream. up handlers in Dream.
- [**`4-counter`**](../4-counter#files) builds the first custom middleware. - [**`4-counter`**](../4-counter#folders-and-files) builds the first custom middleware.
<br> <br>

View File

@ -1,5 +1,3 @@
(executable (executable
(name middleware) (name middleware)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./middleware.exe"
}
}

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -20,50 +20,42 @@ let () =
Dream.get "/echo/:word" Dream.get "/echo/:word"
(fun request -> (fun request ->
Dream.html (Dream.param "word" request)); Dream.html (Dream.param request "word"));
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/3-router</b> <pre><code><b>$ cd example/3-router</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./router.exe</b></code></pre>
<br> <br>
This is also our first dynamic site! A request to `/echo/foo` gets the response This is also our first dynamic site! A request to `/echo/foo` gets the response
`foo`, and a request to `/echo/bar` gets `bar`! Try it in the `foo`, and a request to `/echo/bar` gets `bar`!
[playground](http://dream.as/3-router/echo/foo) &mdash; once the server loads,
edit the URL in the right pane to visit `/echo/bar`.
The syntax `:word` in a route creates a path parameter, which can be read with The syntax `:word` in a route creates a path parameter, which can be read with
[`Dream.param`](https://aantron.github.io/dream/#val-param). [`Dream.param`](https://aantron.github.io/dream/#val-param).
<!-- TODO hyperlink Dream.param to docsc, also Dream.logger. --> <!-- TODO hyperlink Dream.param to docsc, also Dream.logger. -->
[The whole router is a middleware](https://aantron.github.io/dream/#val-router), When none of the routes match, the router returns a `404 Not Found` response.
just like [`Dream.logger`](https://aantron.github.io/dream/#val-logger). When
none of the routes match, the router passes the request to the next handler,
which is right beneath it. In this example, we just respond with `404 Not
Found` when that happens.
Except for the status code, the `404 Not Found` response is *completely* empty, Except for the status code, the `404 Not Found` response is *completely* empty,
so it might not display well in your browser. In example so it might not display well in your browser. In example
[**`9-error`**](../9-error#files), we will decorate all error responses with [**`9-error`**](../9-error#folders-and-files), we will decorate all error responses with
an error template in one central location. an error template in one central location.
<br> <br>
The router can do more than match simple routes: The router can do more than match simple routes:
- [**`f-static`**](../f-static#files) forwards all requests with a certain - [**`f-static`**](../f-static#folders-and-files) forwards all requests with a certain
prefix to a static file handler. prefix to a static file handler.
<!-- - [**`w-scope`**](../w-scope/#files) applies middlewares to groups of routes <!-- - [**`w-scope`**](../w-scope#folders-and-files) applies middlewares to groups of routes
&mdash; but only when they match. &mdash; but only when they match.
- [**`w-subsite`**](../w-subsite/#files) attaches a handler as a complete, - [**`w-subsite`**](../w-subsite#folders-and-files) attaches a handler as a complete,
nested sub-site, which might have its own router. --> nested sub-site, which might have its own router. -->
<!-- TODO --> <!-- TODO -->
@ -71,9 +63,9 @@ The router can do more than match simple routes:
**Next steps:** **Next steps:**
- [**`4-counter`**](../4-counter#files) counts requests, and exposes a route for - [**`4-counter`**](../4-counter#folders-and-files) counts requests, and exposes a route for
getting the count. getting the count.
- [**`5-promise`**](../5-promise#files) introduces - [**`5-promise`**](../5-promise#folders-and-files) introduces
[Lwt](https://github.com/ocsigen/lwt), the promise library used by Dream. [Lwt](https://github.com/ocsigen/lwt), the promise library used by Dream.
<br> <br>

View File

@ -1,5 +1,3 @@
(executable (executable
(name router) (name router)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./router.exe"
}
}

View File

@ -9,7 +9,6 @@ let () =
Dream.get "/echo/:word" Dream.get "/echo/:word"
(fun request -> (fun request ->
Dream.html (Dream.param "word" request)); Dream.html (Dream.param request "word"));
] ]
@@ Dream.not_found

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -4,8 +4,7 @@
This example shows how easy it is to define a custom middleware, This example shows how easy it is to define a custom middleware,
`count_requests`. It exposes the request count at `count_requests`. It exposes the request count at
[http://localhost:8080/](http://localhost:8080/) [http://localhost:8080/](http://localhost:8080/), in a sort of dashboard:
[[playground](http://dream.as/4-counter)], in a sort of dashboard:
```ocaml ```ocaml
let count = ref 0 let count = ref 0
@ -22,11 +21,10 @@ let () =
Dream.get "/" (fun _ -> Dream.get "/" (fun _ ->
Dream.html (Printf.sprintf "Saw %i request(s)!" !count)); Dream.html (Printf.sprintf "Saw %i request(s)!" !count));
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/4-counter</b> <pre><code><b>$ cd example/4-counter</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./counter.exe</b></code></pre>
<br> <br>
@ -39,24 +37,16 @@ which means they usually also
This example's middleware only does something *before* calling the This example's middleware only does something *before* calling the
`inner_handler`. To do something *after*, we will need to await the response `inner_handler`. To do something *after*, we will need to await the response
promise with [Lwt](https://github.com/ocsigen/lwt#readme), the promise library promise with [Lwt](https://github.com/ocsigen/lwt#readme), the promise library
used by Dream. The next example, [**`5-promise`**](../5-promise#files), does used by Dream. The next example, [**`5-promise`**](../5-promise#folders-and-files), does
exactly that! exactly that!
<!-- TODO
<br>
Advanced example [**`w-globals`**](../w-globals/#files) shows how to replace
global state like `count` by state scoped to the application. This is useful if
you are writing middleware to publish in a library. It's fine to use a global
`ref` in private code!
-->
<br> <br>
**Next steps:** **Next steps:**
- [**`5-promise`**](../5-promise#files) shows a middleware that awaits - [**`5-promise`**](../5-promise#folders-and-files) shows a middleware that awaits
responses using [Lwt](https://github.com/ocsigen/lwt). responses using [Lwt](https://github.com/ocsigen/lwt).
- [**`6-echo`**](../6-echo#files) responds to `POST` requests and reads their - [**`6-echo`**](../6-echo#folders-and-files) responds to `POST` requests and reads their
bodies. bodies.
<br> <br>

View File

@ -12,4 +12,3 @@ let () =
Dream.get "/" (fun _ -> Dream.get "/" (fun _ ->
Dream.html (Printf.sprintf "Saw %i request(s)!" !count)); Dream.html (Printf.sprintf "Saw %i request(s)!" !count));
] ]
@@ Dream.not_found

View File

@ -1,5 +1,3 @@
(executable (executable
(name counter) (name counter)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./counter.exe"
}
}

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -2,7 +2,7 @@
<br> <br>
[**`4-counter`**](../4-counter#files) was limited to counting requests *before* [**`4-counter`**](../4-counter#folders-and-files) was limited to counting requests *before*
passing them on to the rest of the app. With the promise library passing them on to the rest of the app. With the promise library
[Lwt](https://github.com/ocsigen/lwt), we can await responses, and do something [Lwt](https://github.com/ocsigen/lwt), we can await responses, and do something
*after*. In this example, we separately count requests that were handled *after*. In this example, we separately count requests that were handled
@ -38,14 +38,11 @@ let () =
!successful !failed)); !successful !failed));
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/5-promise</b> <pre><code><b>$ cd example/5-promise</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./promise.exe</b></code></pre>
Try it in the [playground](http://dream.as/5-promise).
<br> <br>
@ -94,8 +91,8 @@ We will stick to `let%lwt` in the examples and keep things tidy.
**Next steps:** **Next steps:**
- [**`6-echo`**](../6-echo#files) uses Dream and Lwt to read a request body. - [**`6-echo`**](../6-echo#folders-and-files) uses Dream and Lwt to read a request body.
- [**`7-template`**](../7-template#files) shows how to interleave HTML and - [**`7-template`**](../7-template#folders-and-files) shows how to interleave HTML and
OCaml. OCaml.
<br> <br>

View File

@ -2,5 +2,3 @@
(name promise) (name promise)
(libraries dream) (libraries dream)
(preprocess (pps lwt_ppx))) (preprocess (pps lwt_ppx)))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./promise.exe"
}
}

View File

@ -27,4 +27,3 @@ let () =
!successful !failed)); !successful !failed));
] ]
@@ Dream.not_found

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -18,14 +18,11 @@ let () =
body); body);
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/6-echo</b> <pre><code><b>$ cd example/6-echo</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./echo.exe</b></code></pre>
...or run it in the [playground](http://dream.as/6-echo).
<br> <br>
@ -49,11 +46,11 @@ foo
We usually want to do something more interesting with the request body than just We usually want to do something more interesting with the request body than just
echo it, and there are several examples for that! echo it, and there are several examples for that!
- [**`d-form`**](../d-form#files) parses request bodies as forms. - [**`d-form`**](../d-form#folders-and-files) parses request bodies as forms.
- [**`e-json`**](../e-json#files) parses bodies as JSON. - [**`e-json`**](../e-json#folders-and-files) parses bodies as JSON.
- [**`g-upload`**](../g-upload#files) receives file upload forms. - [**`g-upload`**](../g-upload#folders-and-files) receives file upload forms.
- [**`i-graphql`**](../i-graphql#files) receives GraphQL queries. - [**`i-graphql`**](../i-graphql#folders-and-files) receives GraphQL queries.
- [**`j-stream`**](../j-stream#files) streams huge bodies. - [**`j-stream`**](../j-stream#folders-and-files) streams huge bodies.
We delay these examples a bit, so we can squeeze in a couple security topics We delay these examples a bit, so we can squeeze in a couple security topics
first. These examples do take client input, after all! So, it's better to first. These examples do take client input, after all! So, it's better to
@ -65,9 +62,9 @@ present them the right way.
**Next steps:** **Next steps:**
- [**`7-template`**](../7-template#files) builds responses from templates and - [**`7-template`**](../7-template#folders-and-files) builds responses from templates and
guards against injection attacks (XSS). guards against injection attacks (XSS).
- [**`8-debug`**](../8-debug#files) renders error information in responses. - [**`8-debug`**](../8-debug#folders-and-files) renders error information in responses.
<br> <br>

View File

@ -2,5 +2,3 @@
(name echo) (name echo)
(libraries dream) (libraries dream)
(preprocess (pps lwt_ppx))) (preprocess (pps lwt_ppx)))
(data_only_dirs _esy esy.lock)

View File

@ -10,4 +10,3 @@ let () =
body); body);
] ]
@@ Dream.not_found

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./echo.exe"
}
}

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -5,15 +5,15 @@
Dream [*templates*](https://aantron.github.io/dream/#templates) allow Dream [*templates*](https://aantron.github.io/dream/#templates) allow
interleaving OCaml and HTML in a straightforward way, and help with interleaving OCaml and HTML in a straightforward way, and help with
[XSS protection](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). [XSS protection](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).
After looking at the correct example, we will After looking at a secure example, we will [weaken and then exploit
[weaken and then exploit it](#security). it](#security).
```ocaml ```ocaml
let render param = let render param =
<html> <html>
<body> <body>
<h1>The URL parameter was <%s param %>!</h1> <h1>The URL parameter was <%s param %>!</h1>
</body> </body>
</html> </html>
let () = let () =
@ -23,17 +23,16 @@ let () =
Dream.get "/:word" Dream.get "/:word"
(fun request -> (fun request ->
Dream.param "word" request Dream.param request "word"
|> render |> render
|> Dream.html); |> Dream.html);
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/7-template</b> <pre><code><b>$ cd example/7-template</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./template.exe</b></code></pre>
<br> <br>
@ -55,7 +54,7 @@ file to run the template preprocessor:
<br> <br>
The substitution, `<%s param %>`, uses The substitution, `<%s param %>`, uses
[`Printf` conversion specifications](https://caml.inria.fr/pub/docs/manual-ocaml/libref/Printf.html) [`Printf` conversion specifications](https://v2.ocaml.org/api/Printf.html)
from the standard library. So, you can do things like this: from the standard library. So, you can do things like this:
- `<%i my_int %>` to print an OCaml `int`. - `<%i my_int %>` to print an OCaml `int`.
@ -85,15 +84,11 @@ already escaped, or if it is safe for some other reason. But be careful!
To show the danger, let's launch a **script injection (XSS) attack** against To show the danger, let's launch a **script injection (XSS) attack** against
this tiny Web app! First, go to this tiny Web app! First, go to
[`template.eml.ml`](https://github.com/aantron/dream/blob/master/example/7-template/template.eml.ml#L4), [`template.eml.ml`](https://github.com/aantron/dream/blob/master/example/7-template/template.eml.ml#L4),
change the substitution to `<%s! param %>`, and restart the app. You can also change the substitution to `<%s! param %>`, and restart the app. Then, visit
make the edit in the [playground](http://dream.as/7-template/foo). Then,
visit
this highly questionable URL: this highly questionable URL:
[http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E](http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E) [http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E](http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E)
If you are using the playground, change the host and port accordingly.
This URL will cause our Web app to display an alert box, which we, as the This URL will cause our Web app to display an alert box, which we, as the
developers, did not intend! developers, did not intend!
@ -130,23 +125,31 @@ and not supported by Dream.
**Next steps:** **Next steps:**
- [**`8-debug`**](../8-debug#files) shows how to turn on debug responses, and - [**`8-debug`**](../8-debug#folders-and-files) shows how to turn on debug responses, and
get more info about errors. get more info about errors.
- [**`9-error`**](../9-error#files) sets up a central error template for all - [**`9-error`**](../9-error#folders-and-files) sets up a central error template for all
errors. errors.
- [**`r-template`**](../r-template#files) is a Reason syntax version of this - [**`r-template`**](../r-template#folders-and-files) is a Reason syntax version of this
example. example.
<br> <br>
**See also:** **See also:**
- [**`w-tyxml`**](../w-tyxml#files) shows how to use - [**`w-template-files`**](../w-template-files#folders-and-files) moves the template into a
separate `.eml.html` to avoid problems with editor support.
- [**`w-template-logic`**](../w-template-logic#folders-and-files) shows how to put control
flow into templates.
- [**`w-tyxml`**](../w-tyxml#folders-and-files) shows how to use
[TyXML](https://github.com/ocsigen/tyxml), a different templater that uses [TyXML](https://github.com/ocsigen/tyxml), a different templater that uses
OCaml's type system to prevent emitting many kinds of invalid HTML. OCaml's type system to prevent emitting many kinds of invalid HTML.
- [**`r-tyxml`**](../r-tyxml#files) if you are using Reason. You can use TyXML - [**`r-tyxml`**](../r-tyxml#folders-and-files) if you are using Reason. You can use TyXML
with JSX syntax server-side! with JSX syntax server-side!
- [**`w-template-stream`**](../w-template-stream#files) streams templates to - [**`w-dream-html`**](../w-dream-html#folders-and-files) shows how to use
[dream-html](https://github.com/yawaramin/dream-html), another alternative
library for generating HTML from OCaml, which is more closely integrated with
Dream.
- [**`w-template-stream`**](../w-template-stream#folders-and-files) streams templates to
responses, instead of building up complete response strings. responses, instead of building up complete response strings.
<br> <br>

View File

@ -6,5 +6,3 @@
(targets template.ml) (targets template.ml)
(deps template.eml.ml) (deps template.eml.ml)
(action (run dream_eml %{deps} --workspace %{workspace_root}))) (action (run dream_eml %{deps} --workspace %{workspace_root})))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./template.exe"
}
}

View File

@ -1,8 +1,8 @@
let render param = let render param =
<html> <html>
<body> <body>
<h1>The URL parameter was <%s param %>!</h1> <h1>The URL parameter was <%s param %>!</h1>
</body> </body>
</html> </html>
let () = let () =
@ -12,9 +12,8 @@ let () =
Dream.get "/:word" Dream.get "/:word"
(fun request -> (fun request ->
Dream.param "word" request Dream.param request "word"
|> render |> render
|> Dream.html); |> Dream.html);
] ]
@@ Dream.not_found

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -2,12 +2,12 @@
<br> <br>
Getting Dream to respond with more debug information is as easy as adding Dream has a built-in error handler for showing debug information. You can enable
`~debug:true` to [`Dream.run`](https://aantron.github.io/dream/#val-run): it by passing it to `Dream.run`:
```ocaml ```ocaml
let () = let () =
Dream.run ~debug:true Dream.run ~error_handler:Dream.debug_error_handler
@@ Dream.logger @@ Dream.logger
@@ Dream.router [ @@ Dream.router [
@ -20,49 +20,50 @@ let () =
raise (Failure "The Web app failed!")); raise (Failure "The Web app failed!"));
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/8-debug</b> <pre><code><b>$ cd example/8-debug</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./debug.exe</b></code></pre>
<br> <br>
The rest of the app just adds two routes for triggering two kinds of The rest of the app just adds two routes for triggering two kinds of
failures that the debugger will detail. Visit failures that the debugger will detail. Visit
[http://localhost:8080/bad](http://localhost:8080/bad) [http://localhost:8080/bad](http://localhost:8080/bad) to trigger a
[[playground](http://dream.as/8-debug/bad)] to trigger a `400 Bad Request` `400 Bad Request` response, and
response, and [http://localhost:8080/fail](http://localhost:8080/fail) [http://localhost:8080/fail](http://localhost:8080/fail) to trigger an
[[playground](http://dream.as/8-debug/fail)] to trigger an exception. The exception. The debugger will show reports like this:
debugger will show reports like this:
``` ```
(Failure "The Web app failed!") Failure("The Web app failed!")
Raised at Stdlib__string.index_rec in file "string.ml", line 115, characters 19-34 Raised at Stdlib__map.Make.find in file "map.ml", line 137, characters 10-25
Called from Sexplib0__Sexp.Printing.index_of_newline in file "src/sexp.ml", line 113, characters 13-47 Called from Logs.Tag.find in file "src/logs.ml", line 154, characters 14-32
From: Application From: Application
Blame: Server Blame: Server
Severity: Error Severity: Error
Client: 127.0.0.1:61988 Client: 127.0.0.1:64687
GET /fail HTTP/1.1 GET /fail HTTP/1.1
Host: localhost:8080 Host: localhost:8080
Connection: keep-alive Connection: keep-alive
Upgrade-Insecure-Requests: 1 Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 [...snip...] User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Accept: text/html,application/xhtml+xml, [...snip...] Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-GPC: 1 Sec-GPC: 1
Sec-Fetch-Site: none Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1 Sec-Fetch-User: ?1
Sec-Fetch-Dest: document Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br Accept-Encoding: gzip, deflate, br
Accept-Language: en-US;q=0.9,en;q=0.8 Accept-Language: en-US,en;q=0.9,ru-RU;q=0.8,ru;q=0.7
dream.request_id.last_id: 2 dream.client: 127.0.0.1:64687
dream.tls: false
dream.request_id: 3
dream.params:
``` ```
<!-- Get the request id in the list. --> <!-- Get the request id in the list. -->
@ -76,7 +77,7 @@ As you can see, the report includes:
- `Severity:` a suggested log level for the error, - `Severity:` a suggested log level for the error,
- `Client:` the client address, - `Client:` the client address,
- request headers, - request headers,
- any request-scoped and application-scoped variables set in the request. - any other request variables.
<!-- TODO Link to the tutorial example on variables and also mention that they <!-- TODO Link to the tutorial example on variables and also mention that they
are advanced and usually internal. --> are advanced and usually internal. -->
@ -91,8 +92,9 @@ work with in development.
<br> <br>
Both the debugger's output and the non-debug error page are fully customizable You can have Dream show a custom error page with any information or graphics
&mdash; we will do this in the [very next example](../9-error#files)! that you like &mdash; we will do this in the [very next
example](../9-error#folders-and-files)!
<!-- TODO Fix after stack trace is fixed. --> <!-- TODO Fix after stack trace is fixed. -->
<!-- TODO Show the log --> <!-- TODO Show the log -->
@ -102,9 +104,9 @@ Both the debugger's output and the non-debug error page are fully customizable
**Next steps:** **Next steps:**
- [**`9-error`**](../9-error#files) handles all errors in one place, including - [**`9-error`**](../9-error#folders-and-files) handles all errors in one place, including
displaying the debugger output. displaying the debugger output.
- [**`a-log`**](../a-log#files) shows [log - [**`a-log`**](../a-log#folders-and-files) shows [log
levels](https://aantron.github.io/dream/#type-log_level) and levels](https://aantron.github.io/dream/#type-log_level) and
[sub-logs](https://aantron.github.io/dream/#type-sub_log). [sub-logs](https://aantron.github.io/dream/#type-sub_log).

View File

@ -1,5 +1,5 @@
let () = let () =
Dream.run ~debug:true Dream.run ~error_handler:Dream.debug_error_handler
@@ Dream.logger @@ Dream.logger
@@ Dream.router [ @@ Dream.router [
@ -12,4 +12,3 @@ let () =
raise (Failure "The Web app failed!")); raise (Failure "The Web app failed!"));
] ]
@@ Dream.not_found

View File

@ -1,5 +1,3 @@
(executable (executable
(name debug) (name debug)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./debug.exe"
}
}

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -10,28 +10,21 @@ an `error_handler` is to call
[`Dream.error_template`](https://aantron.github.io/dream/#val-error_template): [`Dream.error_template`](https://aantron.github.io/dream/#val-error_template):
```ocaml ```ocaml
let my_error_template debug_info suggested_response = let my_error_template _error debug_info suggested_response =
let status = Dream.status suggested_response in let status = Dream.status suggested_response in
let code = Dream.status_to_int status let code = Dream.status_to_int status
and reason = Dream.status_to_string status in and reason = Dream.status_to_string status in
suggested_response Dream.set_header suggested_response "Content-Type" Dream.text_html;
|> Dream.with_header "Content-Type" Dream.text_html Dream.set_body suggested_response begin
|> Dream.with_body begin
<html> <html>
<body> <body>
<h1><%i code %> <%s reason %></h1> <h1><%i code %> <%s reason %></h1>
<pre><%s debug_info %></pre>
% begin match debug_info with </body>
% | None -> ()
% | Some debug_info ->
<pre><%s debug_info %></pre>
% end;
</body>
</html> </html>
end end;
|> Lwt.return Lwt.return suggested_response
let () = let () =
Dream.run ~error_handler:(Dream.error_template my_error_template) Dream.run ~error_handler:(Dream.error_template my_error_template)
@ -40,22 +33,14 @@ let () =
``` ```
<pre><code><b>$ cd example/9-error</b> <pre><code><b>$ cd example/9-error</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./error.exe</b></code></pre>
Try it in the [playground](http://dream.as/9-error).
<br> <br>
We kept the error template simple for the sake of the example, but this is We kept the error template simple for the sake of the example, but this is
where you'd put in neat graphics to make a beautiful error page! where you'd put in neat graphics to make a beautiful error page!
This app doesn't show debug information by default. However, try adding
`~debug:true` to [`Dream.run`](https://aantron.github.io/dream/#val-run),
rebuilding the app, and accessing it again. You will see the same kind of output
as in example [**`8-debug`**](../8-debug#files), but now you control its
placement and styling.
<br> <br>
Dream will call the error template for every single error response it generates: Dream will call the error template for every single error response it generates:
@ -77,10 +62,8 @@ including return a completely new response.
<br> <br>
`debug_info` is `None` by default. If you passed `~debug:true` to `debug_info` is a multiline string containing the same information as in the
[`Dream.run`](https://aantron.github.io/dream/#val-run), it is `Some` of a previous example, [**`8-debug`**](../8-debug#folders-and-files).
string that contains the debug info that we saw in the previous example,
[**`8-debug`**](../8-debug#files).
<!-- TODO Images of the generated pages. --> <!-- TODO Images of the generated pages. -->
@ -88,17 +71,18 @@ string that contains the debug info that we saw in the previous example,
If you don't customize the error handler, Dream defaults to sending only empty If you don't customize the error handler, Dream defaults to sending only empty
responses, so that your application can be fully localization-friendly &mdash; responses, so that your application can be fully localization-friendly &mdash;
even at the lowest levels. This is also in accordance with the [OWASP Error even at the lowest levels. Rather than leaking hardcoded English strings, Dream
Handling Cheat relies on the user's browser to display its own built-in, localized error pages.
This choice is also in accordance with the [OWASP Error Handling Cheat
Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html). Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html).
<br> <br>
**Next steps:** **Next steps:**
- [**`a-log`**](../a-log#files) shows how to write messages to Dream's - [**`a-log`**](../a-log#folders-and-files) shows how to write messages to Dream's
[log](https://aantron.github.io/dream/#logging). [log](https://aantron.github.io/dream/#logging).
- [**`b-session`**](../b-session#files) adds [session - [**`b-session`**](../b-session#folders-and-files) adds [session
management](https://aantron.github.io/dream/#sessions) for associating state management](https://aantron.github.io/dream/#sessions) for associating state
with clients. with clients.

View File

@ -6,5 +6,3 @@
(targets error.ml) (targets error.ml)
(deps error.eml.ml) (deps error.eml.ml)
(action (run dream_eml %{deps} --workspace %{workspace_root}))) (action (run dream_eml %{deps} --workspace %{workspace_root})))
(data_only_dirs _esy esy.lock)

View File

@ -1,27 +1,20 @@
let my_error_template debug_info suggested_response = let my_error_template _error debug_info suggested_response =
let status = Dream.status suggested_response in let status = Dream.status suggested_response in
let code = Dream.status_to_int status let code = Dream.status_to_int status
and reason = Dream.status_to_string status in and reason = Dream.status_to_string status in
suggested_response Dream.set_header suggested_response "Content-Type" Dream.text_html;
|> Dream.with_header "Content-Type" Dream.text_html Dream.set_body suggested_response begin
|> Dream.with_body begin
<html> <html>
<body> <body>
<h1><%i code %> <%s reason %></h1> <h1><%i code %> <%s reason %></h1>
<pre><%s debug_info %></pre>
% begin match debug_info with </body>
% | None -> ()
% | Some debug_info ->
<pre><%s debug_info %></pre>
% end;
</body>
</html> </html>
end end;
|> Lwt.return Lwt.return suggested_response
let () = let () =
Dream.run ~error_handler:(Dream.error_template my_error_template) Dream.run ~error_handler:(Dream.error_template my_error_template)
@@ Dream.logger @@ Dream.logger
@@ Dream.not_found @@ fun _ -> Dream.empty `Not_Found

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./error.exe"
}
}

View File

@ -2,46 +2,46 @@
Dream's first several examples make up a **tutorial**. Each example is a Dream's first several examples make up a **tutorial**. Each example is a
complete project with a helpful README, and plenty of links to next steps and complete project with a helpful README, and plenty of links to next steps and
documentation. You can begin at [**`1-hello`**](1-hello#files), or look in the documentation. You can begin at [**`1-hello`**](1-hello#folders-and-files), or look in the
list below and jump to whatever interests you! list below and jump to whatever interests you!
- [**`1-hello`**](1-hello/#files) &nbsp;&mdash;&nbsp; the simplest Dream server - [**`1-hello`**](1-hello#folders-and-files) &nbsp;&mdash;&nbsp; the simplest Dream server
responds to every request with the same friendly message. responds to every request with the same friendly message.
- [**`2-middleware`**](2-middleware/#files) &nbsp;&mdash;&nbsp; adds the first - [**`2-middleware`**](2-middleware#folders-and-files) &nbsp;&mdash;&nbsp; adds the first
Dream middleware: the *logger*. Dream middleware: the *logger*.
- [**`3-router`**](3-router/#files) &nbsp;&mdash;&nbsp; different handlers for - [**`3-router`**](3-router#folders-and-files) &nbsp;&mdash;&nbsp; different handlers for
different paths. different paths.
- [**`4-counter`**](4-counter/#files) &nbsp;&mdash;&nbsp; the first *custom* - [**`4-counter`**](4-counter#folders-and-files) &nbsp;&mdash;&nbsp; the first *custom*
middleware! middleware!
- [**`5-promise`**](5-promise/#files) &nbsp;&mdash;&nbsp; introduces Lwt, the - [**`5-promise`**](5-promise#folders-and-files) &nbsp;&mdash;&nbsp; introduces Lwt, the
promise library used by Dream. promise library used by Dream.
- [**`6-echo`**](6-echo/#files) &nbsp;&mdash;&nbsp; reads request bodies. - [**`6-echo`**](6-echo#folders-and-files) &nbsp;&mdash;&nbsp; reads request bodies.
- [**`7-template`**](7-template/#files) &nbsp;&mdash;&nbsp; renders responses - [**`7-template`**](7-template#folders-and-files) &nbsp;&mdash;&nbsp; renders responses
from inline HTML templates and guards against XSS. from inline HTML templates and guards against XSS.
- [**`8-debug`**](8-debug/#files) &nbsp;&mdash;&nbsp; includes detailed - [**`8-debug`**](8-debug#folders-and-files) &nbsp;&mdash;&nbsp; includes detailed
information about errors in responses. information about errors in responses.
- [**`9-error`**](9-error/#files) &nbsp;&mdash;&nbsp; customize all error - [**`9-error`**](9-error#folders-and-files) &nbsp;&mdash;&nbsp; customize all error
responses in one place. responses in one place.
- [**`a-log`**](a-log/#files) &nbsp;&mdash;&nbsp; writing messages to Dream's - [**`a-log`**](a-log#folders-and-files) &nbsp;&mdash;&nbsp; writing messages to Dream's
log. log.
- [**`b-session`**](b-session/#files) &nbsp;&mdash;&nbsp; associates state with - [**`b-session`**](b-session#folders-and-files) &nbsp;&mdash;&nbsp; associates state with
client sessions. client sessions.
- [**`c-cookie`**](c-cookie/#files) &nbsp;&mdash;&nbsp; sets custom cookies. - [**`c-cookie`**](c-cookie#folders-and-files) &nbsp;&mdash;&nbsp; sets custom cookies.
- [**`d-form`**](d-form#files) &nbsp;&mdash;&nbsp; reads forms with CSRF - [**`d-form`**](d-form#folders-and-files) &nbsp;&mdash;&nbsp; reads forms with CSRF
prevention. prevention.
- [**`e-json`**](e-json#files) &nbsp;&mdash;&nbsp; sends and receives JSON - [**`e-json`**](e-json#folders-and-files) &nbsp;&mdash;&nbsp; sends and receives JSON
securely. securely.
- [**`f-static`**](f-static#files) &nbsp;&mdash;&nbsp; serves static files from - [**`f-static`**](f-static#folders-and-files) &nbsp;&mdash;&nbsp; serves static files from
a local directory. a local directory.
- [**`g-upload`**](g-upload#files) &nbsp;&mdash;&nbsp; receives file uploads. - [**`g-upload`**](g-upload#folders-and-files) &nbsp;&mdash;&nbsp; receives file uploads.
- [**`h-sql`**](h-sql#files) &nbsp;&mdash;&nbsp; queries an SQL database. - [**`h-sql`**](h-sql#folders-and-files) &nbsp;&mdash;&nbsp; queries an SQL database.
- [**`i-graphql`**](i-graphql#files) &nbsp;&mdash;&nbsp; serves a GraphQL - [**`i-graphql`**](i-graphql#folders-and-files) &nbsp;&mdash;&nbsp; serves a GraphQL
schema and GraphiQL. schema and GraphiQL.
- [**`j-stream`**](j-stream#files) &nbsp;&mdash;&nbsp; streams request and - [**`j-stream`**](j-stream#folders-and-files) &nbsp;&mdash;&nbsp; streams request and
response bodies. response bodies.
- [**`k-websocket`**](k-websocket#files) &nbsp;&mdash;&nbsp; opens a WebSocket - [**`k-websocket`**](k-websocket#folders-and-files) &nbsp;&mdash;&nbsp; opens a WebSocket
between client and server. between client and server.
- [**`l-https`**](l-https#files) &nbsp;&mdash;&nbsp; enables HTTPS and HTTP/2 - [**`l-https`**](l-https#folders-and-files) &nbsp;&mdash;&nbsp; enables HTTPS and HTTP/2
upgrades. upgrades.
That's it for the tutorial! That's it for the tutorial!
@ -52,38 +52,43 @@ That's it for the tutorial!
There are several examples showing Dream with Reason syntax. There are several examples showing Dream with Reason syntax.
- [**`r-hello`**](r-hello#files) &nbsp;&mdash;&nbsp; the simplest Dream server. - [**`r-hello`**](r-hello#folders-and-files) &nbsp;&mdash;&nbsp; the simplest Dream server.
- [**`r-template`**](r-template#files) &nbsp;&mdash;&nbsp; renders HTML - [**`r-template`**](r-template#folders-and-files) &nbsp;&mdash;&nbsp; renders HTML
templates and protects against XSS. templates and protects against XSS.
- [**`r-template-stream`**](r-template-stream#files) &nbsp;&mdash;&nbsp; streams - [**`r-template-files`**](r-template-files#folders-and-files) &nbsp;&mdash;&nbsp; templates
in separate `.html` files for better editor support.
- [**`r-template-logic`**](r-template-logic#folders-and-files) &nbsp;&mdash;&nbsp; control
flow inside templates.
- [**`r-template-stream`**](r-template-stream#folders-and-files) &nbsp;&mdash;&nbsp; streams
templates as response bodies. templates as response bodies.
- [**`r-tyxml`**](r-tyxml#files) &nbsp;&mdash;&nbsp; type-checked server-side - [**`r-tyxml`**](r-tyxml#folders-and-files) &nbsp;&mdash;&nbsp; type-checked server-side
JSX templates. JSX templates.
- [**`r-graphql`**](r-graphql#files) &nbsp;&mdash;&nbsp; serves a GraphQL - [**`r-graphql`**](r-graphql#folders-and-files) &nbsp;&mdash;&nbsp; serves a GraphQL
schema. schema.
<br> <br>
# Full-stack # Full-stack
- [**`r-fullstack-melange`**](r-fullstack-melange#files) &nbsp;&mdash;&nbsp; - [**`r-fullstack-melange`**](r-fullstack-melange#folders-and-files) &nbsp;&mdash;&nbsp;
server *and* client written in Reason! server *and* client written in Reason!
- [**`w-fullstack-rescript`**](w-fullstack-rescript#files) &nbsp;&mdash;&nbsp; - [**`w-fullstack-rescript`**](w-fullstack-rescript#folders-and-files) &nbsp;&mdash;&nbsp;
shares OCaml code between server and client using ReScript. shares OCaml code between server and client using ReScript.
- [**`w-fullstack-jsoo`**](w-fullstack-jsoo#files) &nbsp;&mdash;&nbsp; shares - [**`w-fullstack-jsoo`**](w-fullstack-jsoo#folders-and-files) &nbsp;&mdash;&nbsp; shares
OCaml code between server and client using js_of_ocaml. OCaml code between server and client using js_of_ocaml.
<br> <br>
# Deploying # Deploying
- [**`z-heroku`**](z-heroku#files) &nbsp;&mdash;&nbsp; to - [**`z-heroku`**](z-heroku#folders-and-files) &nbsp;&mdash;&nbsp; to
[Heroku](https://www.heroku.com). [Heroku](https://www.heroku.com).
- [**`z-docker-esy`**](z-docker-esy#files) &nbsp;&mdash;&nbsp; on a server, - [**`z-fly`**](z-fly#folders-and-files) &nbsp;&mdash;&nbsp; to [Fly.io](https://fly.io/).
- [**`z-docker-esy`**](z-docker-esy#folders-and-files) &nbsp;&mdash;&nbsp; on a server,
using Docker, with package manager esy. using Docker, with package manager esy.
- [**`z-docker-opam`**](z-docker-opam#files) &nbsp;&mdash;&nbsp; on a server, - [**`z-docker-opam`**](z-docker-opam#folders-and-files) &nbsp;&mdash;&nbsp; on a server,
using Docker, with package manager opam. using Docker, with package manager opam.
- [**`z-systemd`**](z-systemd#files) &nbsp;&mdash;&nbsp; on a server, as a - [**`z-systemd`**](z-systemd#folders-and-files) &nbsp;&mdash;&nbsp; on a server, as a
systemd daemon. systemd daemon.
<br> <br>
@ -97,35 +102,51 @@ if something is missing!
<br> <br>
- [**`w-graphql-subscription`**](w-graphql-subscription#files) - [**`w-template-files`**](w-template-files#folders-and-files) &nbsp;&mdash;&nbsp; templates
in separate `.html` files for better editor support.
- [**`w-template-logic`**](w-template-logic#folders-and-files) &nbsp;&mdash;&nbsp; control
flow inside templates.
- [**`w-graphql-subscription`**](w-graphql-subscription#folders-and-files)
&nbsp;&mdash;&nbsp; GraphQL subscriptions. &nbsp;&mdash;&nbsp; GraphQL subscriptions.
- [**`w-esy`**](w-esy#files) &nbsp;&mdash;&nbsp; gives detail on packaging with - [**`w-postgres`**](w-postgres#folders-and-files) &nbsp;&mdash;&nbsp; connects to a
PostgreSQL database.
- [**`w-flash`**](w-flash#folders-and-files) &nbsp;&mdash;&nbsp; using flash messages, which
are displayed on the next request.
- [**`w-chat`**](w-chat#folders-and-files) &nbsp;&mdash;&nbsp; a chat room based on
WebSockets.
- [**`w-content-security-policy`**](w-content-security-policy#folders-and-files)
&nbsp;&mdash;&nbsp; sandboxes Web pages using `Content-Security-Policy`.
- [**`w-esy`**](w-esy#folders-and-files) &nbsp;&mdash;&nbsp; gives detail on packaging with
[esy](https://esy.sh/), an npm-like package manager. [esy](https://esy.sh/), an npm-like package manager.
- [**`w-one-binary`**](w-one-binary#files) &nbsp;&mdash;&nbsp; bakes static - [**`w-one-binary`**](w-one-binary#folders-and-files) &nbsp;&mdash;&nbsp; bakes static
assets into a self-contained server binary. assets into a self-contained server binary.
- [**`w-fswatch`**](w-fswatch#files) &nbsp;&mdash;&nbsp; sets up a development - [**`w-watch`**](w-watch#folders-and-files) &nbsp;&mdash;&nbsp; sets up a development
watcher using fswatch. watcher.
- [**`w-live-reload`**](w-live-reload#files) &nbsp;&mdash;&nbsp; a simple - [**`w-live-reload`**](w-live-reload#folders-and-files) &nbsp;&mdash;&nbsp; a simple
live-reloading setup. live-reloading setup.
- [**`w-tyxml`**](w-tyxml#files) &nbsp;&mdash;&nbsp; uses TyXML for type-checked - [**`w-nginx`**](w-nginx#folders-and-files) &nbsp;&mdash;&nbsp; uses nginx as a
reverse proxy.
- [**`w-tyxml`**](w-tyxml#folders-and-files) &nbsp;&mdash;&nbsp; uses TyXML for type-checked
HTML templating. HTML templating.
- [**`w-long-polling`**](w-long-polling#files) &nbsp;&mdash;&nbsp; old form of - [**`w-dream-html`**](../w-dream-html#folders-and-files) &nbsp;&mdash;&nbsp; uses
dream-html for convenient HTML generation from OCaml.
- [**`w-long-polling`**](w-long-polling#folders-and-files) &nbsp;&mdash;&nbsp; old form of
asynchronous communication without WebSockets. asynchronous communication without WebSockets.
- [**`w-query`**](w-query#files) &nbsp;&mdash;&nbsp; reads URL query parameters. - [**`w-query`**](w-query#folders-and-files) &nbsp;&mdash;&nbsp; reads URL query parameters.
- [**`w-server-sent-events`**](w-server-sent-events#files) &nbsp;&mdash;&nbsp; - [**`w-server-sent-events`**](w-server-sent-events#folders-and-files) &nbsp;&mdash;&nbsp;
[`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource),
an older alternative to WebSockets. an older alternative to WebSockets.
- [**`w-template-stream`**](w-template-stream#files) &nbsp;&mdash;&nbsp; sends - [**`w-template-stream`**](w-template-stream#folders-and-files) &nbsp;&mdash;&nbsp; sends
templates asynchronously, one chunk at a time. templates asynchronously, one chunk at a time.
- [**`w-upload-stream`**](w-upload-stream#files) &nbsp;&mdash;&nbsp; streams - [**`w-upload-stream`**](w-upload-stream#folders-and-files) &nbsp;&mdash;&nbsp; streams
uploaded files. uploaded files.
- [**`w-stress-response`**](w-stress-response#files) &nbsp;&mdash;&nbsp; - [**`w-stress-response`**](w-stress-response#folders-and-files) &nbsp;&mdash;&nbsp;
benchmarks streaming very large responses. benchmarks streaming very large responses.
- [**`w-stress-websocket-send`**](w-stress-websocket-send#files) - [**`w-stress-websocket-send`**](w-stress-websocket-send#folders-and-files)
&nbsp;&mdash;&nbsp; benchmarks sending WebSocket messages quickly. &nbsp;&mdash;&nbsp; benchmarks sending WebSocket messages quickly.
- [**`w-multipart-dump`**](w-multipart-dump#files) &nbsp;&mdash;&nbsp; echoes - [**`w-multipart-dump`**](w-multipart-dump#folders-and-files) &nbsp;&mdash;&nbsp; echoes
`multipart/form-data` bodies for debugging. `multipart/form-data` bodies for debugging.
- [**`z-playground`**](z-playground#files) &nbsp;&mdash;&nbsp; source code of - [**`z-playground`**](z-playground#folders-and-files) &nbsp;&mdash;&nbsp; source code of
the Dream playground. the Dream playground.
<br> <br>
@ -148,7 +169,7 @@ Ideas:
Basics: Basics:
- `w-content-negotiation` - `w-content-negotiation`
- [**`w-query`**](w-query#files) &nbsp;&mdash;&nbsp; done. - [**`w-query`**](w-query#folders-and-files) &nbsp;&mdash;&nbsp; done.
- `w-scope` &nbsp;&mdash;&nbsp; for - `w-scope` &nbsp;&mdash;&nbsp; for
[`Dream.scope`](https://aantron.github.io/dream/#val-scope). [`Dream.scope`](https://aantron.github.io/dream/#val-scope).
- `w-subsite` &nbsp;&mdash;&nbsp; for - `w-subsite` &nbsp;&mdash;&nbsp; for
@ -181,7 +202,6 @@ Techniques:
- `w-graphql-sql` - `w-graphql-sql`
- `w-graphql-mutation` - `w-graphql-mutation`
- `w-https-redirect` - `w-https-redirect`
- `w-postgres-docker`
- `w-sql-stream` - `w-sql-stream`
- `w-websocket-stream` - `w-websocket-stream`

View File

@ -22,17 +22,15 @@ let () =
raise (Failure "The Web app failed!")); raise (Failure "The Web app failed!"));
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/a-log</b> <pre><code><b>$ cd example/a-log</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./log.exe</b></code></pre>
<br> <br>
If you visit [http://localhost:8080](http://localhost:8080) If you visit [http://localhost:8080](http://localhost:8080) and then
[[playground](http://dream.as/a-log)] and then
[http://localhost:8080/fail](http://localhost:8080/fail), you will find these [http://localhost:8080/fail](http://localhost:8080/fail), you will find these
messages in the log, between the others: messages in the log, between the others:
@ -42,7 +40,7 @@ messages in the log, between the others:
``` ```
Note that this is on `stderr`. As you can see, the functions take Note that this is on `stderr`. As you can see, the functions take
[`Printf`-style format strings](https://caml.inria.fr/pub/docs/manual-ocaml/libref/Printf.html), [`Printf`-style format strings](https://v2.ocaml.org/api/Printf.html),
so you can quickly print values of various types to the log. so you can quickly print values of various types to the log.
<br> <br>
@ -78,9 +76,9 @@ let () =
**Next steps:** **Next steps:**
- [**`b-session`**](../b-session#files) returns Web development proper with - [**`b-session`**](../b-session#folders-and-files) returns Web development proper with
session management. session management.
- [**`c-cookie`**](../c-cookie#files) shows cookie handling in Dream. - [**`c-cookie`**](../c-cookie#folders-and-files) shows cookie handling in Dream.
<br> <br>

14
example/a-log/a-log.opam Normal file
View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -1,5 +1,3 @@
(executable (executable
(name log) (name log)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./log.exe"
}
}

View File

@ -14,4 +14,3 @@ let () =
raise (Failure "The Web app failed!")); raise (Failure "The Web app failed!"));
] ]
@@ Dream.not_found

View File

@ -11,10 +11,10 @@ let () =
@@ Dream.memory_sessions @@ Dream.memory_sessions
@@ fun request -> @@ fun request ->
match Dream.session "user" request with match Dream.session_field request "user" with
| None -> | None ->
let%lwt () = Dream.invalidate_session request in let%lwt () = Dream.invalidate_session request in
let%lwt () = Dream.put_session "user" "alice" request in let%lwt () = Dream.set_session_field request "user" "alice" in
Dream.html "You weren't logged in; but now you are!" Dream.html "You weren't logged in; but now you are!"
| Some username -> | Some username ->
@ -23,13 +23,13 @@ let () =
``` ```
<pre><code><b>$ cd example/b-session</b> <pre><code><b>$ cd example/b-session</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./session.exe</b></code></pre>
<br> <br>
The first time you access the app [[playground](http://dream.as/b-session)], it The first time you access the app, it “logs you in” by saving you user name in
“logs you in” by saving you user name in a session. The session manager, a session. The session manager,
[`Dream.memory_sessions`](https://aantron.github.io/dream/#val-memory_sessions), [`Dream.memory_sessions`](https://aantron.github.io/dream/#val-memory_sessions),
a middleware, adds a `dream.session` cookie to the response, containing the a middleware, adds a `dream.session` cookie to the response, containing the
session key. The next time you access the app, the session is looked up again session key. The next time you access the app, the session is looked up again
@ -62,13 +62,13 @@ There are two other session back ends, which are persistent:
stores session data in encrypted cookies. That is, session data is stored on stores session data in encrypted cookies. That is, session data is stored on
clients, rather than on the server. You can replace `Dream.memory_sessions` clients, rather than on the server. You can replace `Dream.memory_sessions`
with `Dream.cookie_sessions` and it will work right away. However, if you with `Dream.cookie_sessions` and it will work right away. However, if you
want to be able to decrypt sessions set by previous runs of the server, pass want to be able to decrypt sessions set by previous runs of the server, use
`~secret:"my-secret"` to the [`Dream.set_secret`](https://aantron.github.io/dream/#val-set_secret)
[`Dream.run`](https://aantron.github.io/dream/#val-run) so that it doesn't middleware before `Dream.cookie_sessions`. If you don't, the server will be
generate a random key each time. using a different random encryption key each time it starts.
- [`Dream.sql_sessions`](https://aantron.github.io/dream/#val-sql_sessions) - [`Dream.sql_sessions`](https://aantron.github.io/dream/#val-sql_sessions)
stores sessions in a database. It's used in example stores sessions in a database. It is shown in example
[**`h-sql`**](../h-sql#files). [**`h-sql`**](../h-sql#folders-and-files).
<br> <br>
@ -90,7 +90,7 @@ new session will, again, be an empty pre-session.
It is best to use HTTPS when using sessions, to prevent session cookies from It is best to use HTTPS when using sessions, to prevent session cookies from
being easily observed by third parties. See being easily observed by third parties. See
[`Dream.run`](https://aantron.github.io/dream/#val-run) argument `~https`, and [`Dream.run`](https://aantron.github.io/dream/#val-run) argument `~https`, and
example [**`l-https`**](../l-https#files). If you redirect from HTTP to HTTPS, example [**`l-https`**](../l-https#folders-and-files). If you redirect from HTTP to HTTPS,
do not issue sessions for HTTP requests. If you do, don't accept them later do not issue sessions for HTTP requests. If you do, don't accept them later
from HTTPS requests. from HTTPS requests.
@ -100,8 +100,8 @@ from HTTPS requests.
**Next steps:** **Next steps:**
- Sessions already use cookies internally, but in - Sessions already use cookies internally, but in
[**`c-cookie`**](../c-cookie#files) we set cookies for our own purposes! [**`c-cookie`**](../c-cookie#folders-and-files) we set cookies for our own purposes!
- [**`d-form`**](../d-form#files) builds secure forms on top of sessions. - [**`d-form`**](../d-form#folders-and-files) builds secure forms on top of sessions.
<br> <br>

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -2,5 +2,3 @@
(name session) (name session)
(libraries dream) (libraries dream)
(preprocess (pps lwt_ppx))) (preprocess (pps lwt_ppx)))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./session.exe"
}
}

View File

@ -4,10 +4,10 @@ let () =
@@ Dream.memory_sessions @@ Dream.memory_sessions
@@ fun request -> @@ fun request ->
match Dream.session "user" request with match Dream.session_field request "user" with
| None -> | None ->
let%lwt () = Dream.invalidate_session request in let%lwt () = Dream.invalidate_session request in
let%lwt () = Dream.put_session "user" "alice" request in let%lwt () = Dream.set_session_field request "user" "alice" in
Dream.html "You weren't logged in; but now you are!" Dream.html "You weren't logged in; but now you are!"
| Some username -> | Some username ->

View File

@ -6,32 +6,32 @@ Let's [set our own cookie](https://aantron.github.io/dream/#cookies):
```ocaml ```ocaml
let () = let () =
Dream.run ~secret:"foo" Dream.run
@@ Dream.set_secret "foo"
@@ Dream.logger @@ Dream.logger
@@ fun request -> @@ fun request ->
match Dream.cookie "ui.language" request with match Dream.cookie request "ui.language" with
| Some value -> | Some value ->
Printf.ksprintf Printf.ksprintf
Dream.html "Your preferred language is %s!" (Dream.html_escape value) Dream.html "Your preferred language is %s!" (Dream.html_escape value)
| None -> | None ->
Dream.response "Set language preference; come again!" let response = Dream.response "Set language preference; come again!" in
|> Dream.add_header "Content-Type" Dream.text_html Dream.add_header response "Content-Type" Dream.text_html;
|> Dream.set_cookie "ui.language" "ut-OP" request Dream.set_cookie response request "ui.language" "ut-OP";
|> Lwt.return Lwt.return response
``` ```
<pre><code><b>$ cd example/c-cookie</b> <pre><code><b>$ cd example/c-cookie</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./cookie.exe</b></code></pre>
<br> <br>
The first time you access this app [[playground](http://dream.as/c-cookie)], it The first time you access this app, it sets up a language preference, `ut-OP`.
sets up a language preference, `ut-OP`. This string is sent to the client in a This string is sent to the client in a `ui.language` cookie. On the next
`ui.language` cookie. On the next request, the client sends it back. The app request, the client sends it back. The app retrieves and displays it.
retrieves and displays it.
<br> <br>
@ -42,7 +42,9 @@ That's because it access certain fields of the request to set some fairly
aggressive security defaults: aggressive security defaults:
- Cookie encryption, for which it accesses the encryption key. This is why we - Cookie encryption, for which it accesses the encryption key. This is why we
passed `~secret` to [`Dream.run`](https://aantron.github.io/dream/#val-run). used the
[`Dream.set_secret`](https://aantron.github.io/dream/#val-set_secret)
middleware.
- Whether the request likely came through an HTTPS connection, to set the - Whether the request likely came through an HTTPS connection, to set the
[`Secure`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) [`Secure`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
attribute. attribute.
@ -94,9 +96,9 @@ The easiest way to do that for general data is to use
**Next steps:** **Next steps:**
- [**`d-form`**](../d-form#files) builds secure forms on top of sessions, and - [**`d-form`**](../d-form#folders-and-files) builds secure forms on top of sessions, and
introduces automatic handling of CSRF tokens. introduces automatic handling of CSRF tokens.
- [**`e-json`**](../e-json#files) sends and receives JSON instead! - [**`e-json`**](../e-json#folders-and-files) sends and receives JSON instead!
<br> <br>

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -1,15 +1,16 @@
let () = let () =
Dream.run ~secret:"foo" Dream.run
@@ Dream.set_secret "foo"
@@ Dream.logger @@ Dream.logger
@@ fun request -> @@ fun request ->
match Dream.cookie "ui.language" request with match Dream.cookie request "ui.language" with
| Some value -> | Some value ->
Printf.ksprintf Printf.ksprintf
Dream.html "Your preferred language is %s!" (Dream.html_escape value) Dream.html "Your preferred language is %s!" (Dream.html_escape value)
| None -> | None ->
Dream.response "Set language preference; come again!" let response = Dream.response "Set language preference; come again!" in
|> Dream.add_header "Content-Type" Dream.text_html Dream.add_header response "Content-Type" Dream.text_html;
|> Dream.set_cookie "ui.language" "ut-OP" request Dream.set_cookie response request "ui.language" "ut-OP";
|> Lwt.return Lwt.return response

View File

@ -1,5 +1,3 @@
(executable (executable
(name cookie) (name cookie)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./cookie.exe"
}
}

View File

@ -2,25 +2,26 @@
<br> <br>
With the session middleware from example [**`b-session`**](../b-session#files), With the session middleware from example [**`b-session`**](../b-session#folders-and-files),
we can build a [secure form](https://aantron.github.io/dream/#forms): we can build a [secure form](https://aantron.github.io/dream/#forms):
```ocaml ```ocaml
let show_form ?message request = let show_form ?message request =
<html> <html>
<body> <body>
% begin match message with % begin match message with
% | None -> () % | None -> ()
% | Some message -> % | Some message ->
<p>You entered: <b><%s message %>!</b></p> <p>You entered: <b><%s message %>!</b></p>
% end; % end;
<%s! Dream.form_tag ~action:"/" request %> <form method="POST" action="/">
<input name="message" autofocus> <%s! Dream.csrf_tag request %>
</form> <input name="message" autofocus>
</form>
</body> </body>
</html> </html>
let () = let () =
@ -42,49 +43,47 @@ let () =
Dream.empty `Bad_Request); Dream.empty `Bad_Request);
] ]
@@ Dream.not_found
``` ```
<pre><code><b>$ cd example/d-form</b> <pre><code><b>$ cd example/d-form</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./form.exe</b></code></pre>
Try it in the [playground](http://dream.as/d-form).
<br> <br>
We didn't write a literal `<form>` tag in the template. Instead, we used The template adds a CSRF token to the form using
[`Dream.form_tag`](https://aantron.github.io/dream/#val-form_tag) to generate [`Dream.csrf_tag`](https://aantron.github.io/dream/#val-csrf_tag). Its output
the tag. [`Dream.form_tag`](https://aantron.github.io/dream/#val-form_tag) also looks something like this:
snuck in a hidden `<input>` field containing a CSRF token:
```html ```html
<form method="POST" action="/"> <form method="POST" action="/">
<input name="dream.csrf" type="hidden" value="j8vjZ6..."> <input name="dream.csrf" type="hidden" value="j8vjZ6...">
<!-- The rest we actually wrote ourselves in the template! -->
<input name="message" autofocus> <input name="message" autofocus>
</form> </form>
``` ```
This hidden `dream.csrf` field helps to That generated, hidden `dream.csrf` field helps to [prevent CSRF
[prevent CSRF attacks](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) attacks](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).
attacks against the form. It should be the [first
field](https://portswigger.net/web-security/csrf/tokens#how-should-csrf-tokens-be-transmitted)
in your form.
[`Dream.form`](https://aantron.github.io/dream/#val-form) expects `dream.csrf` When the form is submitted and parsed using
and checks it. If there is anything wrong with the token, [`Dream.form`](https://aantron.github.io/dream/#val-form), `Dream.form` expects
[`Dream.form`](https://aantron.github.io/dream/#val-form) will return a [value to find the `dream.csrf` field, and checks it. If there is anything wrong with
other than `` `Ok _``](https://aantron.github.io/dream/#type-form_result). the CSRF token, [`Dream.form`](https://aantron.github.io/dream/#val-form) will
return a [value other than
`` `Ok _``](https://aantron.github.io/dream/#type-form_result).
<br> <br>
The form fields carried inside `` `Ok _`` are returned in sorted order, so you The form fields carried inside `` `Ok _`` are returned in sorted order, so you
can reliably pattern-match on them. can reliably pattern-match on them.
The bad token results, like `` `Expired _``, also carry the form fields. You can The bad token results, like `` `Expired (_, _)``, also carry the form fields.
add handling for them to recover. For example, if you receive an expired form, You can add handling for them to recover. For example, if you receive a form
you may want to resend it with some of the fields pre-filled to received with an expired token, you may want to resend it with some of the fields pre-
values, so that the user can try again quickly. filled to received values, so that the user can try again quickly.
However, do not send back any sensitive data, because *any* result other than However, do not send back any sensitive data, because *any* result other than
`` `Ok _`` *might* indicate an attack in progress. That said, `` `Expired _`` `` `Ok _`` *might* indicate an attack in progress. That said, `` `Expired _``
@ -101,14 +100,14 @@ important on login forms and other sensitive pages.
However, this server is so simple that it doesn't store the data anywhere, and However, this server is so simple that it doesn't store the data anywhere, and
the data is not sensitive, so we took a shortcut. See the data is not sensitive, so we took a shortcut. See
[**`h-sql`**](../h-sql#files) for an example with a proper redirection. [**`h-sql`**](../h-sql#folders-and-files) for an example with a proper redirection.
<br> <br>
**Next steps:** **Next steps:**
- [**`e-json`**](../e-json#files) receives and sends JSON. - [**`e-json`**](../e-json#folders-and-files) receives and sends JSON.
- [**`f-static`**](../f-static#files) serves static files from a local - [**`f-static`**](../f-static#folders-and-files) serves static files from a local
directory. directory.
<br> <br>

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -7,5 +7,3 @@
(targets form.ml) (targets form.ml)
(deps form.eml.ml) (deps form.eml.ml)
(action (run dream_eml %{deps} --workspace %{workspace_root}))) (action (run dream_eml %{deps} --workspace %{workspace_root})))
(data_only_dirs _esy esy.lock)

View File

@ -1,13 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./form.exe"
}
}

View File

@ -1,18 +1,19 @@
let show_form ?message request = let show_form ?message request =
<html> <html>
<body> <body>
% begin match message with % begin match message with
% | None -> () % | None -> ()
% | Some message -> % | Some message ->
<p>You entered: <b><%s message %>!</b></p> <p>You entered: <b><%s message %>!</b></p>
% end; % end;
<%s! Dream.form_tag ~action:"/" request %> <form method="POST" action="/">
<input name="message" autofocus> <%s! Dream.csrf_tag request %>
</form> <input name="message" autofocus>
</form>
</body> </body>
</html> </html>
let () = let () =
@ -34,4 +35,3 @@ let () =
Dream.empty `Bad_Request); Dream.empty `Bad_Request);
] ]
@@ Dream.not_found

View File

@ -10,6 +10,8 @@ converter between JSON and an OCaml data type. We then create a little server
that listens for JSON of the right shape, and echoes back its `message` field: that listens for JSON of the right shape, and echoes back its `message` field:
```ocaml ```ocaml
open Ppx_yojson_conv_lib.Yojson_conv.Primitives
type message_object = { type message_object = {
message : string; message : string;
} [@@deriving yojson] } [@@deriving yojson]
@ -17,7 +19,7 @@ type message_object = {
let () = let () =
Dream.run Dream.run
@@ Dream.logger @@ Dream.logger
@@ Dream.origin_referer_check @@ Dream.origin_referrer_check
@@ Dream.router [ @@ Dream.router [
Dream.post "/" Dream.post "/"
@ -35,7 +37,6 @@ let () =
|> Dream.json); |> Dream.json);
] ]
@@ Dream.not_found
``` ```
To get this working, we have to add `ppx_yojson_conv` to our To get this working, we have to add `ppx_yojson_conv` to our
@ -48,24 +49,21 @@ To get this working, we have to add `ppx_yojson_conv` to our
</code></pre> </code></pre>
and to and to
[`esy.json`](https://github.com/aantron/dream/blob/master/example/e-json/esy.json): [`json.opam`](https://github.com/aantron/dream/blob/master/example/e-json/e-json.opam):
<pre><code>{ <pre><code>depends: [
"dependencies": { "ocaml" {>= "4.08.0"}
"@opam/dream": "aantron/dream:dream.opam", "dream"
"@opam/dune": "^2.0", "dune" {>= "2.0.0"}
<b>"@opam/ppx_yojson_conv": "*",</b> <b>"ppx_yojson_conv"</b>
"ocaml": "4.12.x" ]
}
</code></pre> </code></pre>
The build commands, as always, are: The build commands, as always, are:
<pre><code><b>$ cd example/e-json</b> <pre><code><b>$ cd example/e-json</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./json.exe</b></code></pre>
You can try this example in the [playground](http://dream.as/e-json).
<br> <br>
@ -94,7 +92,7 @@ Content-Type: application/json
## Security ## Security
[`Dream.origin_referer_check`](https://aantron.github.io/dream/#val-origin_referer_check) [`Dream.origin_referrer_check`](https://aantron.github.io/dream/#val-origin_referrer_check)
implements the implements the
[OWASP Verifying Origin With Standard Headers](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#verifying-origin-with-standard-headers) [OWASP Verifying Origin With Standard Headers](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#verifying-origin-with-standard-headers)
CSRF protection technique. It doesn't protect `GET` requests, so they shouldn't CSRF protection technique. It doesn't protect `GET` requests, so they shouldn't
@ -114,9 +112,9 @@ requests!
**Next steps:** **Next steps:**
- [**`f-static`**](../f-static#files) serves static files from the local - [**`f-static`**](../f-static#folders-and-files) serves static files from the local
file system. file system.
- [**`g-upload`**](../g-upload#files) receives files from an upload form. - [**`g-upload`**](../g-upload#folders-and-files) receives files from an upload form.
<br> <br>

View File

@ -2,5 +2,3 @@
(name json) (name json)
(libraries dream) (libraries dream)
(preprocess (pps lwt_ppx ppx_yojson_conv))) (preprocess (pps lwt_ppx ppx_yojson_conv)))
(data_only_dirs _esy esy.lock)

View File

@ -0,0 +1,15 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
"ppx_yojson_conv"
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -1,14 +0,0 @@
{
"dependencies": {
"@opam/dream": "aantron/dream:dream.opam",
"@opam/dune": "^2.0",
"@opam/ppx_yojson_conv": "*",
"ocaml": "4.12.x"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829"
},
"scripts": {
"start": "dune exec --root . ./json.exe"
}
}

View File

@ -1,3 +1,5 @@
open Ppx_yojson_conv_lib.Yojson_conv.Primitives
type message_object = { type message_object = {
message : string; message : string;
} [@@deriving yojson] } [@@deriving yojson]
@ -5,7 +7,7 @@ type message_object = {
let () = let () =
Dream.run Dream.run
@@ Dream.logger @@ Dream.logger
@@ Dream.origin_referer_check @@ Dream.origin_referrer_check
@@ Dream.router [ @@ Dream.router [
Dream.post "/" Dream.post "/"
@ -23,4 +25,3 @@ let () =
|> Dream.json); |> Dream.json);
] ]
@@ Dream.not_found

View File

@ -5,8 +5,8 @@
Run this example: Run this example:
<pre><code><b>$ cd example/f-static</b> <pre><code><b>$ cd example/f-static</b>
<b>$ npm install esy && npx esy</b> <b>$ opam install --deps-only --yes .</b>
<b>$ npx esy start</b></code></pre> <b>$ dune exec --root . ./static.exe</b></code></pre>
...and visit ...and visit
[http://localhost:8080/static/static.ml](http://localhost:8080/static/static.ml). [http://localhost:8080/static/static.ml](http://localhost:8080/static/static.ml).
@ -20,7 +20,6 @@ let () =
@@ Dream.router [ @@ Dream.router [
Dream.get "/static/**" (Dream.static ".") Dream.get "/static/**" (Dream.static ".")
] ]
@@ Dream.not_found
``` ```
<br> <br>
@ -57,7 +56,7 @@ You can replace the file loading behavior of
[crunch](https://github.com/mirage/ocaml-crunch) to compile a directory right [crunch](https://github.com/mirage/ocaml-crunch) to compile a directory right
into your Web app binary, and then serve that directory from memory with into your Web app binary, and then serve that directory from memory with
[`Dream.static`](https://aantron.github.io/dream/#val-static)! See example [`Dream.static`](https://aantron.github.io/dream/#val-static)! See example
[**`w-one-binary`**](../w-one-binary#files). [**`w-one-binary`**](../w-one-binary#folders-and-files).
You can also use `~loader` to set arbitrary headers on the response. You can also use `~loader` to set arbitrary headers on the response.
@ -65,9 +64,9 @@ You can also use `~loader` to set arbitrary headers on the response.
**Next steps:** **Next steps:**
- [**`g-upload`**](../g-upload#files) receives files instead of serving them. - [**`g-upload`**](../g-upload#folders-and-files) receives files instead of serving them.
- [**`h-sql`**](../h-sql#files) runs SQL queries against a database. - [**`h-sql`**](../h-sql#folders-and-files) runs SQL queries against a database.
- [**`w-one-binary`**](../w-one-binary#files) bundles assets into a - [**`w-one-binary`**](../w-one-binary#folders-and-files) bundles assets into a
self-contained binary. self-contained binary.
<br> <br>

View File

@ -1,5 +1,3 @@
(executable (executable
(name static) (name static)
(libraries dream)) (libraries dream))
(data_only_dirs _esy esy.lock)

Some files were not shown because too many files have changed in this diff Show More