In this example, we use
ppx_yojson_conv to generate a
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:
open Ppx_yojson_conv_lib.Yojson_conv.Primitives
type message_object = {
message : string;
} [@@deriving yojson]
let () =
Dream.run
@@ Dream.logger
@@ Dream.origin_referrer_check
@@ Dream.router [
Dream.post "/"
(fun request ->
let%lwt body = Dream.body request in
let message_object =
body
|> Yojson.Safe.from_string
|> message_object_of_yojson
in
`String message_object.message
|> Yojson.Safe.to_string
|> Dream.json);
]To get this working, we have to add ppx_yojson_conv to our
dune
file:
(executable
(name json)
(libraries dream)
(preprocess (pps lwt_ppx ppx_yojson_conv)))
and to
json.opam:
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "2.0.0"}
"ppx_yojson_conv"
]
The build commands, as always, are:
$ cd example/e-json
$ opam install --deps-only --yes .
$ dune exec --root . ./json.exeThis example expects JSON of the form {"message": "some-message"}. Let's test
it with both curl and HTTPie:
$ curl http://localhost:8080 \
-H "Origin: http://localhost:8080" \
-H "Host: localhost:8080" \
-H "Content-Type: application/json" \
--data '{"message": "foo"}'
"foo"
$ echo '{"message": "foo"}' | \
http POST :8080 Origin:http://localhost:8080 Host:localhost:8080
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: application/json
"foo"
Dream.origin_referrer_check
implements the
OWASP Verifying Origin With Standard Headers
CSRF protection technique. It doesn't protect GET requests, so they shouldn't
do mutations. It also isn't good enough for cross-origin usage in its current
form. But it is enough to do AJAX in small and medium Web apps without the need
for generating tokens.
This technique relies on that the browser will send matching Origin: (or
Referer:) and Host: headers to the Web app for a genuine request, while,
for a cross-site request, Origin: and Host: will not match —
Origin: will be the other site or null. Try varying the headers in the
curl and http commands to see the check in action, rejecting your nefarious
requests!
Next steps:
f-staticserves static files from the local file system.g-uploadreceives files from an upload form.