elixir-mint / mint

Functional HTTP client for Elixir with support for HTTP/1 and HTTP/2 🌱
Apache License 2.0
1.36k stars 112 forks source link

Mint.HTTP1.Response not parsing a valid binary #289

Closed ijunaid8989 closed 3 years ago

ijunaid8989 commented 3 years ago

I am trying to do Basic auth to y-camera which respond as server HTTPD. I started it off as

iex(19)> {:ok, conn} = Mint.HTTP.connect(:http, "93.107.118.128", 8083)                                                                   
{:ok,
 %Mint.HTTP1{
   buffer: "",
   host: "93.107.118.128",
   mode: :active,
   port: 8083,
   private: %{},
   request: nil,
   requests: {[], []},
   scheme_as_string: "http",
   socket: #Port<0.10>,
   state: :open,
   transport: Mint.Core.Transport.TCP
 }}

and

iex(20)> {:ok, conn, request_ref} = Mint.HTTP.request(conn, "GET", "/snapshot.jpg", [{"Authorization", "Basic XXX="}], "")
{:ok,
 %Mint.HTTP1{
   buffer: "",
   host: "93.107.118.128",
   mode: :active,
   port: 8083,
   private: %{},
   request: %{
     body: nil,
     connection: [],
     content_length: nil,
     data_buffer: [],
     headers_buffer: [],
     method: "GET",
     ref: #Reference<0.1988600272.3738697731.204828>,
     state: :status,
     status: nil,
     transfer_encoding: [],
     version: nil
   },
   requests: {[], []},
   scheme_as_string: "http",
   socket: #Port<0.10>,
   state: :open,
   transport: Mint.Core.Transport.TCP
 }, #Reference<0.1988600272.3738697731.204828>}

When I start passing messages to mint as

iex(5)> receive do
...(5)> message when Mint.HTTP.is_connection_message(conn, message) ->
...(5)> Mint.HTTP.stream(conn, message)
...(5)> other ->
...(5)> # This message is related to something else or to some other connection
...(5)> end

at this line https://github.com/elixir-mint/mint/blob/master/lib/mint/http1.ex#L394 in data,

one first receive it gives

"HTTP/1.0 200 OK\r\nServer: HTTPD\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nContent-Type: image/jpeg\r\n\r\n" and on receiving again it gives a binary image in data.

  219, 0, 67, 0, 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
  21, 19, 18, 18, 19, 39, 28, 30, 23, ...>>

but it got failed when it gets passed by decode method.

{:ok,
 %Mint.HTTP1{
   buffer: "",
   host: "93.107.118.128",
   mode: :active,
   port: 8083,
   private: %{},
   request: %{
     body: :until_closed,
     connection: [],
     content_length: nil,
     data_buffer: [[] | ""],
     headers_buffer: [],
     method: "GET",
     ref: #Reference<0.1988600272.3738697731.204828>,
     state: :body,
     status: 200,
     transfer_encoding: [],
     version: {1, 0}
   },
   requests: {[], []},
   scheme_as_string: "http",
   socket: #Port<0.10>,
   state: :open,
   transport: Mint.Core.Transport.TCP
 },
 [
   {:status, #Reference<0.1988600272.3738697731.204828>, 200},
   {:headers, #Reference<0.1988600272.3738697731.204828>,
    [
      {"server", "HTTPD"},
      {"pragma", "no-cache"},
      {"cache-control", "no-cache"},
      {"content-type", "image/jpeg"}
    ]}
 ]}

and on passing message again,

{:error,
 %Mint.HTTP1{
   buffer: "",
   host: "93.107.118.128",
   mode: :active,
   port: 8083,
   private: %{},
   request: %{
     body: nil,
     connection: [],
     content_length: nil,
     data_buffer: [],
     headers_buffer: [],
     method: "GET",
     ref: #Reference<0.1988600272.3738697731.204828>,
     state: :status,
     status: nil,
     transfer_encoding: [],
     version: nil
   },
   requests: {[], []},
   scheme_as_string: "http",
   socket: #Port<0.10>,
   state: :closed,
   transport: Mint.Core.Transport.TCP
 }, %Mint.HTTPError{module: Mint.HTTP1, reason: :invalid_status_line}, []}

I see these results on this line https://github.com/elixir-mint/mint/blob/master/lib/mint/http1/response.ex#L7

IO.inspect(:erlang.decode_packet(:http_bin, binary, []))

This does pass the binary but with an error

{:ok,
 {:http_error,
  <<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0,
    255, 219, 0, 67, 0, 13, 9, 10>>},
 <<11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21, 19, 18, 18, 19, 39,
   28, 30, 23, 32, 46, 41, 49, 48, 46, 41, 45, 44, 51, 58, 74, 62, 51, 54, 70,
   55, 44, 45, 64, 87, 65, 70, 76, 78, ...>>}

the binary being passed is a valid one because I can save it to a file and its an image.

I have tried all the available options from https://erlang.org/doc/man/erlang.html#decode_packet-3

    IO.inspect(:erlang.decode_packet(:http_bin, binary, []))
    IO.inspect(:erlang.decode_packet(:httph_bin, binary, []))
    IO.inspect(:erlang.decode_packet(:httph, binary, []))
    IO.inspect(:erlang.decode_packet(:http, binary, []))
    IO.inspect(:erlang.decode_packet(:raw, binary, []))
    IO.inspect(:erlang.decode_packet(:tpkt, binary, []))
    IO.inspect(:erlang.decode_packet(:line, binary, []))
    IO.inspect(:erlang.decode_packet(:fcgi, binary, []))
    IO.inspect(:erlang.decode_packet(:sunrm, binary, []))
    IO.inspect(:erlang.decode_packet(:cdr, binary, []))
    IO.inspect(:erlang.decode_packet(0, binary, []))
    IO.inspect(:erlang.decode_packet(1, binary, []))
    IO.inspect(:erlang.decode_packet(2, binary, []))
    IO.inspect(:erlang.decode_packet(4, binary, []))

Which results into this

{:ok,
 {:http_error,
  <<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0,
    255, 219, 0, 67, 0, 13, 9, 10>>},
 <<11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21, 19, 18, 18, 19, 39,
   28, 30, 23, 32, 46, 41, 49, 48, 46, 41, 45, 44, 51, 58, 74, 62, 51, 54, 70,
   55, 44, 45, 64, 87, 65, 70, 76, 78, ...>>}
{:ok,
 {:http_error,
  <<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0,
    255, 219, 0, 67, 0, 13, 9, 10>>},
 <<11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21, 19, 18, 18, 19, 39,
   28, 30, 23, 32, 46, 41, 49, 48, 46, 41, 45, 44, 51, 58, 74, 62, 51, 54, 70,
   55, 44, 45, 64, 87, 65, 70, 76, 78, ...>>}
{:ok,
 {:http_error,
  [255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255,
   219, 0, 67, 0, 13, 9, 10]},
 <<11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21, 19, 18, 18, 19, 39,
   28, 30, 23, 32, 46, 41, 49, 48, 46, 41, 45, 44, 51, 58, 74, 62, 51, 54, 70,
   55, 44, 45, 64, 87, 65, 70, 76, 78, ...>>}
{:ok,
 {:http_error,
  [255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255,
   219, 0, 67, 0, 13, 9, 10]},
 <<11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21, 19, 18, 18, 19, 39,
   28, 30, 23, 32, 46, 41, 49, 48, 46, 41, 45, 44, 51, 58, 74, 62, 51, 54, 70,
   55, 44, 45, 64, 87, 65, 70, 76, 78, ...>>}
{:ok,
 <<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255,
   219, 0, 67, 0, 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
   21, 19, 18, 18, 19, 39, 28, ...>>, ""}
{:error, :invalid}
{:ok,
 <<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255,
   219, 0, 67, 0, 13, 9, 10>>,
 <<11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21, 19, 18, 18, 19, 39,
   28, 30, 23, 32, 46, 41, 49, 48, 46, 41, 45, 44, 51, 58, 74, 62, 51, 54, 70,
   55, 44, 45, 64, 87, 65, 70, 76, 78, ...>>}
{:error, :invalid}
{:more, 2144927716}
{:error, :invalid}
{:ok,
 <<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255,
   219, 0, 67, 0, 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
   21, 19, 18, 18, 19, 39, 28, ...>>, ""}
{:ok,
 <<216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255, 219,
   0, 67, 0, 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32, 21,
   19, 18, 18, 19, 39, 28, 30, ...>>,
 <<66, 177, 193, 21, 82, 209, 240, 36, 51, 98, 114, 130, 9, 10, 22, 23, 24, 25,
   26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71,
   72, 73, 74, 83, 84, 85, 86, 87, 88, 89, ...>>}
{:more, 65498}
{:error, :invalid}

the same Basic auth do works in Postman, as well with HTTPoison and Hackney

and return an image, can you guide me?

ijunaid8989 commented 3 years ago

The issue seems to be at this place https://github.com/elixir-mint/mint/blob/master/lib/mint/http1.ex#L394.

the data is already a binary image and don't need passing

ijunaid8989 commented 3 years ago

closing this in favour of https://github.com/keathley/finch/issues/111