Packages
pigeon
0.4.1
2.0.1
2.0.0
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.1.0-rc.1
1.1.0-rc.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.0
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
iOS (APNS), Android (FCM), and Amazon Android (ADM) push notifications for Elixir.
Current section
Files
Jump to
Current section
Files
lib/http2_study_client.ex
defmodule Http2StudyClient do
require Logger
@moduledoc """
http2study
"""
@doc "GET HTTP/2.0"
def get domain, port do
{:ok, sock} = :gen_tcp.connect domain, port, [:binary, {:packet, 0}]
IO.inspect sock
try do
{:ok, data} = send_connection_preface sock
IO.inspect data
#{:ok, data} = establish_connection sock
#IO.inspect data
{:ok, data} = send_get_request sock
IO.inspect data
:ok = send_goaway sock
after
:ok = :gen_tcp.close sock
end
end
def get_ssl domain, port do
:ssl.start()
{:ok, socket} = :gen_tcp.connect domain, port, [:binary, {:packet, 0}]
options = [{:mode, :binary}, {:reuse_sessions, false}, {:packet, 0}]
{:ok, sock} = :ssl.connect(socket, options)
{:sslsocket, socket, pid} = sock
{:gen_tcp, tcp_pid, :tls_connection, :undefined} = socket
try do
IO.inspect sock
{:ok, data} = send_connection_preface_ssl sock
IO.inspect data
{:ok, data} = establish_connection sock
IO.inspect data
{:ok, data} = send_get_request sock
IO.inspect data
:ok = send_goaway sock
after
:ok = :ssl.close sock
end
end
defp establish_connection sock do
{:ok, data} = send_settings sock
IO.inspect data
unless data = build_frame(0x01, 0, 0, <<>>) do
{:error, "Can't establish a connection."}
else
send_ack sock
end
end
defp send_connection_preface_ssl sock do
IO.puts "Sending SSL connection preface"
:ssl.send sock, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
case do_receive_once(sock) do
{:ok, data} ->
if Regex.match?(~r/^HTTP\//, data) do
{:error, "not supported."}
else
{:ok, data}
end
x -> x
end
end
defp send_connection_preface sock do
IO.puts "Sending connection preface"
:gen_tcp.send sock, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
case do_receive_ssl(sock) do
{:ok, data} ->
if Regex.match?(~r/^HTTP\//, data) do
{:error, "not supported."}
else
{:ok, data}
end
x -> x
end
end
defp send_settings sock do
IO.puts "Sending SETTINGS"
:gen_tcp.send sock, build_frame(0x4, 0, 0, <<>>)
do_receive_once sock
end
defp send_ack sock do
IO.puts "Sending ACK"
:gen_tcp.send sock, build_frame(0x01, 0, 0, <<>>)
do_receive_once sock
end
defp send_goaway sock do
IO.puts "Sending GOAWAY"
no_error = 0
:gen_tcp.send sock, build_frame(0x7, 0, 0, <<no_error::32>>)
:gen_tcp.close sock
end
defp send_get_request sock do
IO.puts "Sending GET request"
end_headers = 0x4
:gen_tcp.send sock, build_frame(0x1, end_headers, 1, <<
<<0::1, 0::1, 0::1, 1::1, 0::4, 0::1, byte_size("scheme")::7, "scheme", 0::1, byte_size("http")::7, "http">>,
<<0::1, 0::1, 0::1, 1::1, 0::4, 0::1, byte_size("authority")::7, "authority", 0::1, byte_size("nghttp2.org")::7, "nghttp2.org">>,
<<0::1, 0::1, 0::1, 1::1, 0::4, 0::1, byte_size("path")::7, "path", 0::1, byte_size("/httpbin/")::7, "/httpbin/">>,
<<0::1, 0::1, 0::1, 1::1, 0::4, 0::1, byte_size("method")::7, "method", 0::1, byte_size("GET")::7, "GET">>
>>)
do_receive_once sock
end
defp build_frame frame_type, flags, stream_id, payload do
header = <<0::2, byte_size(payload)::14, frame_type::8, flags::8, 0::1, stream_id::31>>
IO.inspect header
<<header::binary, payload::binary>>
end
defp do_receive_ssl sock do
receive do
{:tcp, sock, bin} ->
{:ok, bin}
after
5000 ->
{:error, "timeout."}
end
end
defp do_receive_once sock do
receive do
{:tcp, sock, bin} ->
IO.inspect to_string(bin)
<<0::2, payload_size::14, frame_type::8, flags::8, 0::1, stream_id::31, payload::binary>> = bin
case frame_type do
0x3 ->
<<error_code::32, _::binary>> = payload
{:error, "RST_STREAM error_code:#{error_code}"}
0x7 ->
<<error_code::32, _::binary>> = payload
{:error, "GOAWAY error_code:#{error_code}"}
_ ->
{:ok, bin}
end
{:ssl_closed, sock} ->
{:error, "closed."}
{:ssl_error, sock, reason} ->
{:error, reason}
whatever ->
IO.inspect whatever
after
5000 ->
{:error, "timeout."}
end
end
# defp do_receive_response sock, header \\ [], body \\ [] do
# end
end