-
-
Notifications
You must be signed in to change notification settings - Fork 339
Initial implementation of Method #8
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
Conversation
src/method.rs
Outdated
/// let method = Method::extension("FOO"); | ||
/// assert_eq!(method, "FOO"); | ||
/// ``` | ||
pub fn extension(s: &str) -> Method { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, something I've noticed a while ago in hyper is that the Method::Extension(String)
constructor allows constructing an invalid method. It's bothered me a little, and maybe this is the time to fix it.
Perhaps instead of easily constructing with any string at all, we'd need to at least check that the string only contains characters in the legal range. According to RFC7230, here's the ABNF:
method = token
token = 1*tchar
tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
"^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, maybe we have two options to get an extension:
- A
FromStr
implementation Method::from_str_unchecked(s: &str) -> Method
The first option would parse, and if it is a standard method, it would set it to the right enum variant.
The second option will always set it to the extension, and it is up to the caller to ensure that the given string is a valid method and not actually one of the existing standard methods.
We may decide not to use enum Extension {
Inline { data: [u8; 7], len: u8 },
Allocated(String),
} Given this list of methods: https://www.iana.org/assignments/http-methods/http-methods.xhtml, most methods are under 7 chars. However, this is an internal detail, so I'm not super worried right now. |
Ok, I removed bytes for this case. HTTP methods are going to be usually pretty small, so the zero-copy functionality of bytes is over kill. By not using it, we save some space! woohoo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might as a .as_str()
method as well (shorthand for the .as_ref()
impl) to just explicitly have a method for converting to a string.
src/method.rs
Outdated
pub struct Method(Inner); | ||
|
||
#[derive(Debug)] | ||
pub struct FromBytesError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make this an opaque struct (with zero size) so we can extend it in the future if need be. Something like:
pub struct FromBytesError { _priv: () }
src/method.rs
Outdated
/// method, i.e. one that is defined as a constant in this module. | ||
/// | ||
/// The function is unsafe as the input is not checked as valid UTF-8. | ||
pub unsafe fn from_bytes_unchecked(src: &[u8]) -> Method { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naively I'd expect us to not have this and instead of From<&str> for Method
and let users do their own str::from_utf8_unchecked
perhaps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly, but see above too. I would rather not have to always do string comparison. That would defeat the point of having an enum at all.
pub fn is_safe(&self) -> bool { | ||
match self.0 { | ||
Get | Head | Options | Trace => true, | ||
_ => false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this may be incorrect in the face of from_bytes_unchecked
because we could hav ExtensionInline(b"GET")
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
src/method.rs
Outdated
} | ||
|
||
fn cause(&self) -> Option<&Error> { | ||
None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a default method so I think it's safe to omit
/// Currently includes 8 variants representing the 8 methods defined in | ||
/// [RFC 7230](https://tools.ietf.org/html/rfc7231#section-4.1), plus PATCH, | ||
/// and an Extension variant for all extensions. | ||
#[derive(Clone, PartialEq, Eq, Hash, Debug)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the derived PartailEq
and Hash
may also be incorrect in the presence of from_bytes_unchecked
(similar to below) as it's possible to have Inner::Get
and Inner::ExtensionInline(b"GET")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that is the point! We want to avoid string comparisons if we don't have to, and from_bytes_unchecked
is unsafe
. So, if you do it wrong, that is on you :)
I'm going to remove |
I guess as a naive user I would expect: assert_eq!(Method::from("GET"), GET); for all variants of |
@alexcrichton well, that's why Anyway, I got rid of the fn, so we can debate it later. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good to me.
|
||
#[derive(Debug)] | ||
pub struct FromBytesError { | ||
_priv: (), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I again wonder if InvalidMethodError
is more descriptive..
This PR adds a dependency on the bytes crate, but does not expose it at all in the public API. It also adds a
str::Str
type that indicates that the innerBytes
is UTF-8 encoded, but the intension is to not expose this type at all. It will be reused as part of other types.Continuation of #3 & #5