WEBVTT

00:00:15.000 --> 00:00:52.000
<v Glen (Plabayo BV)> Hello everybody, with me is Lucio. We had him in a previous episode all about gRPC. For our episode, the first one about protocol shorts, we want to talk a bit about gRPC and specifically, even though gRPC was developed with H2 in mind, some environments or some organizations had use case for it beyond H2 and they wanted to make sure that it could also be used over HTTP 1.1 or from within a browser. And for that, one of the protocols is gRPC web. And with me, like I said, is Lucio. So welcome again, Lucio.

00:00:52.000 --> 00:00:54.000
<v Lucio Franco> Thank you for having me back.

00:00:54.000 --> 00:01:13.000
<v Glen (Plabayo BV)> Yeah, it's not been that long. So I wanted to invite you as you were in my opinion like the Rust gRPC expert and last time was a great blast. So maybe to remind the listeners as we did talk about it a bit last time, can you tell me a bit again what gRPC is and then how gRPC web fits in there?

00:01:13.000 --> 00:01:52.000
<v Lucio Franco> Yeah, gRPC is a language agnostic protocol for defining ⁓ network request or network procedure calls. So ⁓ what RPC stand for. ⁓ And it's a protocol defined by Google. It's designed to be language agnostic. So it can be implemented in any language. And in fact, ⁓ it's implemented in the majority of the mainstream languages that we use right now. ⁓ And I maintain Tonic, which is the currently the most popular Rust implementation of gRPC. ⁓ And gRPC web is a protocol on top of the regular gRPC protocol to enable web-based usage.

00:01:52.000 --> 00:02:09.000
<v Glen (Plabayo BV)> Okay, and so normally GRPC is like going over H2 frames and where the header frames are used for the metadata. You also have the trailer header frame, which is also used. Maybe first recap a bit again, what is in these metadata frames or the header frames?

00:02:09.000 --> 00:03:52.000
<v Lucio Franco> Yeah, so H2 is ⁓ HTTP2 protocol. ⁓ It was designed as a next generation on top of HTTP1 to enable ⁓ multiplexed streams. So enabling you to use one TCP stream to send multiple parallel in-flight requests and responses. ⁓ It's also streaming based. So like it allows you to kind of have these multiplexed streams. So you can have multiple streams that have writers and readers. all in the same TCP connection, which was not possible with HTTP one and the way that protocol was designed. GRPC itself sits just purely on top of this as essentially like a definition of using protobuf and HTTP two. And it just kind of glues it together. It's actually like a very lightweight abstraction. ⁓ And so it just uses the HTTP two framing stuff and it just injects protobuf messages into it. And it kind of defines a couple. HTTP headers, whether that's in the initial headers, which is what you would think of as your normal HTTP one request or response headers. And additionally, since it has a streaming nature, there's the ability to send trailers, trailing headers at the end of the stream. ⁓ And ⁓ protobuf leverages these by just defining some names, some well known names that then the protobuf libraries can just use to extract things like a status of a request, right? If request failed or not. ⁓ And gRPC web kind of takes the same idea and just tries to build it on top of HTTP one. ⁓ Now the main crux of why you might be asking why is there a difference here is that HTTP one clearly does not have the same feature set that HTTP two has. So gRPC web is kind of an adaptation on top of HTTP two's implementation to actually be a much more limited version. And we get to put those details in a bit.

00:03:52.000 --> 00:04:06.000
<v Glen (Plabayo BV)> Yeah, and maybe before we get into that, is it actually like a difference between these metadata, like key values versus like a header? Like are there like maybe more restrictions or are they pretty much just the same but a different name?

00:04:06.000 --> 00:04:58.000
<v Lucio Franco> Yeah, the headers themselves are the header keys, so header names are valid ⁓ HTTP two headers. There's restrictions on what you can do there, but that's whatsoever in the spec. The value of the key again is just a valid H2 header value, except that gRPC has one additional layer on top to allow you to define either ASCII or binary base64 encoded values. Um, so that's just built on top of HTTP2 Now I don't know if this is like a gRPC specific thing, or if this is just like a technique to use the values inside of H2. I'm pretty sure it's the latter here. So it's not like a gRPC unique thing that they do this sort of ASCII Base64 stuff. It's just a way to expose that to users so they don't need to think about the H2 semantics, right? Cause that's the big advantage of a gRPC is that you don't need to really think about.

00:04:58.000 --> 00:05:02.000
<v Glen (Plabayo BV)> Mm.

