parse.ex (2514B)
1 defmodule Mint.HTTP1.Parse do 2 @moduledoc false 3 4 alias Mint.Core.Util 5 6 defmacro is_digit(char), do: quote(do: unquote(char) in ?0..?9) 7 defmacro is_alpha(char), do: quote(do: unquote(char) in ?a..?z or unquote(char) in ?A..?Z) 8 defmacro is_whitespace(char), do: quote(do: unquote(char) in '\s\t') 9 defmacro is_comma(char), do: quote(do: unquote(char) == ?,) 10 defmacro is_vchar(char), do: quote(do: unquote(char) in 33..126) 11 12 defmacro is_tchar(char) do 13 quote do 14 is_digit(unquote(char)) or is_alpha(unquote(char)) or unquote(char) in '!#$%&\'*+-.^_`|~' 15 end 16 end 17 18 def ignore_until_crlf(<<>>), do: :more 19 def ignore_until_crlf(<<"\r\n", rest::binary>>), do: {:ok, rest} 20 def ignore_until_crlf(<<_char, rest::binary>>), do: ignore_until_crlf(rest) 21 22 def content_length_header(string) do 23 case Integer.parse(String.trim_trailing(string)) do 24 {length, ""} when length >= 0 -> {:ok, length} 25 _other -> {:error, {:invalid_content_length_header, string}} 26 end 27 end 28 29 def connection_header(string) do 30 split_into_downcase_tokens(string) 31 end 32 33 def transfer_encoding_header(string) do 34 split_into_downcase_tokens(string) 35 end 36 37 defp split_into_downcase_tokens(string) do 38 case token_list_downcase(string) do 39 {:ok, []} -> {:error, :empty_token_list} 40 {:ok, list} -> {:ok, list} 41 :error -> {:error, {:invalid_token_list, string}} 42 end 43 end 44 45 # Made public for testing. 46 def token_list_downcase(string), do: token_list_downcase(string, []) 47 48 defp token_list_downcase(<<>>, acc), do: {:ok, :lists.reverse(acc)} 49 50 # Skip all whitespace and commas. 51 defp token_list_downcase(<<char, rest::binary>>, acc) 52 when is_whitespace(char) or is_comma(char), 53 do: token_list_downcase(rest, acc) 54 55 defp token_list_downcase(rest, acc), do: token_downcase(rest, _token_acc = <<>>, acc) 56 57 defp token_downcase(<<char, rest::binary>>, token_acc, acc) when is_tchar(char), 58 do: token_downcase(rest, <<token_acc::binary, Util.downcase_ascii_char(char)>>, acc) 59 60 defp token_downcase(rest, token_acc, acc), do: token_list_sep_downcase(rest, [token_acc | acc]) 61 62 defp token_list_sep_downcase(<<>>, acc), do: {:ok, :lists.reverse(acc)} 63 64 defp token_list_sep_downcase(<<char, rest::binary>>, acc) when is_whitespace(char), 65 do: token_list_sep_downcase(rest, acc) 66 67 defp token_list_sep_downcase(<<char, rest::binary>>, acc) when is_comma(char), 68 do: token_list_downcase(rest, acc) 69 70 defp token_list_sep_downcase(_rest, _acc), do: :error 71 end