Skip to content

Commit

Permalink
Some fixes for HTTP/2 protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
quinnj committed Jun 21, 2024
1 parent b057b50 commit f3b3264
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 31 deletions.
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ uuid = "b77c38ae-d26b-ff15-6dc9-5bc94be9e2a6"
version = "1.0.0"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
LibAwsCommon = "c6e421ba-b5f8-4792-a1c4-42948de3ed9d"
LibAwsHTTP = "ce851869-0d7a-41e7-95ef-2d4cb63876dd"
Expand Down
18 changes: 10 additions & 8 deletions src/HTTP2.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module HTTP2

using CodecZlib, URIs, Mmap
using CodecZlib, URIs, Mmap, Base64
using LibAwsCommon, LibAwsIO, LibAwsHTTP

include("utils.jl")
Expand All @@ -10,6 +10,7 @@ const Context = Dict{Symbol, Any}

mutable struct Request
method::String
version::String
uri::URI
_uri::aws_uri
headers::Headers
Expand All @@ -30,13 +31,13 @@ mutable struct Request
aws_uri_init_parse(uri_ref, allocator, url_ref)
end
_uri = uri_ref[]
return new(String(method), makeuri(_uri), _uri, something(headers, Header[]), body, ctx)
return new(String(method), "", makeuri(_uri), _uri, something(headers, Header[]), body, ctx)
end
Request() = new()
end

Base.getproperty(x::Request, s::Symbol) = s == :url || s == :target ? x.uri : getfield(x, s)
print_request(io::IO, r::Request) = print_request(io, r.method, r.uri.path, r.headers, r.body)
print_request(io::IO, r::Request) = print_request(io, r.method, r.version, r.uri.path, r.headers, r.body)
function Base.show(io::IO, r::Request)
println(io, "HTTP2.Request:")
print_request(io, r)
Expand All @@ -63,16 +64,17 @@ RequestMetrics() = RequestMetrics(0, 0, 0, nothing)

mutable struct Response
status::Int
version::String
headers::Headers
body::Any # IO or Vector{UInt8}
metrics::RequestMetrics
end

Response(body=UInt8[]) = Response(0, Header[], body, RequestMetrics())
Response(status::Integer, body) = Response(status, Header[], Vector{UInt8}(string(body)), RequestMetrics())
Response(status::Integer) = Response(status, Header[], Vector{UInt8}(), RequestMetrics())
Response(body=UInt8[]) = Response(0, "", Header[], body, RequestMetrics())
Response(status::Integer, body) = Response(status, "", Header[], Vector{UInt8}(string(body)), RequestMetrics())
Response(status::Integer) = Response(status, "", Header[], Vector{UInt8}(), RequestMetrics())

print_response(io::IO, r::Response) = print_response(io, r.status, r.headers, r.body)
print_response(io::IO, r::Response) = print_response(io, r.status, r.version, r.headers, r.body)
function Base.show(io::IO, r::Response)
println(io, "HTTP2.Response:")
print_response(io, r)
Expand Down Expand Up @@ -307,7 +309,7 @@ function __init__()
# initialize logger
LOGGER[] = aws_mem_acquire(allocator, 64)
LOGGER_FILE_REF[] = Libc.FILE(Libc.RawFD(1), "w")
LOGGER_OPTIONS[] = aws_logger_standard_options(aws_log_level(2), C_NULL, Ptr{Libc.FILE}(LOGGER_FILE_REF[].ptr))
LOGGER_OPTIONS[] = aws_logger_standard_options(aws_log_level(3), C_NULL, Ptr{Libc.FILE}(LOGGER_FILE_REF[].ptr))
@assert aws_logger_init_standard(LOGGER[], allocator, LOGGER_OPTIONS) == 0
aws_logger_set(LOGGER[])
# intialize c functions
Expand Down
40 changes: 21 additions & 19 deletions src/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,18 @@ function c_on_setup(conn, error_code, ctx_ptr)
ctx.verbose >= 1 && @info "building request: $(ctx.request.uri.host)"
ctx.connection = conn
protocol_version = aws_http_connection_get_version(conn)
ctx.response.version = protocol_version == AWS_HTTP_VERSION_2 ? "2" : protocol_version == AWS_HTTP_VERSION_1_1 ? "1.1" : "1.0"
ctx.request.version = ctx.response.version
# build up request headers
headers = ctx.request.headers
headers = Headers()
path = resource(ctx.request.uri)
if protocol_version == AWS_HTTP_VERSION_2
# set scheme
setheader(headers, ":scheme", ctx.request.uri.scheme)
# set authority
setheader(headers, ":authority", ctx.request.uri.host)
else
# set host
setheader(headers, "host", ctx.request.uri.host)
end
# setheader(headers, "host", ctx.request.uri.host)
# accept header
if !hasheader(headers, "accept")
setheader(headers, "accept", "*/*")
Expand All @@ -100,9 +101,18 @@ function c_on_setup(conn, error_code, ctx_ptr)
setheader(headers, "user-agent", USER_AGENT[])
end
# accept-encoding
if ctx.decompress === nothing || ctx.decompress
setheader(headers, "accept-encoding", "gzip")
# if ctx.decompress === nothing || ctx.decompress
# setheader(headers, "accept-encoding", "gzip")
# end
# basic auth if present
if !isempty(ctx.request.uri.userinfo)
setheader(headers, "authorization", "Basic $(base64encode(ctx.request.uri.userinfo))")
end
# add any user-provided headers
for header in ctx.request.headers
push!(headers, lowercase(string(header[1])) => string(header[2]))
end
ctx.request.headers = headers
# process request body if present
input_stream = make_input_stream(ctx)
# call a user-provided modifier function (if provided)
Expand All @@ -127,21 +137,13 @@ function c_on_setup(conn, error_code, ctx_ptr)
Threads.notify(ctx.completed)
return
end
path = resource(ctx.request.uri)
if protocol_version == AWS_HTTP_VERSION_2
# set method
setheader(headers, ":method", ctx.request.method)
# set path
setheader(headers, ":path", path)
else
# set method
aws_http_message_set_request_method(request, aws_byte_cursor_from_c_str(ctx.request.method))
# set path
aws_http_message_set_request_path(request, aws_byte_cursor_from_c_str(path))
end
# set method
aws_http_message_set_request_method(request, aws_byte_cursor_from_c_str(ctx.request.method))
# set path
aws_http_message_set_request_path(request, aws_byte_cursor_from_c_str(path))
# add headers to request
for (k, v) in headers
header = aws_http_header(aws_byte_cursor_from_c_str(string(k)), aws_byte_cursor_from_c_str(string(v)), AWS_HTTP_HEADER_COMPRESSION_USE_CACHE)
header = aws_http_header(aws_byte_cursor_from_c_str(k), aws_byte_cursor_from_c_str(v), AWS_HTTP_HEADER_COMPRESSION_USE_CACHE)
aws_http_message_add_header(request, header)
end
# set body from input_stream if present
Expand Down
8 changes: 4 additions & 4 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ resource(uri::URI) = string( isempty(uri.path) ? "/" : uri.path,
!isempty(uri.query) ? "?" : "", uri.query,
!isempty(uri.fragment) ? "#" : "", uri.fragment)

function print_request(io, method, path, headers, body)
function print_request(io, method, version, path, headers, body)
write(io, "\"\"\"\n")
write(io, string(method, " ", path, " HTTP/1.1\r\n"))
write(io, string(method, " ", path, " HTTP/$version\r\n"))
for h in headers
write(io, string(h.first, ": ", h.second, "\r\n"))
end
Expand All @@ -57,9 +57,9 @@ function print_request(io, method, path, headers, body)
return
end

function print_response(io, status, headers, body)
function print_response(io, status, version, headers, body)
write(io, "\"\"\"\n")
write(io, string("HTTP/1.1 ", status, "\r\n"))
write(io, string("HTTP/$version ", status, "\r\n"))
for h in headers
write(io, string(h.first, ": ", h.second, "\r\n"))
end
Expand Down

0 comments on commit f3b3264

Please sign in to comment.