00:05:02.000 --> 00:05:09.000
<v Lucio Franco> HTTP2, you just think of things in the higher level gRPC context and it will work very well.

00:05:09.000 --> 00:05:16.000
<v Glen (Plabayo BV)> Okay, and why is it important that we can have like trailer headers? Like what's specific use case for that? What if we didn't have that?

00:05:16.000 --> 00:05:51.000
<v Lucio Franco> So it's really simple actually. Besides the custom use cases, the main use case for trailing headers is if you have a long running stream of messages and that stream fails at some point, you need to indicate to the user that it failed, why it failed. So it can be a failure, know, the server ran out of resources or, you know, some sort of, you know, user logic was incorrect or a request message coming in was incorrectly formatted and so it couldn't reply. Anything that might do with the stream status can be sent as a trailer. And usually when you get the trailer responses, it kind of ends the whole, that stream. ⁓ And so it's a way to indicate that.

00:05:51.000 --> 00:06:18.000
<v Glen (Plabayo BV)> Okay, very cool. And then so obviously like you said, if we are going over HTTP 1.1, we are a lot more limited to we only have like basically one stream. think, yeah, we, and usually it's like a request response. So I guess, I get it. You just go to the bare minimum, I guess, where you just, you request something and then either you finish your stream fully and then the server can respond like, and that's kind of like it.

00:06:18.000 --> 00:06:40.000
<v Lucio Franco> Yeah, so it's somewhat similar. ⁓ The major limitation of gRPC web is that you have no client streaming. What that means is there's no way for the client to stream a bunch of messages asynchronously via the client, right? So like it can only receive a stream of messages, but it cannot send a stream of messages. So ⁓ this is like one of the major limitations. Yeah, because the way that like the fetch API's work. So, so gRPC web, need to back up a little bit. It exists purely for the fact to enable people to hit gRPC endpoints from web browsers, because ⁓ most users that do service to service gRPC calls always have an HTTP 2 client. There's HTTP 2 implementations in almost every language. So the restriction for needing to not

00:06:40.000 --> 00:07:02.000
<v Glen (Plabayo BV)> Why is that by the way?

00:07:02.000 --> 00:08:23.000
<v Lucio Franco> be able to use HPE 2 is generally only scoped down to browsers. ⁓ There's a couple other use cases. had a use case with FlyIO only accepting HPE 1 into the load balancer. So that's another use case that I found where I needed to use gRPC web. But the major use case is, know, hitting things from the browser and being able to hit a gRPC endpoint from the browser. ⁓ That ⁓ limitation comes from the fact that fetch. So the API available in the browser is the fetch API. ⁓ you know, via JavaScript and that does not let you send streamable bodies. It only lets you send a, you know, ⁓ already buffered body and that's it. But it does support streaming on the receiving end. And this is because simply, you know, things like on the web, like images, you request to get an image and the image might need to be chunked to you. And therefore you need to, it needs to support that streaming stuff. So in reality, it's actually a reaction to just what is available in the browser and kind of adapting it to the needs of how the browser makes requests. ⁓ And so that's why only server-side streaming is supported because you can stream things from the server, but you cannot stream things from the client to the server without using something like WebSockets or some other technology that lets you do that. But that's a whole other spectrum of problems to be discovered when implementing that with gRPC.

00:08:23.000 --> 00:08:46.000
<v Glen (Plabayo BV)> Yeah, yeah, I understand. Yeah, that's what I was wondering because you want your web sockets. I guess you could try it, but it might have its own issues, like you say. Even though, because in the end, as far as I understand WebRTC, sorry, sorry, WebRTC, as far as I understand WebGRPC, then you go to JSON, right? Where you JSON and code the, no, no.

00:08:46.000 --> 00:09:44.000
<v Lucio Franco> No, it's protobuf as well. You can be JSON or protobuf. The actual encoding in the frame is independent of gRPC. So gRPC itself actually can support JSON. It can support anything else. As long as you have the right encoders and the two implementations agree, ⁓ the content type can change. And there are protobuf implementations in the browser. So it continues to be protobuf. Really the only limitation is around the client side streaming. And I think there's a couple like strange... header limitations that are not usually a problem. ⁓ There are just some natural just limitations and how, there's no multiplexing and there's a single stream and the way the headers work. believe, yeah, if I remember correctly, there's some custom ⁓ trailing header ⁓ stuff needs to be implemented because HV1 does not have trailing headers. So there needs to be a way to indicate that the body is complete and that you're not sending the header. ⁓ So there's some custom logic there that... There's not that much code, but it enables that.

