Skip to content

Commit 34eedc2

Browse files
committed
Test proxy pool with both http and https
1 parent 002647a commit 34eedc2

File tree

2 files changed

+103
-32
lines changed

2 files changed

+103
-32
lines changed

src/Connections.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,11 @@ function newconnection(wrapconnection::Function,
451451

452452
connection_limit_warning(connection_limit)
453453

454-
key = (url.host, url.port, proxy, require_ssl_verification, keepalive, true)
454+
key = if isnothing(proxy) || IOType == socket_type_tls
455+
(url.host, url.port, proxy, require_ssl_verification, keepalive, true)
456+
else
457+
(URI(proxy).host, URI(proxy).port, nothing, require_ssl_verification, keepalive, true)
458+
end
455459

456460
acquire(
457461
getpool(pool, IOType),
@@ -461,6 +465,9 @@ function newconnection(wrapconnection::Function,
461465

462466
if proxy !== nothing
463467
url = URI(proxy)
468+
if IOType != socket_type_tls
469+
proxy = nothing
470+
end
464471
end
465472

466473
innerIOType = sockettype(url, socket_type, socket_type_tls)
@@ -479,7 +486,7 @@ function newconnection(wrapconnection::Function,
479486
end
480487

481488
if connectionkey(io) != key
482-
throw(ErrorException(string("Connection error ", (;expected = connectionkey(io), key))))
489+
throw(ErrorException(string("Connection error ", (;expected = key, got = connectionkey(io)))))
483490
end
484491

485492
io

test/client.jl

Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -553,52 +553,116 @@ end
553553
end
554554
end
555555

556-
@testset "HTTP CONNECT Proxy pool" begin
557-
# Stores the http request passed by the client
558-
messages = []
559-
streams = Set()
560-
561-
function forwardstream(src, dst)
562-
while isopen(dst) && isopen(src) && !eof(src)
563-
buff = readavailable(src)
564-
!isempty(buff) && isopen(dst) && write(dst, buff)
565-
end
556+
function forwardstream(src, dst)
557+
while isopen(dst) && isopen(src) && !eof(src)
558+
buff = readavailable(src)
559+
!isempty(buff) && isopen(dst) && write(dst, buff)
560+
end
561+
end
566562

567-
close(src)
568-
close(dst)
563+
@testset "HTTP CONNECT Proxy pool" begin
564+
function forwardclosetask(src, dst)
565+
errormonitor(@async begin
566+
forwardstream(src, dst)
567+
close(src)
568+
close(dst)
569+
end)
569570
end
570571

571-
# Simple implementation of a proxy server
572+
# Stores the http message passed by the client
573+
messages = []
574+
upstreams = Set()
575+
576+
# Simple implementation of a https proxy server
572577
proxy = HTTP.listen!(IPv4(0), 8082; stream = true) do http::HTTP.Stream
573578
push!(messages, http.message)
574-
host, port = split(http.message.target, ":")
575-
targetstream = connect(host, parse(Int, port))
576-
HTTP.setstatus(http, 200)
577-
HTTP.startwrite(http)
578-
up = @async forwardstream(http.stream.io, targetstream)
579-
down = @async forwardstream(targetstream, http.stream.io)
580-
push!(streams, targetstream)
581-
wait(up)
582-
wait(down)
583-
delete!(streams, targetstream)
579+
580+
hostport = split(http.message.target, ":")
581+
targetstream = connect(hostport[1], parse(Int, get(hostport, 2, "443")))
582+
push!(upstreams, targetstream)
583+
try
584+
HTTP.setstatus(http, 200)
585+
HTTP.startwrite(http)
586+
up = forwardclosetask(http.stream.io, targetstream)
587+
down = forwardclosetask(targetstream, http.stream.io)
588+
589+
wait(up)
590+
wait(down)
591+
finally
592+
delete!(upstreams, targetstream)
593+
end
584594
end
585595

586596
try
587597
# Make the HTTP request
588-
r1 = HTTP.get("https://example.com:443"; proxy="http://localhost:8082", retry=false, status_exception=true)
598+
r1 = HTTP.get("https://$httpbin/ip"; proxy="http://localhost:8082", retry=false, status_exception=true)
589599
@test length(messages) == 1
590600
@test first(messages).method == "CONNECT"
591-
@test length(streams) == 1 && isopen(first(streams)) # still alive
601+
@test length(upstreams) == 1 && isopen(first(upstreams)) # still alive
592602

593603
# Make another request
594604
# This should reuse the connection pool and not make another request to the proxy
595605
empty!(messages)
596-
r2 = HTTP.get("https://example.com:443"; proxy="http://localhost:8082", retry=false, status_exception=true)
597-
@test isempty(messages)
598-
@test r1.body == r2.body # no new message to the proxy yet successfully get the same response from the target server
599-
@test length(streams) == 1 && isopen(first(streams)) # still only one stream alive
606+
r2 = HTTP.get("https://$httpbin/ip"; proxy="http://localhost:8082", retry=false, status_exception=true)
607+
@test isempty(messages) # no new message to the proxy
608+
@test length(upstreams) == 1 && isopen(first(upstreams)) # still only one stream alive
609+
finally
610+
close.(upstreams)
611+
close(proxy)
612+
HTTP.Connections.closeall()
613+
wait(proxy)
614+
end
615+
end
616+
617+
@testset "HTTP Proxy pool" begin
618+
# Stores the http request passed by the client
619+
downstreamconnections = Set{HTTP.Connections.Connection}()
620+
upstreamconnections = Set{HTTP.Connections.Connection}()
621+
finished_request = Base.Event(true)
622+
623+
# Simple implementation of a http proxy server
624+
proxy = HTTP.listen!(IPv4(0), 8082; stream = true) do http::HTTP.Stream
625+
push!(downstreamconnections, http.stream)
626+
627+
HTTP.open(http.message.method, http.message.target, http.message.headers;
628+
decompress = false, version = http.message.version, retry=false,
629+
redirect = false) do targetstream
630+
push!(upstreamconnections, targetstream.stream)
631+
632+
up = errormonitor(@async forwardstream(http, targetstream))
633+
targetresponse = startread(targetstream)
634+
635+
HTTP.setstatus(http, targetresponse.status)
636+
for h in targetresponse.headers
637+
HTTP.setheader(http, h)
638+
end
639+
640+
HTTP.startwrite(http)
641+
down = errormonitor(@async forwardstream(targetstream, http))
642+
643+
wait(up)
644+
wait(down)
645+
646+
notify(finished_request)
647+
end
648+
end
649+
650+
try
651+
# Make the HTTP request
652+
r1 = HTTP.get("http://$httpbin/ip"; proxy="http://localhost:8082", retry=false, redirect = false, status_exception=true)
653+
wait(finished_request)
654+
@test length(downstreamconnections) == 1
655+
@test length(upstreamconnections) == 1
656+
657+
# Make another request
658+
# This should reuse a connection pool in both the client and proxy
659+
r2 = HTTP.get("http://$httpbin/ip"; proxy="http://localhost:8082", retry=false, redirect = false, status_exception=true)
660+
661+
# Check that notify was actually called, but that the set of connections remains of size 1
662+
wait(finished_request)
663+
@test length(downstreamconnections) == 1
664+
@test length(upstreamconnections) == 1
600665
finally
601-
close.(streams)
602666
close(proxy)
603667
HTTP.Connections.closeall()
604668
wait(proxy)

0 commit comments

Comments
 (0)