[HN Gopher] Hyper - A fast and correct HTTP implementation for Rust
       ___________________________________________________________________
        
       Hyper - A fast and correct HTTP implementation for Rust
        
       Author : belter
       Score  : 71 points
       Date   : 2023-05-12 19:07 UTC (3 hours ago)
        
 (HTM) web link (crates.io)
 (TXT) w3m dump (crates.io)
        
       | infogulch wrote:
       | Any recommendations for rust template engines? I'd like something
       | that can easily render labeled fragments of a template instead of
       | requiring me to split a page into a dozen little files. Kinda
       | like inline {{block}} definitions in Go's html/template. Speed is
       | also nice.
       | 
       | From template-benchmark-rs [0] I found sailfish [1] (fast, but no
       | fragments(?)). render-rs [2] and syn-rsx [3] both let you write
       | html in rust macros which is cool (maybe that can substitute for
       | fragments?). Then there's gtmpl-rust [4] which is just Go
       | templates reimplemented in rust.
       | 
       | [0]: https://github.com/rosetta-rs/template-benchmarks-rs
       | 
       | [1]: https://github.com/rust-sailfish/sailfish
       | 
       | [2]: https://github.com/render-rs/render.rs last updated Jul 2020
       | 
       | [3]: https://github.com/stoically/syn-rsx last updated Nov 2022
       | 
       | [4]: https://github.com/fiji-flo/gtmpl-rust
        
         | tomjakubowski wrote:
         | tera is fairly standard. Jinja2-like syntax. I'm not sure what
         | you mean about rendering labeled fragments, do you have an
         | example?
        
           | infogulch wrote:
           | Sure. They're called 'partials' sometimes. Useful if you want
           | to rerender just part of a page. This is a pattern used by
           | HTMX, a 'js framework' that accepts fragments of html in an
           | http response and injects it into the page. This is good
           | because it avoids the flash and state loss of a whole page
           | reload. See the HTMX essay on template fragments for a more
           | complete argument [0].
           | 
           | This is a go template for an interactive todos app [1] that
           | I'm experimenting with. The html content of the entire page
           | is present in one template definition which is split into 6
           | inline {{block}} definitions / "fragments". The page supports
           | 5 interactions indicated by {{define}} definitions, each of
           | which reuse various block fragments relevant to that
           | interaction. I'm in the process of converting it to use
           | embedded cozodb [2] queries which act as a server side data
           | store. The idea here is that the entire 'app', including all
           | html fragments, styles, http requests and responses, db
           | schema, and queries are embedded into this single 100-line
           | file.
           | 
           | [0]: https://htmx.org/essays/template-fragments/
           | 
           | [1]: https://github.com/infogulch/go-
           | htmx/blob/master/templates/t...
           | 
           | [2]: https://github.com/cozodb/cozo
        
         | prussian wrote:
         | https://maud.lambda.xyz/
         | 
         | Maybe this?
        
       | renewiltord wrote:
       | Appears to have heavy use of `async`, etc. Has anyone gone about
       | creating JNI bindings for an `async` API? I imagine you start the
       | pool in a context object and then access the APIs through that
       | via some callback mechanism? I'd love to read someone's example
       | code if you're willing to share.
        
         | subarctic wrote:
         | I'm not really familiar with JNI and not sure if it's different
         | on Android vs server-side Java, but this forum thread might be
         | interesting reading for you: https://users.rust-
         | lang.org/t/rust-jni-android-async-callbac...
         | 
         | EDIT: also maybe take a look at this?
         | https://github.com/rousan/AndroidWithRust
         | 
         | "tokio jni" is the search term that turned these up for me
        
       | Animats wrote:
       | Hyper is still at version 0.x.
       | 
       | I currently use "ureq" client side, due to async contamination in
       | Hyper.
        
         | timeon wrote:
         | "ureq" is bit different from Hyper. Hyper is lower level. In
         | same category as "ureq" - there is "reqwest" which is built on
         | top of Hyper and has also "blocking" option (aka without
         | async).
        
       | satvikpendem wrote:
       | If you want to build a backend in Rust, Axum (which uses hyper
       | underneath) is pretty recommended these days, as it's all in the
       | tokio ecosystem. Actix Web is good too, but it has its own
       | ecosystem of libraries. I read the book Zero To Production in
       | Rust [0] which was a great overview on not just Rust but scalable
       | backend architectures as a whole.
       | 
       | Interestingly, Cloudflare wanted to use hyper but found that it
       | was _too_ correct, so they had to build their own [1].
       | 
       | [0] https://www.zero2prod.com
       | 
       | [1] https://blog.cloudflare.com/how-we-built-pingora-the-
       | proxy-t...
        
         | tele_ski wrote:
         | We interestingly ran into issues with actix and the AWS lb. The
         | lb takes some liberty with how it handled connections and actix
         | seems to be "to the spec" so we were seeing a lot of dropped
         | connections. Placing nginx between the two resolved the issue
         | but it's fairly disappointing that we need that layer when it
         | should be unnecessary overhead. I'd love to give axum a try if
         | we could find time and see if it behaves better.
        
           | infogulch wrote:
           | > lb takes some liberty with how it handled connections
           | 
           | Interesting, I'm curious about the details here. Does the lb
           | reuse connections for multiple requests or something?
        
             | scottlamb wrote:
             | > Interesting, I'm curious about the details here. Does the
             | lb reuse connections for multiple requests or something?
             | 
             | I'm curious too. There must be more to it than that because
             | LBs reusing backhaul connections is standard practice. It's
             | not only an optimization but in many cases you'll quickly
             | hit ephemeral port exhaustion if you don't. TCP connections
             | are distinguished by (src_ip, src_port, dst_ip, dst_port)
             | tuple. For this leg you're probably only varying the
             | src_port portion, and all of the valid options are cooling
             | in time_wait state.
        
         | cschneid wrote:
         | What's the current state of database access? Last I looked a
         | while back Diesel was really cool, but didn't play nice w/
         | Async.
        
           | phaer wrote:
           | Haven't used it myself, but https://github.com/SeaQL/sea-orm
           | seems to be popular in some communities and async
        
           | lwhsiao wrote:
           | SQLx [1] is commonly recommended. It has the nice feature
           | that your queries can be verified at compile time.
           | 
           | [1]: https://github.com/launchbadge/sqlx
        
           | redman25 wrote:
           | Async is not necessarily as useful for database connections
           | since connection counts will generally be in the 10s and
           | handled with a thread pool. It's pretty low overhead to just
           | use pooling.
        
             | unshavedyak wrote:
             | Yea but you still want a good async interface if you're
             | already using async, even if it's mocked over an underlying
             | threadpool. Otherwise you have to wrap all your DB clients
             | in your own adhoc async wrappers which feels kinda bad,
             | imo.
        
           | satvikpendem wrote:
           | I use Prisma Client Rust [0], coming from the Node.js world,
           | it works great. Some people like to use sqlx though, I'm not
           | too big into writing SQL for every little thing.
           | 
           | [0] https://github.com/Brendonovich/prisma-client-rust
        
           | Spartan-S63 wrote:
           | Diesel now has an official async adapter:
           | https://crates.io/crates/diesel-async
        
         | skywal_l wrote:
         | I tried warp [0] and I am unimpressed so far. Pretty complex,
         | limited documentation, buggy. The builder paradigm they used
         | feels pretty constrained and, in my opinion, achieve the
         | opposite of the simplicity it is supposed to bring. I was
         | surprised it is so popular.
         | 
         | Maybe I need more time or a favorable comparison to another
         | framework to appreciate it.
         | 
         | [0] https://github.com/seanmonstar/warp
        
           | dcormier wrote:
           | We used warp originally, and ended up refactoring to axum.
           | We've been much happier with it.
        
       | sdfghswe wrote:
       | Why is it that "it's correct" is something worth mentioning?
       | Presumably if it's not correct it's either not an implementation,
       | or not known that it's not correct.
        
         | epgui wrote:
         | I don't know if it's what is being referred to here, but
         | "provably correct software" is a whole thing. It takes the idea
         | of software tests to the next level, and is very important in
         | some contexts.
        
         | satvikpendem wrote:
         | The implementation could be incorrect (in certain cases) but
         | still be useful. Cloudflare has such an implementation:
         | https://blog.cloudflare.com/how-we-built-pingora-the-proxy-t...
        
         | cmckn wrote:
         | Share the same general sentiment, but in the case of HTTP, many
         | implementations are forgiving of conventional usage that may
         | not match the specs; so I guess it's worth mentioning that this
         | impl is strictly by-the-book.
        
           | rickstanley wrote:
           | This "book" would be the RFC?
        
             | chlorion wrote:
             | Yes, "by the book" is a very commonly used metaphor in
             | English, even when no book is involved.
             | 
             | It's roughly equal to saying that you are doing something
             | strictly by the rules (and the rules don't have to be
             | contained in a book or even exist in text form).
             | 
             | Some uses would be like: "My boss insists on doing
             | everything by the book".
        
         | sophacles wrote:
         | It's a good question with an unsatisfying answer. Networking is
         | kind of difficult.
         | 
         | Sitting down with an RFC and coding up what it says is nowhere
         | near as simple as it seems like it should be:
         | 
         | * RFCs are often ambiguous, I've seen teams implement a
         | protocol in a way that certainly seems to follow the RFC but
         | won't be widely interoperable.
         | 
         | * RFCs are often incomplete, many protocols are specified
         | across a lot of different RFCs, and by different authors, so
         | it's easy to miss important details or even whole RFCs
         | exacerbating the above point.
         | 
         | * RFCs are regularly released as protocols evolve and
         | invalidate older versions of the protocol (or early
         | experimental versions of the protocol, etc) often. Sometimes
         | the newest RFC does a lot of work to disambiguate what would be
         | allowed by older versions see for example this recent RFC
         | https://httpwg.org/specs/rfc9110.html
         | 
         | * Independent of what the RFC says, there's what Cisco does (or
         | MS or Google or other large influential imlementors).
         | 
         | * A lot of protocol implementations don't implement the full
         | protocol (that is various extensions or rarely used features).
         | 
         | * A lot of protocol implementations implement what the RFC says
         | in the most commonly aggreed on way, plus a compatibility
         | options for other commonly used implementations, plus some
         | oddball interpretations of the RFC that the authors like.
         | 
         | * There's vendor-specific extensions.
         | 
         | * There's common but unspecified behaviors that implementations
         | tend to converge on, but which aren't easy to intuit.
         | 
         | * There's implementations that handle mixtures of versions
         | (e.g. implementations of http 1.1 that handle 1.0 or 0.9 just
         | fine are common).
         | 
         | And so on. So to answer the question "is 'it's correct' worth
         | mentioning?" - yes, something along these lines tends to be
         | important.
         | 
         | Of course "what does correct mean" is a giant can of worms....
         | 
         | In the case of hyper I think it means: an attempt to be
         | extremely precise in what is allowed (and as close to the
         | disambiguated RFCs as possible), and strict as well - not being
         | particularly loose in what it accepts as input. That's my
         | interpretation anway.
        
           | vp8989 wrote:
           | "Sitting down with an RFC and coding up what it says is
           | nowhere near as simple as it seems like it should be"
           | 
           | I learned this for myself when I tried coding an IRC server
           | for fun. Quickly found that I made more progress, faster by
           | just using Wireshark to see what an established server was
           | doing and copying that.
        
         | tux3 wrote:
         | For HTTP, being pedantically correct is a tradeoff. On the plus
         | side, you prevent weird potentially unexpected behaviors by
         | cleanly rejecting off-spec behavior instead of accepting
         | potentially broken input and seeing what happens.
         | 
         | But you also can't interact with everyone else anymore, because
         | a whole lot of people run slightly off-spec software,
         | successfully, and sometimes without knowing it.
        
       | timeon wrote:
       | Also: https://crates.io/crates/arti-hyper
        
       | loeg wrote:
       | Any particular reason to highlight Hyper now? This crate has been
       | around for years, I think?
        
         | belter wrote:
         | The daily 10,000 ? - https://xkcd.com/1053/
        
           | charcircuit wrote:
           | That doesn't explain why Hyper. There is millions of things
           | people don't know that you could choose from.
        
             | mcdonje wrote:
             | Go ahead and post one of those millions of other things.
        
       | simonhamp wrote:
       | How does this compare to Rocket (https://rocket.rs/) - I've just
       | started using Rocket and it seems to provide everything that
       | Hyper does and a lot more out of the box too
       | 
       | When would I use Hyper instead of Rocket?
        
         | paavohtl wrote:
         | Hyper is a relatively low level HTTP library, while Rocket is a
         | web server framework. So Hyper doesn't concern itself with
         | things like routing, authentication, state management, template
         | rendering, static file hosting and so on, which Rocket
         | provides. Hyper is only focused on being a good implementation
         | of the HTTP protocol and serving as a base for higher level
         | libraries and applications. You could use Hyper to build a
         | framework like Rocket - though AFAIK Rocket uses its own HTTP
         | implementation.
         | 
         | It's kind of like that difference between Photoshop and libpng.
        
           | sam0x17 wrote:
           | Rocket uses hyper for it's HTTP
        
             | [deleted]
        
         | darrell_roberts wrote:
         | It is built using hyper.
         | 
         | Hyper is a dependency:
         | 
         | https://github.com/SergioBenitez/Rocket/blob/v0.5-rc/core/ht...
        
         | satvikpendem wrote:
         | Others have explained the difference, but I wouldn't use Rocket
         | at all, to be honest. It's barely maintained, the maintainer
         | left for some time without telling anyone and without giving
         | any repository access to other contributors, and it has a bus
         | factor of one. I'd recommend Axum since it's backed by the
         | Tokio contributors which makes it much less likely to be
         | unmaintained later on.
        
           | simonhamp wrote:
           | There was a release just a couple of months ago - that
           | doesn't seem to be "barely maintained"
        
             | satvikpendem wrote:
             | The 0.5 release is literally years in the making and
             | there's no indication that it'll be done any time soon. The
             | creator said they finished most of it in a 2020 comment and
             | it's still not done.
        
       | donpdonp wrote:
       | I cant speak to 'correctness' but ureq has been great to work
       | with. Simple and small. https://crates.io/crates/ureq
        
       | benatkin wrote:
       | It's what Deno uses.
       | https://crates.io/crates/deno_http/0.99.0/dependencies
       | 
       | "A fast an correct HTTP implementation" makes sense for Deno, as
       | Deno is founded by the same person who founded Node.js and the
       | correctness of Node's HTTP server was different from that of
       | other scripting languages.
        
         | tomjakubowski wrote:
         | In what ways was Node's HTTP server different? Is it still a
         | problem with today's Node versions?
        
           | benatkin wrote:
           | Oh I mean Deno's HTTP server is excellent in the same way
           | Node's is. That isn't cited as one of the primary reasons for
           | creating Deno. However Deno is built on a different platform
           | (Rust rather than C) so it uses a different HTTP library.
           | 
           | I'm pretty sure Deno is contributing significantly to Hyper.
           | 
           | Deno's HTTP server is more balanced when it comes to
           | tradeoffs than node's I think. Node is optimized for IO-bound
           | programs is what I have heard.
        
       ___________________________________________________________________
       (page generated 2023-05-12 23:01 UTC)