00:09:44.000 --> 00:09:52.000
<v Glen (Plabayo BV)> and I suppose that is just done as part of the body where maybe the streaming body of the server is just giving an ending here.

00:09:52.000 --> 00:10:26.000
<v Lucio Franco> Right, because the way H2Frames work is they have ⁓ the frame itself, it kind of has a couple options in it. So it can be just a headers, it can be a body, it can be headers and a body, and it can send those however it wants. With HPE 1, you don't have that. You have the headers first, and then you have the body, and EOS, end of stream, right? So they just kind of leverage the right before EOS to send some headers in, and then, you know, the actual decoder has a way to figure out, I saw this flag, you know, every... message is set with a flag and if they have a different flag I know it's headers versus being a body, right? It's as simple as that. ⁓

00:10:26.000 --> 00:10:30.000
<v Glen (Plabayo BV)> So it's kind of like SSC, but then it's kind of like its own protocol, guess.

00:10:30.000 --> 00:10:32.000
<v Lucio Franco> Yeah, exactly.

00:10:32.000 --> 00:10:44.000
<v Glen (Plabayo BV)> Okay, very cool. And then I saw that, and it is unrelated from GPC, but I saw that, like you said, it doesn't have to be protobuf, it can also be JSON. Like, why would people ever do that?

00:10:44.000 --> 00:10:47.000
<v Lucio Franco> That's a very good question. I think I would ask that question larger, why do people write a lot of different types of software, to be honest? People make interesting choices all the time. And in reality, people have different trade-offs. There could be many reasons. I could see someone's logic being that they want to use gRPC, but their entire domain, everything in their domain is built around JSON and not protobuf in mind. And so that's one thing. But you have remember the entire ecosystem is built around protobuf.

00:10:47.000 --> 00:11:09.000
<v Glen (Plabayo BV)> You You

00:11:09.000 --> 00:11:23.000
<v Lucio Franco> As soon as you start to stray away from protobuf, then you start running into limitations of, know, the advantage of using gRPC, which is the cross-language client stuff. like if you're using gRPC just to do rust to rust conversation in between your code, you can do whatever you want. And, and protobuf is, is pretty flexible in that sense.

00:11:23.000 --> 00:11:27.000
<v Glen (Plabayo BV)> Yeah, yeah. Yeah, because I saw in Tonic you have this concept in Tonic around codecs and encoders, decoders, so I guess you could really just do it however you want, like whatever encoding format.

00:11:27.000 --> 00:11:58.000
<v Lucio Franco> Sorry, not part of, GRPC. Yeah. Yeah, and in reality, like the way that we encode onto the wire is just a length delimited frame. So we just have like a, I think it's like a U32 or something that essentially says how big the body is and then it just reads that many bytes and then it decodes that message. So whatever is inside that message, bytes can be decoded however you want. And that's how you can even apply compression or encryption if you really want it. There's a lot of options there.

00:11:58.000 --> 00:12:09.000
<v Glen (Plabayo BV)> and Yeah, very cool. And did you ever see someone trying to use from a browser

00:12:09.000 --> 00:12:56.000
<v Lucio Franco> Yeah, I people do use gRPC web from the browser. There's the JavaScript implementation that you can pull in. ⁓ I think it's a pretty low use case. think the majority of people doing things in the browser tend to go through REST and other more browser focused APIs. gRPC definitely is in the space of microservices and distributed systems, a little bit less browser to backend kind of calls. ⁓ But the advantage is like if you have an API defined in gRPC, it's maybe easier just to... pull in the gRPC web client instead of having to create a separate API on top of that. And there's advantages. Doing things with gRPC, you have code gen, you can move much quicker. So there are advantages. think it's just that the gRPC space has not penetrated into the kind of regular web space as much as other things have like GraphQL or REST.

00:12:56.000 --> 00:13:10.000
<v Glen (Plabayo BV)> Maybe one last question, now that things like Quic is becoming more popular, is there something that people should need to know? Could they just, instead of using h2 frames, they would start to use Quic Streams, or is there some gotchas there?

