hyper: TLS server corrupts large client responses

Got a strange one. I’m using hyper as a simple proxy. I have an EC2 instance running on HTTPS. When I contact the server, it uses the hyper client to download data from another (external) source, and sends it back as a response.

My service function has the signature

fn service(
    mut req: Request<hyper::Body>,
) -> impl Future<Item = Response<Body>, Error = Error> + Send

And since the client ResponseFuture implements Future<Item=Response<Body> I was just returning the future directly. However I found that large payloads (~1MB) were getting corrupted in strange ways. Certain sections of the payload were being duplicated and/or sent out-of-order (but usually the first 100KB or so were correct). This problem only seemed to occur when both the server and the external server were contacted through TLS - if either used HTTP the problem went away.

I worked around the problem by concatenating the response body before returning it.

resp.and_then(|resp| {
    let (parts, body) = resp.into_parts();
   body.concat2().map(|body| {
        let body = Body::from(body);
        Response::from_parts(parts, body)
    })
})

That seemed to fix it.

Stack:

hyper = "0.12.8"
hyper-tls = "0.3.0"
rustls = "0.13.0"
tokio = "0.1.7"
tokio-rustls = "0.7.1"
tokio-tcp = "0.1.1"

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 3
  • Comments: 21 (11 by maintainers)

Most upvoted comments

I just published tokio-rustls 0.7.2, which should fix the problem. By the way, it also has writev support.

I’ve just published rustls 0.13.1 too.

OK, I now understand what’s happening. It revolves around use of rustls::Stream with non-blocking transports. This wasn’t really supported, and indeed the documentation (though alas not the std::io type system) for the type states the requirement for a blocking transport. This can be made to work, and I’ll push a version of rustls which supports this shortly.

I can reproduce this, and echo the difficulty getting a reproduction over loopback. The discontinuities seem to be non-deterministic, too. So I’m currently thinking the bug is happening only when TCP buffers get filled, and then somewhere backpressure goes wrong. Still looking.

Thanks for the repro, I’ll look at this asap

I see two TLS dependencies, does it happen with both? If so, that’d imply the bug is in hyper. If only one, that’d imply the bug is in that TLS lib.