Skip to content

Commit

Permalink
parse status and description from headers
Browse files Browse the repository at this point in the history
  • Loading branch information
mmmries committed Oct 16, 2022
1 parent 34cf645 commit 8076ea4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 7 deletions.
20 changes: 17 additions & 3 deletions lib/gnat/parsec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand All @@ -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
Expand Down
16 changes: 12 additions & 4 deletions test/gnat/parsec_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ 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
binary = "HMSG SUBJECT 1 REPLY 23 30\r\nNATS/1.0\r\nHeader: X\r\n\r\nPAYLOAD\r\n"

{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
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 8076ea4

Please sign in to comment.