00:13:10.000 --> 00:16:36.000
<v Lucio Franco> Yeah, so mean, in general, we need to think about why quic was implemented quic was what which is HTTP three was implemented by Google for the focus of improving how mobile devices work on the internet. What's important here is a mobile devices tend to move from cell tower to cell tower tend to have a lot more interference potentially at random times. So essentially a lot more unpredictability and delivery of packets. so if you know the kind of like history around TCP or if you've ever played video games for example, the way that NeverKing works in video games is does not rely on TCP, it uses just UDP because it turns out when you try to do all the features that TCP has, is like correct ordering of frames and bytes, you tend to try to go back and get old things that were missed and maybe that doesn't matter anymore and it can actually slow down the request significantly. In the context of a video game for example, that could mean that you're replaying a state that happened a second ago rather than the current state where the player is now. ⁓ Why this is important is that mobile devices have a similar kind of problem of dropping packets and the set of sensitivity. so QUIC was designed to kind of fill the space. Whereas HTTP2 and TCP are kind of very similar in their streaming semantics. provide these kind of like abstraction layer that say, that give you these guarantees around delivery of packets and frames. ⁓ Whereas QUIC is kind of like, okay, ignoring that sort of thing, I care just about. being able to work on top of UDP and being able to work in environments where I maybe don't have super solid connections, but I can still get the end user's request done in a good amount of time because I can be smart about it. ⁓ Now, what this means for things like gRPC is, remember, gRPC is heavily used in the data centers. It's heavily used in microservices and distributed systems where you tend to have 10 gigabit cables connected between devices. You can really saturate connections and packet loss is a lot less. You have a lot more control in the data center, even things like... tuning the routers to ensure that you have priority over other things. So because of this, the advantage of H3 and QUIC does not show its advantage. And actually I think in some cases is slower, which means high level what this means is like HV2 is still the king of data centers and still the king of being able to completely saturate connections. ⁓ And that's why you have not seen much movement towards H3 in gRPC. ⁓ And you see the movement for QUIC being more in your HTTP layer on your browser and in the kind of like L7 load balancer world where you are kind of, you can leverage these things. For gRPC itself, where you're within a data center, you don't really get that advantage and therefore we tend to stick with H2 and then drop down to H1 if you you really don't have the support. That said, I believe there is an H3 backend in gRPC Java. The potential for having an H3 backend in Rust is pretty high just with the fact that we're kind of built on top of the hybrid ecosystem. And at least Tonic is likely to support H3 in the future if that work ever kind of if Hyper itself can like ship it as a self-contained thing where we don't need to do that much that's likely to happen. ⁓ As for the gRPC Rust developments that we've been working on that's likely just to support H2 for now just because we're probably going to need to drop into the lower level H2 library kind of leaving behind the hyper abstractions just because of the the kind of level that we're taking in gRPC Rust to kind of be above and beyond what Tonic is right now. ⁓ But yeah, at end of the day, think that the answer is what we've seen the data is that H2 is still incredibly good and that QUIC is, well, it's really cool, not really, you know, it has its use cases, right? And we need to think about those trade-offs.

00:16:36.000 --> 00:16:48.000
<v Glen (Plabayo BV)> So maybe the takeaway I take from this as well is that maybe the naming of Ace3 is a bit unfortunate because people might think it's the next version while maybe it's more like an alternative use case.

00:16:48.000 --> 00:17:18.000
<v Lucio Franco> no, I think, I think it's a case of people just need to understand better what the different ones are. Like, I think it's pretty clear that H2 did not delete the need for H1. H1 is still heavily used and there are reasons to use H1 over H2 in certain cases. And so I think it's just a case of really understanding what the technology is doing. And, know, maybe the, the real thing is we do a bad job of explaining what H2 and H3 and H1 are, right? Like maybe, I mean, I don't recommend reading the H2 to be too spec to be honest. So, ⁓ you know. That's probably problem number one. The spec is not very well explained to people and even people that try to implement H2 struggle to decipher what it's saying. ⁓ maybe we can start there to fix the problem.

00:17:18.000 --> 00:17:50.000
<v Glen (Plabayo BV)> No. Very cool. So I want to try to maybe in the future, develop some episodes to maybe experience better the difference between these different HTTP versions and the trade-offs and why one might choose over the other because I totally agree with you. So thank you very much for your time, Lucio. You were in the first protocol short episodes. Let's see if people like it. Bye bye.

00:17:50.000 --> 00:18:03.000
<v Lucio Franco> Thank you. Bye bye.

00:18:03.000 --> 00:18:30.000
<v Glen (Plabayo BV)> With me is Brecht, he's also a maintainer of Rama together with me. He's been a crucial developer in our organization, well, at least an open source organization. And so I'm very happy that today he's joining us ⁓ as he will help us a bit shed some lights on what is possible around H2 and WebSocket. But before we begin all that, Brecht, can you introduce yourself a bit?

