Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unsafe_write requires iswritable(::SSLContext) #614

Closed
msavael opened this issue Nov 2, 2020 · 3 comments
Closed

unsafe_write requires iswritable(::SSLContext) #614

msavael opened this issue Nov 2, 2020 · 3 comments

Comments

@msavael
Copy link

msavael commented Nov 2, 2020

I'm meeting the following when doing multi-threaded HTTPS requests:

Julia 1.5.2
HTTP v0.8.19
MbedTLS v1.0.2

ERROR: TaskFailedException:
ArgumentError: `unsafe_write` requires `iswritable(::SSLContext)`
Stacktrace:
 [1] request(::Type{HTTP.StreamRequest.StreamLayer{Union{}}}, ::HTTP.ConnectionPool.Transaction{MbedTLS.SSLContext}, ::HTTP.Messages.Request, ::String; reached_redirect_limit::Bool, response_stream::Nothing, iofunction::Nothing, verbose::Int64, kw::Base.Iterators.Pairs{Symbol,Any,Tuple{Symbol,Symbol},NamedTuple{(:sslconfig, :retry),Tuple{MbedTLS.SSLConfig,Bool}}}) at ~/.julia/packages/HTTP/IAI92/src/StreamRequest.jl:83
 [2] request(::Type{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}, ::HTTP.URIs.URI, ::HTTP.Messages.Request, ::String; proxy::Nothing, socket_type::Type{T} where T, reuse_limit::Int64, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:iofunction, :reached_redirect_limit, :sslconfig, :retry, :verbose),Tuple{Nothing,Bool,MbedTLS.SSLConfig,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/ConnectionRequest.jl:96
 [3] request(::Type{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}, ::HTTP.URIs.URI, ::Vararg{Any,N} where N; kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:iofunction, :reached_redirect_limit, :sslconfig, :retry, :verbose),Tuple{Nothing,Bool,MbedTLS.SSLConfig,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/ExceptionRequest.jl:19
 [4] (::Base.var"#56#58"{Base.var"#56#57#59"{ExponentialBackOff,HTTP.RetryRequest.var"#2#3"{Bool,HTTP.Messages.Request},typeof(HTTP.request)}})(::Type{T} where T, ::Vararg{Any,N} where N; kwargs::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:iofunction, :reached_redirect_limit, :sslconfig, :retry, :verbose),Tuple{Nothing,Bool,MbedTLS.SSLConfig,Bool,Int64}}}) at ./error.jl:288
 [5] #request#1 at ~/.julia/packages/HTTP/IAI92/src/RetryRequest.jl:44 [inlined]
 [6] request(::Type{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}, ::String, ::HTTP.URIs.URI, ::Array{Pair{SubString{String},SubString{String}},1}, ::String; http_version::VersionNumber, target::String, parent::HTTP.Messages.Response, iofunction::Nothing, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{6,Symbol},NamedTuple{(:reached_redirect_limit, :sslconfig, :retry, :retries, :retry_non_idempotent, :verbose),Tuple{Bool,MbedTLS.SSLConfig,Bool,Int64,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/MessageRequest.jl:51
 [7] request(::Type{HTTP.BasicAuthRequest.BasicAuthLayer{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}}, ::String, ::HTTP.URIs.URI, ::Array{Pair{SubString{String},SubString{String}},1}, ::String; kw::Base.Iterators.Pairs{Symbol,Any,NTuple{7,Symbol},NamedTuple{(:reached_redirect_limit, :sslconfig, :retry, :retries, :retry_non_idempotent, :verbose, :parent),Tuple{Bool,MbedTLS.SSLConfig,Bool,Int64,Bool,Int64,HTTP.Messages.Response}}}) at ~/.julia/packages/HTTP/IAI92/src/BasicAuthRequest.jl:28
 [8] request(::Type{HTTP.RedirectRequest.RedirectLayer{HTTP.BasicAuthRequest.BasicAuthLayer{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}}}, ::String, ::HTTP.URIs.URI, ::Array{Pair{SubString{String},SubString{String}},1}, ::String; redirect_limit::Int64, forwardheaders::Bool, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:sslconfig, :retry, :retries, :retry_non_idempotent, :verbose),Tuple{MbedTLS.SSLConfig,Bool,Int64,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/RedirectRequest.jl:24
 [9] request(::String, ::String, ::Array{Pair{SubString{String},SubString{String}},1}, ::Array{UInt8,1}; headers::Dict{String,String}, body::String, query::Nothing, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:sslconfig, :retry, :retries, :retry_non_idempotent, :verbose),Tuple{MbedTLS.SSLConfig,Bool,Int64,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/HTTP.jl:314

It only seems to happen on the first request. Subsequent parallel requests are fine.
I am creating a new SSLConfig per request, with a custom CA chain:

sslconfig = MbedTLS.SSLConfig(true)
MbedTLS.ca_chain!(sslconfig, MbedTLS.crt_parse_file("bundle_path"))
HTTP.request(....; sslconfig=sslconfig)

Any help much appreciate!

@msavael
Copy link
Author

msavael commented Dec 11, 2020

Any ideas on this? I can't reproduce it with a public example unfortunately - seems to be somehow specific to either the internal service I am calling, or the SSL certificate chain. Here is a more detailed stacktrace, though:

ArgumentError: `unsafe_write` requires `iswritable(::SSLContext)`
Stacktrace:
 [1] ssl_unsafe_write(::MbedTLS.SSLContext, ::Ptr{UInt8}, ::UInt64) at ~/.julia/packages/MbedTLS/4YY6E/src/ssl.jl:228
 [2] unsafe_write at ~/.julia/packages/MbedTLS/4YY6E/src/ssl.jl:405 [inlined]
 [3] unsafe_write at ~/.julia/packages/HTTP/IAI92/src/ConnectionPool.jl:171 [inlined]
 [4] unsafe_write at ./io.jl:622 [inlined]
 [5] write at ./io.jl:645 [inlined]
 [6] startwrite(::HTTP.Streams.Stream{HTTP.Messages.Response,HTTP.ConnectionPool.Transaction{MbedTLS.SSLContext}}) at ~/.julia/packages/HTTP/IAI92/src/Streams.jl:87
 [7] request(::Type{HTTP.StreamRequest.StreamLayer{Union{}}}, ::HTTP.ConnectionPool.Transaction{MbedTLS.SSLContext}, ::HTTP.Messages.Request, ::String; reached_redirect_limit::Bool, response_stream::Nothing, iofunction::Nothing, verbose::Int64, kw::Base.Iterators.Pairs{Symbol,Any,Tuple{Symbol,Symbol},NamedTuple{(:sslconfig, :retry),Tuple{MbedTLS.SSLConfig,Bool}}}) at ~/.julia/packages/HTTP/IAI92/src/StreamRequest.jl:37
 [8] request(::Type{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}, ::HTTP.URIs.URI, ::HTTP.Messages.Request, ::String; proxy::Nothing, socket_type::Type{T} where T, reuse_limit::Int64, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:iofunction, :reached_redirect_limit, :sslconfig, :retry, :verbose),Tuple{Nothing,Bool,MbedTLS.SSLConfig,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/ConnectionRequest.jl:96
 [9] request(::Type{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}, ::HTTP.URIs.URI, ::Vararg{Any,N} where N; kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:iofunction, :reached_redirect_limit, :sslconfig, :retry, :verbose),Tuple{Nothing,Bool,MbedTLS.SSLConfig,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/ExceptionRequest.jl:19
 [10] (::Base.var"#56#58"{Base.var"#56#57#59"{ExponentialBackOff,HTTP.RetryRequest.var"#2#3"{Bool,HTTP.Messages.Request},typeof(HTTP.request)}})(::Type{T} where T, ::Vararg{Any,N} where N; kwargs::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:iofunction, :reached_redirect_limit, :sslconfig, :retry, :verbose),Tuple{Nothing,Bool,MbedTLS.SSLConfig,Bool,Int64}}}) at ./error.jl:288
 [11] #request#1 at ~/.julia/packages/HTTP/IAI92/src/RetryRequest.jl:44 [inlined]
 [12] request(::Type{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}, ::String, ::HTTP.URIs.URI, ::Array{Pair{SubString{String},SubString{String}},1}, ::String; http_version::VersionNumber, target::String, parent::HTTP.Messages.Response, iofunction::Nothing, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{6,Symbol},NamedTuple{(:reached_redirect_limit, :sslconfig, :retry, :retries, :retry_non_idempotent, :verbose),Tuple{Bool,MbedTLS.SSLConfig,Bool,Int64,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/MessageRequest.jl:51
 [13] request(::Type{HTTP.BasicAuthRequest.BasicAuthLayer{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}}, ::String, ::HTTP.URIs.URI, ::Array{Pair{SubString{String},SubString{String}},1}, ::String; kw::Base.Iterators.Pairs{Symbol,Any,NTuple{7,Symbol},NamedTuple{(:reached_redirect_limit, :sslconfig, :retry, :retries, :retry_non_idempotent, :verbose, :parent),Tuple{Bool,MbedTLS.SSLConfig,Bool,Int64,Bool,Int64,HTTP.Messages.Response}}}) at ~/.julia/packages/HTTP/IAI92/src/BasicAuthRequest.jl:28
 [14] request(::Type{HTTP.RedirectRequest.RedirectLayer{HTTP.BasicAuthRequest.BasicAuthLayer{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}}}, ::String, ::HTTP.URIs.URI, ::Array{Pair{SubString{String},SubString{String}},1}, ::String; redirect_limit::Int64, forwardheaders::Bool, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:sslconfig, :retry, :retries, :retry_non_idempotent, :verbose),Tuple{MbedTLS.SSLConfig,Bool,Int64,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/RedirectRequest.jl:24
 [15] request(::String, ::String, ::Array{Pair{SubString{String},SubString{String}},1}, ::Array{UInt8,1}; headers::Dict{String,String}, body::String, query::Nothing, kw::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:sslconfig, :retry, :retries, :retry_non_idempotent, :verbose),Tuple{MbedTLS.SSLConfig,Bool,Int64,Bool,Int64}}}) at ~/.julia/packages/HTTP/IAI92/src/HTTP.jl:314

MbedtTLS v1.0.3
HTTP v0.8.19
Julia 1.5.3

Other possibly relevant details: I'm doing a POST request, and I'm consuming the response with IOBuffer(r.body) which gets passed to CodecLz4 for compression.

If anyone is able to deduce something from the stacktrace, it would be amazing! Currently, I can't do parallel HTTPS requests which is a real nuisance.

@mkshirazi
Copy link

I am facing a similar problem. I have mentioned it here. However, unlike you, I can not get self signed certificate to verify even once

@quinnj
Copy link
Member

quinnj commented May 26, 2022

This should be fixed on master; in short, there were a couple different ways multithreaded request code could get internal structures corrupted and lead to these kinds of bugs. The 1.0 release is coming soon and we'll encourage all to upgrade to avoid these kinds of issues.

@quinnj quinnj closed this as completed May 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants