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

hyper::Error should distinguish http1 TooLarge from other parse errors #2462

Open
acfoltzer opened this issue Mar 11, 2021 · 11 comments
Open
Labels
A-error Area: error handling

Comments

@acfoltzer
Copy link
Member

acfoltzer commented Mar 11, 2021

Currently if an http1 message head exceeds the http1_max_buf_size, a hyper::Error is returned where err.is_parse() == true. This is indistinguishable from other errors that httparse might bubble up, which poses a problem for deciding how to respond to these errors. A TooLarge can occur just because of the choices made when setting up the max buffer size (many implementations default to 1MB vs the ~400KB default for hyper), vs. an actually malformed HTTP message which probably indicates a misbehaving server.

Could we add a new method to hyper::Error that distinguishes these? hyper::Error::is_buf_size_exceeded() as a strawman?

@acfoltzer
Copy link
Member Author

When chasing down a few other errors we've observed for customer services, I'm coming around to the idea that hyper::Error might need a broader scale overhaul. Perhaps with #[non_exhaustive] now in the language, we could expose the error enums more directly without risking too much in terms of compatibility?

Currently there are only 8 flavors of error that can be inspected programmatically through the hyper::Error::is_*() methods. But, depending on the feature flags enabled, there are at least 31 error kinds (7 Parse variants + 11 User variants + 13 other Kinds), plus dynamically typed errors via the cause field. While these can be distinguished by parsing the Display output of the error, this is of course not a sustainable approach.

I checked the rest of the issues for something speaking to a broader Error overhaul effort, so apologies if I missed something, but this would be really valuable to have sorted out before 1.0. How can we help?

@seanmonstar
Copy link
Member

Having a method to distinguish that it's a TooLarge internally would be fine.

Regarding the general idea of making the variants public, this comment still generally fits what I've though about the design issue of doing so in Rust.

nox added a commit to nox/hyper that referenced this issue Mar 15, 2021
We rename Parse::TooLarge into Parse::HeaderSectionTooLarge while at it.
nox added a commit to nox/hyper that referenced this issue Mar 15, 2021
…ium#2462)

We rename Parse::TooLarge into Parse::HeaderSectionTooLarge while at it.
@acfoltzer
Copy link
Member Author

@seanmonstar thanks. That's good context, but the thread seems to be inconclusive, so I'm not sure what the right path forward is. Would you like to see the method approach extended to all the currently-possible error variants? There was also mention in that thread of distinguishing between server and client errors; should that still be considered as well?

@seanmonstar
Copy link
Member

Yea that thread itself doesn't have a conclusion, I mostly was just meaning to link to that specific comment. I've also largely embraced the idea that only a few error conditions are ever interesting in code (such that you would want to react and do something differently), and that most are just something to eventually tell the user about.

I don't yet know what the way forward is for matching error variants. But I've started a draft blog post about the difficulties of pattern matching vs extensibility...

@acfoltzer
Copy link
Member Author

The problems for us arise less in terms of code needing to react and do things differently, and more in transparency and reporting to customers, as well as observability into the health of our systems. In other words, it's just something to eventually tell the user about, but how we tell them matters. While we could present the Display output to users and let them parse it if they wish to quantize the data, it would be less error-prone and more straightforward to be able to provide the more granular error information directly.

Given that, we'd really like to see a comprehensive programmatic way to distinguish errors, whether that's via pattern matching, methods, or some other approach (other than string matching 😉). It sounds like you'd prefer to continue with the methods approach, but I'd like to make sure of that before we work on putting a PR together with a boatload of new methods.

@seanmonstar
Copy link
Member

I think the methods option, with a ton of is_*, is ugly 😢 . But it also allows extending to new variants. For example, #2466 is asking that Parse::TooLarge be expanded into more specific sub variants. If we had exposed a normal, flat ErrorKind enum, it'd be impossible to do that without breaking people.

I've never gotten around to more fully trying that wacky idea I linked to... like, if the exposed kinds were somehow completely non-exhaustive, then this could be possible, maybe?

match e.kind() {
    Kind::TooLarge(_) => {},
    _etc => {},
}

And some eventual addition like this would still work, I think?

enum TooLarge {
    HeaderSection(Sealed),
    HeaderName(Sealed),
    // etc
}

enum Kind {
    TooLarge(TooLarge),
    // etc
}

@nox
Copy link
Contributor

nox commented Mar 19, 2021

When you say Sealed, I assume you mean a public type in a private module that downstream cannot refer by name?

@seanmonstar
Copy link
Member