00:18:30.000 --> 00:19:47.000
<v Brecht> Thanks for having me. ⁓ Yeah, I'm Brecht. I live in Belgium, actually quite close to Glen So that makes it really useful to discuss work and that's also how I got involved in Rama. But I've actually always been working in network infrastructure like code. It started really early when I was a child. ⁓ I went to the library and they... didn't allow me to use the internet how I would like to use it so I got really creative with VPNs and proxies and all of the things and that's really how I got into network infrastructure and hacking around. ⁓ Then forward many many years and ⁓ my first job is in web scraping which again involves a lot of network infrastructure, code and being creative with network. ⁓ That's also how I got involved in Rama because Rama is really useful for all of these things and it really allows you to do basically all the crazy stuff you can think of and actually quite an easy way. ⁓ But yeah, that's probably the short introduction.

00:19:47.000 --> 00:21:26.000
<v Glen (Plabayo BV)> Okay, thank you very much and also thank you very much for finding time to help us shed some light on these topics. So from our conversations in the recent past, it was very clear to me that you had found some very nice use cases of both H2 and WebSockets. And while they are not like unique discoveries, like certainly not that you invented the hot water here, I do think that they are not... observed in or at least presented sufficiently. I think most people think about HTTP 2 around just, okay, it's the next version of HTTP 1 and it helps us to send requests. It also helps solve some problems. But of course, we also learned from Lucio that we shouldn't always think that HTTP 2 is a replacement of HTTP 1 and HTTP 3 is a replacement of HTTP 2 because actually they all have also their pros and cons. And there is a reason why they all three exist next to each other. Still, HTTP2 allowed some use cases that weren't really possible with HTTP1. And same goes for WebSocket, like the most common use case of WebSockets is something like you need something like a chat client or something and people want to send JSON messages between server and client bidirectionally. But given how it is set up and given how the like protocol actually operates, there are some really nice use cases if you can think slightly beyond what is it usually presented as. So to begin with, and maybe also to refresh our listeners, can you maybe explain a bit what is HTTP2?

00:21:26.000 --> 00:24:10.000
<v Brecht> ⁓ So let's maybe quickly start with HTTP 1 just in general. ⁓ You basically do one request and you get one response and you can only do them sequentially. So they're single use while HTTP 2 adds a major feature ⁓ called multiplexing which means you can reuse a single connection for multiple things at the same time. ⁓ It does this in the most basic form by adding an ID. to every single packet you send and by using that ID it can multiplex. That allows one connection to be used by multiple requests and responses at the same time which makes it really flexible to support a lot of things and a huge upside as well is that you don't always need to open new connections for everything. People tend to forget this but opening a new connection is actually really expensive if you do it fast enough. because TCP and TLS both have handshakes that are quite slow and this becomes especially important if you have slow network conditions or you do a huge amount of requests in a short time. ⁓ So basically HTTP2 allows you to do multiple things over the same connection at the same time. There's some issues with that which is partly why HTTP3 was invented but for most use cases HTTP2 is really fine. especially like in data center conditions. ⁓ But now to get creative with HTTP2. HTTP2 allows you to stream whatever data you want from one side to another side and you can do it at the same time. ⁓ This sounds like it's something you would expect it to do but it's actually quite complex to implement but it opens the door to so many use cases. ⁓ For example, a... Something that sounds like abuse, but it's not really abuse because it's within the spec is over HTTP 2 you can implement a custom protocol to proxy streams, whatever byte stream, but instead of using the normal HTTP connect logic, you would just put it in the request body and put it in the response body and use custom headers to implement your own protocol. And you just basically have a request with a body that never ends and a response with a body that never ends. That's Basically a creative use case of HTTP 2 that many people don't think of but it allows you to skip the initial connect handshake and under some conditions that makes a huge difference. ⁓ That's the short thing like which direction do you want to go in for.

00:24:10.000 --> 00:24:19.000
<v Glen (Plabayo BV)> Yeah, maybe I would like us to intend a bit more like how it works on a protocol level. So maybe before you can actually explain like how you pull that off, like maybe you can explain a bit how is HTTP2.

00:24:19.000 --> 00:24:22.000
<v Brecht> Mm-hmm.

00:24:22.000 --> 00:25:11.000
<v Glen (Plabayo BV)> and code on the wire because with HTTP1 I think most people get it. mean, some people might not get it, like it's easier to explain because it's basically just you start with your status line or you start with your header line, then you have your headers and then you have your body basically. And that's more or less easy to understand. It's also like in plain text, but starting with HTTP 2, we went to a binary format and it's also has a slightly more, well, I would say complex way to encode, but it does make it lot simpler and it allows ⁓ a lot of use cases. It also means that now your bodies are streaming by default, but I'm getting a bit ahead of myself. So maybe could you talk a bit about that? Like how is HTTP 2 encoded?

