From 8076ea4316ef42d70ec82e228c48beac1b2d405d Mon Sep 17 00:00:00 2001 From: Michael Ries Date: Sat, 15 Oct 2022 10:43:38 +0100 Subject: [PATCH] parse status and description from headers --- lib/gnat/parsec.ex | 20 +++++++++++++++++--- test/gnat/parsec_test.exs | 16 ++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lib/gnat/parsec.ex b/lib/gnat/parsec.ex index 4f31662..552264e 100644 --- a/lib/gnat/parsec.ex +++ b/lib/gnat/parsec.ex @@ -115,9 +115,23 @@ defmodule Gnat.Parsec do def parse_headers("NATS/1.0" <> rest) do case String.split(rest, "\r\n", parts: 2) do + [" " <> status, headers] -> + + case :cow_http.parse_headers(headers) do + {parsed, ""} -> + case String.split(status, " ", parts: 2) do + [status, description] -> + {:ok, status, description, parsed} + [status] -> + {:ok, status, nil, parsed} + end + + _other -> + {:error, "Could not parse headers"} + end [_status_line, headers] -> case :cow_http.parse_headers(headers) do - {parsed, ""} -> {:ok, parsed} + {parsed, ""} -> {:ok, nil, nil, parsed} _other -> {:error, "Could not parse headers"} end _other -> @@ -142,8 +156,8 @@ defmodule Gnat.Parsec do payload_length = total_length - header_length case rest do << headers::size(header_length)-binary, payload::size(payload_length)-binary, "\r\n", rest::binary>> -> - {:ok, headers} = parse_headers(headers) - {:ok, {:hmsg, subject, sid, reply_to, headers, payload}, rest} + {:ok, status, description, headers} = parse_headers(headers) + {:ok, {:hmsg, subject, sid, reply_to, status, description, headers, payload}, rest} _other -> {:error, string} end diff --git a/test/gnat/parsec_test.exs b/test/gnat/parsec_test.exs index 6d39f21..1499c33 100644 --- a/test/gnat/parsec_test.exs +++ b/test/gnat/parsec_test.exs @@ -39,7 +39,7 @@ defmodule Gnat.ParsecTest do {state, [parsed]} = Parsec.new() |> Parsec.parse(binary) assert state.partial == nil - assert parsed == {:hmsg, "SUBJECT", 1, nil, [{"header", "X"}], "PAYLOAD"} + assert parsed == {:hmsg, "SUBJECT", 1, nil, nil, nil, [{"header", "X"}], "PAYLOAD"} end test "parsing messages with headers - single header" do @@ -47,7 +47,7 @@ defmodule Gnat.ParsecTest do {state, [parsed]} = Parsec.new() |> Parsec.parse(binary) assert state.partial == nil - assert parsed == {:hmsg, "SUBJECT", 1, "REPLY",[{"header", "X"}], "PAYLOAD"} + assert parsed == {:hmsg, "SUBJECT", 1, "REPLY", nil, nil, [{"header", "X"}], "PAYLOAD"} end # This example comes from https://github.com/nats-io/nats-architecture-and-design/blob/cb8f68af6ba730c00a6aa174dedaa217edd9edc6/adr/ADR-9.md @@ -56,7 +56,7 @@ defmodule Gnat.ParsecTest do {state, [parsed]} = Parsec.new() |> Parsec.parse(binary) assert state.partial == nil - assert parsed == {:hmsg, "my.messages", 2, nil,[{"nats-last-consumer", "0"}, {"nats-last-stream", "0"}], ""} + assert parsed == {:hmsg, "my.messages", 2, nil, "100", "Idle Heartbeat", [{"nats-last-consumer", "0"}, {"nats-last-stream", "0"}], ""} end # This example comes from https://github.com/nats-io/nats-architecture-and-design/blob/682d5cd5f21d18502da70025727128a407655250/adr/ADR-13.md @@ -65,7 +65,15 @@ defmodule Gnat.ParsecTest do {state, [parsed]} = Parsec.new() |> Parsec.parse(binary) assert state.partial == nil - assert parsed == {:hmsg, "_INBOX.x7tkDPDLCOEknrfB4RH1V7.OgY4M7", 2, nil, [], ""} + assert parsed == {:hmsg, "_INBOX.x7tkDPDLCOEknrfB4RH1V7.OgY4M7", 2, nil, "404", "No Messages", [], ""} + end + + test "parsing no_responders messages" do + binary = "HMSG _INBOX.10ahfXw89Nx5htVf.7Il73yuah/RHW6w8 0 16 16\r\nNATS/1.0 503\r\n\r\n\r\n" + + {state, [parsed]} = Parsec.new() |> Parsec.parse(binary) + assert state.partial == nil + assert parsed == {:hmsg, "_INBOX.10ahfXw89Nx5htVf.7Il73yuah/RHW6w8", 0, nil, "503", nil, [], ""} end test "parsing PING message" do