package dream
Tidy, feature-complete Web framework
Install
Dune Dependency
Authors
Maintainers
Sources
dream-1.0.0-alpha1.tar.gz
sha256=c8d988568fbbeffb151abdb4d6b903fbd3897842d3eb9b2c28fb350f0f02bbd4
md5=b8ad7f3e30f3e88e5451d92e42b49ce4
doc/src/websocketaf/handshake.ml.html
Source file handshake.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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
module Headers = Httpaf.Headers let create_request ~nonce ~headers target = let nonce = Base64.encode_exn nonce in let headers = Headers.add_list headers [ "upgrade" , "websocket" ; "connection" , "upgrade" ; "sec-websocket-version", "13" ; "sec-websocket-key" , nonce ] in Httpaf.Request.create ~headers `GET target let sec_websocket_key_proof ~sha1 sec_websocket_key = (* From RFC6455§1.3: * For this header field, the server has to take the value (as present * in the header field, e.g., the base64-encoded [RFC4648] version minus * any leading and trailing whitespace) and concatenate this with the * Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA- * 95CA-C5AB0DC85B11" in string form, which is unlikely to be used by * network endpoints that do not understand the WebSocket Protocol. A * SHA-1 hash (160 bits) [FIPS.180-3], base64-encoded (see Section 4 of * [RFC4648]), of this concatenation is then returned in the server's * handshake. *) let concatenation = sec_websocket_key ^ "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" in Base64.encode_exn ~pad:true (sha1 concatenation) (* Copied from headers.ml in http/af. * Compares ASCII strings in a Case Insensitive manner. *) module CI = struct let[@inline always] lower c = if c >= 0x41 && c <= 0x5a then c + 32 else c let equal x y = let len = String.length x in len = String.length y && ( let equal_so_far = ref true in let i = ref 0 in while !equal_so_far && !i < len do let c1 = Char.code (String.unsafe_get x !i) in let c2 = Char.code (String.unsafe_get y !i) in equal_so_far := lower c1 = lower c2; incr i done; !equal_so_far ) end (* TODO: this function can just return the reason *) let passes_scrutiny ~request_method headers = (* From RFC6455§4.2.1: * The client's opening handshake consists of the following parts. If the * server, while reading the handshake, finds that the client did not send * a handshake that matches the description below [...], the server MUST * stop processing the client's handshake and return an HTTP response with * an appropriate error code (such as 400 Bad Request). * * 1. An HTTP/1.1 or higher GET request, including a "Request-URI" * [RFC2616] [...]. * * 2. A |Host| header field containing the server's authority. * * 3. An |Upgrade| header field containing the value "websocket", treated * as an ASCII case-insensitive value. * * 4. A |Connection| header field that includes the token "Upgrade",treated * as an ASCII case-insensitive value. * * 5. A |Sec-WebSocket-Key| header field with a base64-encoded (see Section * 4 of [RFC4648]) value that, when decoded, is 16 bytes in length. * * 6. A |Sec-WebSocket-Version| header field, with a value of 13. * * [...] * * Note: there are 9 points in the above section of the RFC, and the last * 3 refer to optional fields. *) match request_method, Headers.get_exn headers "host", Headers.get_exn headers "upgrade", Headers.get_exn headers "connection", Headers.get_exn headers "sec-websocket-key", Headers.get_exn headers "sec-websocket-version" with (* 1, 2 *) | `GET, _host, upgrade, connection, sec_websocket_key, "13" -> (* 3 *) CI.equal upgrade "websocket" && (* 4 *) (List.exists (fun v -> CI.equal (String.trim v) "upgrade") (String.split_on_char ',' connection)) && (* 5 *) (try String.length (Base64.decode_exn ~pad:true sec_websocket_key) = 16 with | _ -> false) | _ -> false | exception _ -> false let upgrade_headers ~sha1 ~request_method headers = if passes_scrutiny ~request_method headers then begin let sec_websocket_key = Headers.get_exn headers "sec-websocket-key" in let accept = sec_websocket_key_proof ~sha1 sec_websocket_key in let upgrade_headers = [ "Upgrade", "websocket" ; "Connection", "upgrade" ; "Sec-Websocket-Accept", accept ] in Ok upgrade_headers end else Error "Didn't pass scrutiny" let respond_with_upgrade ?(headers=Headers.empty) ~sha1 reqd upgrade_handler = let request = Httpaf.Reqd.request reqd in match upgrade_headers ~sha1 ~request_method:request.meth request.headers with | Ok upgrade_headers -> Httpaf.Reqd.respond_with_upgrade reqd (Headers.add_list headers upgrade_headers) upgrade_handler; Ok () | Error msg -> Error msg
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>