00:25:11.000 --> 00:27:20.000
<v Brecht> Okay, so maybe to start simple It's good to remember that everything that we send over the network is encoded in some sort of packet format HTTP 1 is quite a simple format HTTP 2 takes this a little bit further and actually has multiple types of frames that called in HTTP 2 So first off something that all frames or more frames include is and identifier which type of frame this is because if you have multiple types you somehow need to know which type you're sending. ⁓ Some of the types of frames there are in HTTP2 are headers frames. Headers is basically what you would see for your request and your response headers. There's other use cases but that's basically what they are. You also have data frames. ⁓ Both header and data frames also include an identifier to know which stream this is a part of. This is how the multiplexing works. Basically when you send a byte stream over HTTP 2, it can be a large request or body, it gets split up into multiple data frames. That's how the streaming works. The internal state of HTTP 2 manages that and then your end application can see this as one big body or multiple small parts. You also have some other frames like settings frames, priority frames, continuation frames, like you have like quite a lot of small implementation details ⁓ Some of them are to manage the connection others are to manage streams There's a go away frame to say like hey, we want a graceful shutdown There's also a reset stream a reset stream is specifically when a request or response triggered something that crashed a specific stream Important detail here is also is that you will only crash a single stream not the entire connection, which is important for many use cases ⁓ But in general, it has multiple frames. Each frame has different meaning. And by adding IDs and stream IDs to these frames, we can effectively ⁓ stream multiple things at the same time over a single connection.

00:27:20.000 --> 00:27:45.000
<v Glen (Plabayo BV)> Okay, and then normally what we stream over there, let's say our data anyway has no protocol, right? Because our data is basically the data frames or just anything that's usually your HTTP payload. But I think for you use case, you were describing that you invent some kind of custom protocol for that. So can you maybe talk a bit about what you're doing there and why and how?

00:27:45.000 --> 00:28:49.000
<v Brecht> This is why I mentioned it feels kind of hacky because in its most basic form you don't really reinvent something new. You can just send a request and you add some sort of custom header to that request. For example, I want to proxy to google.com and you call the header x-proxy or whatever some internal name. And then most of the time if you use a library like everyone does it will just encode those headers. as HTTP to headers and then the body can just be a stream that's an infinite stream and that's basically copying bytes over from whatever other stream you have. we don't really have to invent something new like HTTP works out of the box with this. It's only if you want to add custom logic to there to like even do more crazy things. That's when we come into like territory of gRPC which kind of works like this but it uses headers in a creative way as well to signal status codes at the end of a transaction.

00:28:49.000 --> 00:29:00.000
<v Glen (Plabayo BV)> Okay, and so what would be the difference between that versus using something like the Extended Conext and ⁓ Proxying basically like that.

00:29:00.000 --> 00:29:50.000
<v Brecht> ⁓ Under normal circumstances you want to be using the connect but the way connect works is you have an incoming request ⁓ and let's say you want to use a proxy go to a specific website you're gonna send the connect to the server the server is gonna say okay the connect is ready and then you're gonna start streaming bytes over your stream it's especially noticeable if your proxy server is far away the initial connect has quite a lot of latency because it's a one way, ⁓ a two way handshake and that adds up, like especially have like multiple hops, like all of these add up. With the other approach, you can immediately send data and skip the initial wait type.

00:29:50.000 --> 00:30:14.000
<v Glen (Plabayo BV)> Okay, so it basically operates a bit like what I would call a sneak proxy, where you are sending your requests with all the normal headers that you would normally send to the proxy, but instead of sending it to the IP address of the target server, you send it to the IP address of the proxy. Is that more less how I can imagine it, or you're doing something on top of that?

00:30:14.000 --> 00:30:20.000
<v Brecht> Yes. No, no. the basic form, you can see it like that indeed.

00:30:20.000 --> 00:30:28.000
<v Glen (Plabayo BV)> Okay, and so the biggest reason why you do such a use case is to prevent the initial handshake latency, as you were describing.

00:30:28.000 --> 00:30:42.000
<v Brecht> Yes, especially like depending on how your proxy infrastructure looks and how many geographic data centers you have, you could have multiple of these handshakes and they add up.

00:30:42.000 --> 00:31:04.000
<v Glen (Plabayo BV)> But yeah, and of course given that in HTTP 2 you can ⁓ basically also have trailer headers or headers in between your body frames that should mean you can also maybe set a different header for your X-Proxy target I guess.

