package dream

  1. Overview
  2. Docs

Source file origin_referrer_check.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(* This file is part of Dream, released under the MIT license. See LICENSE.md
   for details, or visit https://github.com/aantron/dream.

   Copyright 2021 Anton Bachin *)



module Message = Dream_pure.Message
module Stream = Dream_pure.Stream



let log =
  Log.sub_log "dream.origin"

(* TODO Rename all next_handler to inner_handler. *)
let origin_referrer_check inner_handler request =

  match Message.method_ request with
  | `GET | `HEAD ->
    inner_handler request

  | _ ->
    let origin =
      match Message.header request "Origin" with
      | Some "null" | None -> Message.header request "Referer"
      | Some _ as origin -> origin
    in

    match origin with
    | None ->
      log.warning (fun log -> log ~request
        "Origin and Referer headers both missing");
      Message.response ~status:`Bad_Request Stream.empty Stream.null
      |> Lwt.return

    (* TODO Also recommend Uri to users. *)
    | Some origin ->

      match Message.header request "Host" with
      | None ->
        log.warning (fun log -> log ~request "Host header missing");
        Message.response ~status:`Bad_Request Stream.empty Stream.null
        |> Lwt.return

      | Some host ->

        let origin_uri = Uri.of_string origin in

        let schemes_match =
          match Uri.scheme origin_uri with
          | Some "http" -> not (Helpers.tls request)
          | Some "https" -> Helpers.tls request
          | _ -> false
        in

        let host_host, host_port =
          match String.split_on_char ':' host with
          | [host; port] -> Some host, Some port
          | _ -> Some host, None
        in

        let origin_port =
          match Uri.port origin_uri with
          | None -> None
          | Some port -> Some (string_of_int port)
        in

        let hosts_match = Uri.host origin_uri = host_host
        and ports_match = origin_port = host_port in

        if schemes_match && hosts_match && ports_match then
          inner_handler request

        else begin
          log.warning (fun log -> log ~request
            "Origin-Host mismatch: '%s' vs. '%s'" origin host);
          Message.response ~status:`Bad_Request Stream.empty Stream.null
          |> Lwt.return
        end
OCaml

Innovation. Community. Security.