From 88b503761ed15a64d533f620e9c1734dfb5a64e2 Mon Sep 17 00:00:00 2001 From: Ulugbek Abdullaev Date: Fri, 27 Nov 2020 13:29:00 +0500 Subject: [PATCH] [wip] implement capability advertisement decoding that is sent by the server on initial contact with client --- src/not-so-smart/capability_v2.ml | 44 ++++++++++++++++++++++ src/not-so-smart/capability_v2.mli | 13 +++++++ src/not-so-smart/dune | 6 +++ src/not-so-smart/protocol_v2.ml | 60 ++++++++++++++++++++++++++++++ src/not-so-smart/protocol_v2.mli | 8 ++++ 5 files changed, 131 insertions(+) create mode 100644 src/not-so-smart/capability_v2.ml create mode 100644 src/not-so-smart/capability_v2.mli create mode 100644 src/not-so-smart/protocol_v2.ml create mode 100644 src/not-so-smart/protocol_v2.mli diff --git a/src/not-so-smart/capability_v2.ml b/src/not-so-smart/capability_v2.ml new file mode 100644 index 000000000..bf9b32199 --- /dev/null +++ b/src/not-so-smart/capability_v2.ml @@ -0,0 +1,44 @@ +open Astring + +type t = + [ `Shallow + | `Filter + | `Ref_in_want + | `Sideband_all + | `Packfile_uris + | `Unknown of string + | `Unknown_with_param of string * string ] + +let to_string = function + | `Shallow -> "shallow" + | `Ref_in_want -> "ref-in-want" + | `Sideband_all -> "sideband-all" + | `Filter -> "filter" + | `Packfile_uris -> "packfile-uris" + | `Unknown s -> s + | `Unknown_with_param (k, v) -> Fmt.str "%s=%s" k v + +let of_string ?value = function + | "shallow" -> `Shallow + | "ref-in-want" -> `Ref_in_want + | "sideband-all" -> `Sideband_all + | "filter" -> `Filter + | "packfile-uris" -> `Packfile_uris + | c -> ( + assert (not (String.is_empty c)); + match value with + | None -> `Unknown c + | Some "" -> assert false + | Some v -> `Unknown_with_param (c, v) ) + +let pp = Fmt.of_to_string to_string + +let equal t1 t2 = + match t1, t2 with + | `Shallow, `Shallow + | `Filter, `Filter + | `Ref_in_want, `Ref_in_want + | `Sideband_all, `Sideband_all + | `Packfile_uris, `Packfile_uris -> + true + | _, _ -> false diff --git a/src/not-so-smart/capability_v2.mli b/src/not-so-smart/capability_v2.mli new file mode 100644 index 000000000..b9ddc8031 --- /dev/null +++ b/src/not-so-smart/capability_v2.mli @@ -0,0 +1,13 @@ +type t = + [ `Shallow + | `Filter + | `Ref_in_want + | `Sideband_all + | `Packfile_uris + | `Unknown of string + | `Unknown_with_param of string * string ] + +val to_string : t -> string +val of_string : ?value:string -> string -> t +val pp : t Fmt.t +val equal : t -> t -> bool diff --git a/src/not-so-smart/dune b/src/not-so-smart/dune index 250b5a0d0..20416dfdf 100644 --- a/src/not-so-smart/dune +++ b/src/not-so-smart/dune @@ -42,3 +42,9 @@ (libraries ipaddr decompress.de decompress.zl cstruct logs astring result rresult bigstringaf fmt emile conduit lwt domain-name uri sigs smart pck nss digestif carton carton-lwt)) + +(library + (name git_proto_v2) + (public_name git-nss.git-wire-proto-v2) + (modules capability_v2 protocol_v2) + (libraries astring git-nss.pkt-line fmt)) diff --git a/src/not-so-smart/protocol_v2.ml b/src/not-so-smart/protocol_v2.ml new file mode 100644 index 000000000..1f6906697 --- /dev/null +++ b/src/not-so-smart/protocol_v2.ml @@ -0,0 +1,60 @@ +open Astring + +module Decoder = struct + open Pkt_line.Decoder + + type nonrec error = [ error | `Expected_protocol_version ] + type 'a t = decoder -> ('a, error) state + + (* let v_space = String.Sub.of_string " " *) + let v_version2 = String.Sub.of_string "version 2" + let v_flush_pkt = String.Sub.of_string "0000" + let is_flush_pkt = String.Sub.equal v_flush_pkt + let is_new_line = function '\n' -> true | _ -> false + + let peek_pkt ?(trim = true) decoder = + let buf, off, len = peek_pkt decoder in + let buf = Bytes.to_string buf in + let res = String.Sub.v buf ~start:off ~stop:(off + len) in + if trim then String.Sub.trim ~drop:is_new_line res else res + + let rec prompt_pkt ?strict k decoder = + if at_least_one_pkt decoder then k decoder + else prompt ?strict (prompt_pkt ?strict k) decoder + + (* + capability-advertisement = protocol-version + capability-list + flush-pkt + *) + let decode_capability_ad decoder = + (* capability = PKT-LINE(key[=value] LF) + + key = 1*(ALPHA | DIGIT | "-") + value = 1*(ALPHA | DIGIT | " -_.,?\/{}[]()<>!@#$%^&*+=:;") *) + let parse_capability s = + let s = String.Sub.to_string s in + match String.cut s ~sep:"=" with + | None -> Capability_v2.of_string s + | Some (key, value) -> Capability_v2.of_string key ~value + in + + (* capability-list = *capability *) + let rec decode_capability_list capabilities decoder = + let v = peek_pkt decoder in + if is_flush_pkt v then return capabilities decoder + else + let cap = parse_capability v in + prompt_pkt (decode_capability_list (cap :: capabilities)) decoder + in + + (* protocol-version = PKT-LINE("version 2" LF) *) + let decode_protocol_version decoder = + let v = peek_pkt decoder in + if String.Sub.equal v v_version2 then + prompt_pkt (decode_capability_list []) decoder + else fail decoder `Expected_protocol_version + in + + decode_protocol_version decoder +end diff --git a/src/not-so-smart/protocol_v2.mli b/src/not-so-smart/protocol_v2.mli new file mode 100644 index 000000000..898b2c86d --- /dev/null +++ b/src/not-so-smart/protocol_v2.mli @@ -0,0 +1,8 @@ +module Decoder : sig + open Pkt_line.Decoder + + type nonrec error = [ error | `Expected_protocol_version ] + type 'a t = decoder -> ('a, error) state + + val decode_capability_ad : Capability_v2.t list t +end