00:31:04.000 --> 00:31:29.000
<v Brecht> Yes, you can, yeah that's what I mean, but in the basic setup you don't need to use those, but you can if you want to. ⁓ But yeah, then you can reuse the same stream, or you can open multiple streams, like there's no real cost in opening more streams, like there's some limits, but opening streams is instant and you don't need to wait for the server to confirm it so you don't have that initial handshake latency problem.

00:31:29.000 --> 00:31:51.000
<v Glen (Plabayo BV)> Yeah, true. That is actually quite clever because that means you can just for every destination just have it stream, I guess. Okay, very cool. And then that allows you basically to use HTTP 2 for like your proxy tunneling purpose, but with all the usual handshake and you basically have like a zero round trip proxy in there. Now, ⁓ if we then pivot a bit to WebSockets.

00:31:51.000 --> 00:31:56.000
<v Brecht> Yes.

00:31:56.000 --> 00:32:31.000
<v Glen (Plabayo BV)> You also had some very interesting use cases like there, as I said before, usually people think about the WebSockets in like, I can have some kind of chat service, some chat client in the browser and now it's all dynamic or even something like notifications or some kind of, I mean, even though it's bidirectionally, of course, some people still just use it as like some kind of. status or notification stream single directionally from the server to the client, but you can go bidirectionally and Yeah, maybe first explain a bit. What is web sockets because I am not sure if we ever covered up sockets before

00:32:31.000 --> 00:33:40.000
<v Brecht> Yeah, so basically WebSockets were the solution to someone has an application running in a browser and they need some sort of communication with a server that's duplex. Meaning both the web browser could send messages and receive. In most circumstances, the browser can only send requests and receive responses back, but the server has no way to like send to the browser. There's some other things there like server-side events, but again, one-day action. Websockets allow it in both directions. The main problem Websockets solve is communication that's bidirectional. That's the most basic form of it. To do that, they support some sort of messages to send between them. The message that pretty much everyone uses is a text message, which is just a UTF encoded string. Other message types are also binary, ping pong. Ping can be used to by both sides to send a ping message, the server or the web browser would then send a pong back and that can be used to detect if the connection is still open and healthy. ⁓

00:33:40.000 --> 00:34:15.000
<v Glen (Plabayo BV)> Yeah, and to me it reminds me of like the frames of HTTP 2 because those ping and pong and those data things are all called frames as well. But what I wonder for example, because it's often done over an HTTP 1.1 connection, like how do they achieve the bi-directional nature of it because you could just have the server sending to the client and the client sending to the server, it's not the same as your traditional HTTP one connection where it's like you have your request, you respond. So your request, you respond instead. It seems you can have them both at the same time.

00:34:15.000 --> 00:37:13.000
<v Brecht> Yeah, it's actually easier than you think. It's by running the exact same code on both sides. And ⁓ you basically have a multiplexer or demultiplexer or dispatcher, however it's called. ⁓ But when a message comes in, it decodes the message and then figures out where that message needs to go. HTTP2 is kind of the same. And when you look in source code of HTTP2, there's quite a lot of shared code on both sides. It's only what to do with the actual stuff, that it becomes different what the client and the server are. But encoding and decoding messages is fully the same on both sides. ⁓ Which is also why web sockets are really interesting and you can do quite a lot of stuff with it because you can send messages and you can again make a protocol on top of that. In this context we're talking about frames and how they kind of look like frames in HTTP2. But when you step back a little bit it's actually for every single layer in a network stack, every single layer makes packets and adds some sort of logic on top of that. If you go to like other layers like the IP layer, TCP layer, like all of these again make packets and add logic on top of that fulfilling one need. ⁓ and you already mentioned that websockets mostly work over HTTP1. The main reason to do that is you use HTTP1, you connect to a server and you say hey I want to upgrade, I want to connect with a websocket. It has an upgrade header for that specifically and the server then basically transforms the byte stream from HTTP to just a byte stream that is handled by the websocket. HTTP2 allows something similar. by using extended connect and ⁓ also saying I want to connect with a websocket here. The server can accept that, but the way the upgrade there works, like the IO stream is not the direct IO stream. It has internal state management that transforms a single HTTP2 stream, not the entire connection, just a single stream to use websockets. ⁓ Most of the time you... don't want to use it for WebSocket because it adds quite a lot of logic on top of streams to be able to support that and you have like the entire protocol overhead of HTTP2. Well, for most use cases for WebSockets you don't need multiple streams at the same time ⁓ and it's important to remember like before we mentioned a data stream, a data package just sends the data that's not entirely correct you need like some sort of encoding like how does it know it's a data frame? how long is that data frame, it always adds a little bit of extra information. And if you have WebSockets, you kind of are already doing that. You're also sending which frame it is, how big is this frame. But now you do it twice, which adds quite a lot of overhead if you do it a lot of times.