Yea exactly, the linked comment tries to explain it more. Note though, I'm not saying that this is what we definitely should do, just that it seems plausible and I wish I had time to explore it more in an experiment to see how good or bad it is in reality.

@nox
Copy link
Contributor

nox commented Mar 19, 2021

That seems like a reasonable plan to me. Do you think we should try to get people's opinion on this somewhere? Can we start implementing that error encoding?

@seanmonstar
Copy link
Member

Certainly, trying it out on a smaller project where it's less expensive (to the ecosystem) to try it out would be a great start. Also happy to get other people's opinions, wherever you think they're likely to provide them.

@nox
Copy link
Contributor

nox commented Apr 7, 2021

No I mean as a PR to Hyper hah.

nox added a commit to nox/hyper that referenced this issue Apr 7, 2021
…ium#2462)

We rename Parse::TooLarge into Parse::HeaderSectionTooLarge while at it.
nox added a commit to nox/hyper that referenced this issue Apr 15, 2021
nox added a commit to nox/hyper that referenced this issue Apr 15, 2021
nox added a commit to nox/hyper that referenced this issue Apr 15, 2021
nox added a commit to nox/hyper that referenced this issue Apr 15, 2021
nox added a commit to nox/hyper that referenced this issue Apr 16, 2021
nox added a commit to nox/hyper that referenced this issue Apr 16, 2021
nox added a commit to nox/hyper that referenced this issue Apr 16, 2021
nox added a commit to nox/hyper that referenced this issue Apr 21, 2021
nox added a commit to nox/hyper that referenced this issue Apr 22, 2021
acfoltzer added a commit to acfoltzer/hyper that referenced this issue May 6, 2021
…errors

The discussion in hyperium#2462 opened up some larger questions about more comprehensive approaches to the
error API, with the agreement that additional methods would be desirable in the short term. These
methods address an immediate need of our customers, so I would like to get them in first before we
flesh out a future solution.

One potentially controversial choice here is to still return `true` from `is_parse_error()` for
these variants. I hope the naming of the methods make it clear that the new predicates are
refinements of the existing one, but I didn't want to change the behavior of `is_parse_error()`
which would require a major version bump.
acfoltzer added a commit to acfoltzer/hyper that referenced this issue May 6, 2021
The discussion in hyperium#2462 opened up some larger questions about more comprehensive approaches to the
error API, with the agreement that additional methods would be desirable in the short term. These
methods address an immediate need of our customers, so I would like to get them in first before we
flesh out a future solution.

One potentially controversial choice here is to still return `true` from `is_parse_error()` for
these variants. I hope the naming of the methods make it clear that the new predicates are
refinements of the existing one, but I didn't want to change the behavior of `is_parse_error()`
which would require a major version bump.
acfoltzer added a commit to acfoltzer/hyper that referenced this issue May 6, 2021
The discussion in hyperium#2462 opened up some larger questions about more comprehensive approaches to the
error API, with the agreement that additional methods would be desirable in the short term. These
methods address an immediate need of our customers, so I would like to get them in first before we
flesh out a future solution.

One potentially controversial choice here is to still return `true` from `is_parse_error()` for
these variants. I hope the naming of the methods make it clear that the new predicates are
refinements of the existing one, but I didn't want to change the behavior of `is_parse_error()`
which would require a major version bump.
@davidpdrsn davidpdrsn added the A-error Area: error handling label May 7, 2021
seanmonstar pushed a commit that referenced this issue May 13, 2021
…tus` methods (#2538)

The discussion in #2462 opened up some larger questions about more comprehensive approaches to the
error API, with the agreement that additional methods would be desirable in the short term. These
methods address an immediate need of our customers, so I would like to get them in first before we
flesh out a future solution.

One potentially controversial choice here is to still return `true` from `is_parse_error()` for
these variants. I hope the naming of the methods make it clear that the new predicates are
refinements of the existing one, but I didn't want to change the behavior of `is_parse_error()`
which would require a major version bump.
BenxiangGe pushed a commit to BenxiangGe/hyper that referenced this issue Jul 26, 2021
…tus` methods (hyperium#2538)

The discussion in hyperium#2462 opened up some larger questions about more comprehensive approaches to the
error API, with the agreement that additional methods would be desirable in the short term. These
methods address an immediate need of our customers, so I would like to get them in first before we
flesh out a future solution.

One potentially controversial choice here is to still return `true` from `is_parse_error()` for
these variants. I hope the naming of the methods make it clear that the new predicates are
refinements of the existing one, but I didn't want to change the behavior of `is_parse_error()`
which would require a major version bump.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-error Area: error handling
Projects
None yet
Development

No branches or pull requests

4 participants