Handle ConnectionReset+ConnectionAbort at any time (#168)

Previously we had a special case for BadStatusRead that would happen
only when we got a ConnectionAborted error reading the status line.
However, sometimes we get ConnectionReset instead. Also the HTTP
spec says that idempotent requests may be retried anytime a connection
is closed prematurely.

The change treats as retryable any ConnectionAborted OR ConnectionReset
error while reading the status line and headers. It removes the special
case BadStatusRead error.

Fixes #165 (I think).
This commit is contained in:
Jacob Hoffman-Andrews
2020-09-29 01:55:34 -07:00
committed by GitHub
parent 065b560dfb
commit 17d7e147eb
4 changed files with 10 additions and 22 deletions

View File

@@ -1,5 +1,5 @@
use std::fmt;
use std::io;
use std::io::{self, ErrorKind};
/// Errors that are translated to ["synthetic" responses](struct.Response.html#method.synthetic).
#[derive(Debug)]
@@ -14,9 +14,6 @@ pub enum Error {
ConnectionFailed(String),
/// Too many redirects. Synthetic error `500`.
TooManyRedirects,
/// We fail to read the status line. This happens for pooled connections when
/// TLS fails and we don't notice until trying to read.
BadStatusRead,
/// A status line we don't understand `HTTP/1.1 200 OK`. Synthetic error `500`.
BadStatus,
/// A header line that couldn't be parsed. Synthetic error `500`.
@@ -37,11 +34,11 @@ pub enum Error {
}
impl Error {
// If the error is bad status read, which might happen if a TLS connections is
// closed and we only discover it when trying to read the status line from it.
pub(crate) fn is_bad_status_read(&self) -> bool {
// Return true iff the error was due to a connection closing.
pub(crate) fn connection_closed(&self) -> bool {
match self {
Error::BadStatusRead => true,
Error::Io(e) if e.kind() == ErrorKind::ConnectionAborted => true,
Error::Io(e) if e.kind() == ErrorKind::ConnectionReset => true,
_ => false,
}
}
@@ -54,7 +51,6 @@ impl Error {
Error::DnsFailed(_) => 400,
Error::ConnectionFailed(_) => 500,
Error::TooManyRedirects => 500,
Error::BadStatusRead => 500,
Error::BadStatus => 500,
Error::BadHeader => 500,
Error::Io(_) => 500,
@@ -75,7 +71,6 @@ impl Error {
Error::DnsFailed(_) => "Dns Failed",
Error::ConnectionFailed(_) => "Connection Failed",
Error::TooManyRedirects => "Too Many Redirects",
Error::BadStatusRead => "Failed to read status line",
Error::BadStatus => "Bad Status",
Error::BadHeader => "Bad Header",
Error::Io(_) => "Network Error",
@@ -96,7 +91,6 @@ impl Error {
Error::DnsFailed(err) => format!("Dns Failed: {}", err),
Error::ConnectionFailed(err) => format!("Connection Failed: {}", err),
Error::TooManyRedirects => "Too Many Redirects".to_string(),
Error::BadStatusRead => "Failed to read status line".to_string(),
Error::BadStatus => "Bad Status".to_string(),
Error::BadHeader => "Bad Header".to_string(),
Error::Io(ioe) => format!("Network Error: {}", ioe),