00:37:13.000 --> 00:38:00.000
<v Glen (Plabayo BV)> That also reminds me again of what Lúcio was saying about we should really like take separately those version of HTTP and see them as one following the other as they clearly have to use cases. In this case, for example, there is a really good use case to use HTTP even though there is HTTP 2 because you don't really benefit from having that entire heavy protocol on top. In fact, it makes it slower and more complex as you said. Now that said, If you take a bit, if you take a bit of context and just see it as what it is, which is like a bidirectional stream of like messages between the client and the server, what are some of the clever use cases that you've observed in the past?

00:38:00.000 --> 00:39:29.000
<v Brecht> Actually a very popular use case is to use WebSockets to do proxying or VPN setups. Most of the time that starts because people are in some sort of restricted area, be it the browser or be it a public library or whatever. But most of the time WebSockets are allowed by everything because it's just normal, it looks like normal website traffic. So people allow it and now we have a protocol. over which you can send messages and as we discussed before each protocol is basically wrapping bytes in some sort of message or frame or however the protocol calls it but WebSockets allows you to send messages so you can do your own protocol on top of that so you can implement proxy logic on top of this a VPN on top of this a completely custom setup on top of it where you just encode bytes in some sort of message that the other side can then parse ⁓ So basically WebSockets is just another way of ⁓ encoding messages and whatever you want to send over that. Like in essence it's always a message or a frame or some sort of packet. They're called different on each layer but they basically do the same. They have some sort of byte input, they wrap it in some sort of frame with metadata and then they pass it one layer up.

00:39:29.000 --> 00:39:48.000
<v Glen (Plabayo BV)> Okay, very cool. And so that also means that given that you can wrap these data frames or data packets, whatever you want call that, you can add some metadata there so you can do multiplexing over your single bidirectional stream. I guess that's how you achieve it.

00:39:48.000 --> 00:40:27.000
<v Brecht> Actually when you see it, like when people use web sockets for like even a basic use case like a chat app, ⁓ they're actually most of the time also implementing multiplexing where they add some sort of ID to each message, to each of the messages sent. Pretty much always just JSON string encoded because it's really easy to get started. But in its basic form that is multiplexing by adding an ID. A protocol like HTTP2 just takes it a little bit further by hiding that completely away from you. But at the end of the day it's just ⁓ AID added to some packet.

00:40:27.000 --> 00:40:39.000
<v Glen (Plabayo BV)> Okay, thank you very much for explanation. I think that clarified it a lot. Is there anything else you would like to share about this or about the earlier discussion around HTTP2?

00:40:39.000 --> 00:41:21.000
<v Brecht> No, not really. one important... maybe a small thing. Like, just... Like you mentioned, there's like trade-offs. And, ⁓ something you're not gonna expect, but like, if you're downloading a very large file, it's actually better to do it over HTTP 1 versions, because, again, you don't have the overhead of the HTTP 2 protocol, where that only really shines if you want to use multiple streams, or you need any of the other more fancy features. ⁓ That's basically a small remark that's probably unexpected to some people or most people actually. ⁓ But yeah, that's that basically.

00:41:21.000 --> 00:41:36.000
<v Glen (Plabayo BV)> Very cool. Well, thank you for sharing this knowledge. I also have a feeling that it won't be the last time that I will have you on the podcast. Now you were in the first protocol shorts ⁓ episodes. So I'm very grateful for your time and expertise, Brecht.

00:41:36.000 --> 00:41:41.000
<v Brecht> Yeah, thank you for having me. It was fun.

00:41:41.000 --> 00:41:46.000
<v Elizabeth (Plabayo)> Netstack.fm is brought to you by Plabayo building secure, open, and resilient infrastructure with Rust protocols, and purpose. This show is also made possible by Rama, the open source networking framework. Plabayo offers service contracts and welcome sponsorships to keep building and supporting its ecosystem. The theme music of this podcast was composed by DJ Mailbox. If you enjoyed this episode, don't forget to subscribe on your favorite podcast platform and leave a five-star review. It really helps others discover the show. Thanks for tuning in. We'll see you next time for the next handshake.

