 Surprise, I'm back. It's been a while, and I apologize. But I thought, we probably have seen enough of Paul's face for a while, so I thought I'd just swoop in and do a video of my own for a change. So here I am. And I thought I'd show you simple HTTP2 server. It's a tool that I've written a long time ago for a Udacity course I did about HTTP and HTTP2. I should probably put the link down here, or in the description, you'll probably find a link to the Udacity course there. And it's a tool that you just download and start, and it serves the current directory over HTTP2. So it's very similar to Python's simple HTTP2 server, to Python's simple HTTP server, but my server does HTTP2. And it needed a new tool because HTTP2 by design is always encrypted and always needs a TLS certificate. And because generating these certificates is really annoying and really time consuming, I just build it straight into the tool. So it does it right away for you, and you just start it, and it spins up, and there you go with the HTTP2. And I wrote it in Go because Go was very early with support on HTTP2 and because I just love Go. But back when I wrote it, they didn't have support for push. And that was one of the big things that I wanted to play around with. So what I did is I basically grabbed the code from the Senate library, put it in my project, and monkey patched support for push in there. But now just a few weeks ago, Go 1.8 came out. And while there's loads of improvements there in terms of performance and garbage collection, but also they now have native support for push. So I could finally throw out my monkey patched version. And I used the opportunity when I was working on the tool anyway to basically do a whole refactor to just split the code up. It was really messy, really grown, and make nice little files and modules, and make it more accessible for all of you out there who may want to contribute to this tool because you want a feature or something. So now the code is hopefully much more modular and much more readable. And I thought I'd just dive in and explain a little bit on how it now works. So before I had a so-called push manifest, and this push manifest was just a way for you to define which resources are supposed to be pushed when a certain request comes in. And Eric Bidelman and I kind of came up with that. And we kind of wanted to make an industry standard. But it turns out that most people already had a solution, and those were HTTP link headers. So now I kind of threw away this manifest idea and went back to basically allowing you to specify headers, because that's something that people wanted to have anyway, because sometimes you want to experiment with caching headers, or you need to set custom headers for whatever reason, when you do server work, for example. So I added that and sketched up a little config because sometimes you wanted to do single-page applications where you need to do rewrites. And I sketched out a config. And in the end, I kind of realized what I had was pretty much the same as Firebase has on their static hosting. So I decided to basically just adopt the entire Firebase config, which is pretty cool, because while Firebase does have a tool to allow your offline development for the static hosting, they don't support HTTP2 or push. And so with simple HTTP2 server, you can kind of do that now. I mean, it's not 100% high fidelity the implementation that I wrote, but so far, it's worked with every project that I have on Firebase. And I thought that's pretty cool. So yeah, after that, I basically just got implementing, and that's what I want to kind of talk about. So if you want to start by getting the code, you would have to go on to GitHub. It is in the Google Chrome org in the wrapper called Simple HTTP Server, who would have thought. And the read me has, hopefully, all the information you need, how to get it, how to install it, but also, obviously, it has the code. And so the entry point to the code, the main function, literally the main function, is in Simple HTTP2 server.go. And it's, in a way, straightforward. It's just a lot of manual config because I'm doing some tricky stuff, which I'm going to explain later. But I do flag parsing, set up the server, and then I have one function which is going to be called for every request that comes in. And this function gets pretty similar to Express, actually, gets a response object where you put in your response and your headers in the response, and the request object that has all the request data. And I basically wrote a function called process with config that takes both these objects and just mangles them according to the config. So if the request matches a rewrite rule, it will just rewrite the request. If the request matches a header rule, it will add these headers to the response, and then just returns. And what you get back is you figure out if you have to redirect it because then you stop, or otherwise, you will push the resources if there's any link headers. Or you will grab the files from the file system that you need and just push them out to the client. And I have one bit. I used the Gzip implementation from the New York Times. They have a Go implementation for Gzip, not for Gzip, but for an HTTP-compatible version of Gzip, where as long as I'm sure that the contents of the file are text-based, I'm going to run it through Gzip. And I think a lot of local development tools are missing out on this feature, because in production, you almost always want to have Gzip enabled, especially for CSS, because there's so much wins if you enable Gzip for CSS. And in local development, you kind of miss out on these gains, and so you might spend time optimizing things that don't need optimizing. So with simple, if you serve, you always have Gzip enabled for local development, which I think is pretty important. And if it is Gzip, then I just put it up the files. And that's basically the whole request-response cycle. So I've been mentioning push, but I said I removed the push manifest. So how does it work now? So most CDNs use a link header, the HTTP link header. And if it has a rel equals preload, the CDNs like Cloudflare or Akamai will turn this header into an additional push. So if you look into the readmate further down, you will have an example with a header down here where I say the key is link. So I'm specifying a link header. And the value is the file that I want to push in angle brackets. And then I say rel preload, because only rel preload will be pushed. There's also prefetch, which will actually make the browser download and parse the entire file. So preload is a little different. And usually, it's also a good idea to specify what this file is, if it's an image or a script, because the browser might prioritize how much bandwidth to allocate to that push. But that's soft that this tool allows you to play around with an experiment. So this is now how you do pushes. And another thing I want to touch on which I thought was, I felt a little bit smart after doing it, but then it turns out a lot of people do that already. But still, I totally thought I came up with it, is the hijack HTTP listener that I wrote. If you look into the hpbsdetect.go, what I'm doing here is, for web server, usually you open a listener on like port 8080 or some port that listens for incoming connections, and then it gives a connection. And usually, that connection is handed to the web server. And the web server reads from the connection, does the HTTP protocol parsing, all that kind of shenanigans, and sends back a response via that connection. This hijack listener basically is a wedge in between the web server and the listener. Because the problem is that if you bind an HTTPS web server, which HTTP2 practically is, to port 8080, and you type localhost colon 8080 in your browser, the browser will attempt to connect using HTTP plain text. And it's just going to fail, because the browser sends a plain text request, but the server is trying to do a TL as handshake, and it's just going to fail miserably, and it's going to close the connection. So what I'm doing here, basically, is I'm taking the connection before it gets to the server implementation, and checking if the first byte on the connection is the number 22. It's a check I'm doing right here. If it's the number 22, I can be really sure that it is an HTTPS connection, because the first byte of the TL as handshake is byte 22. So if that happens, then I say, I'm fine. Continue. Go to the web server. If it's not, however, I have basically just ignore whatever the server is that the client is sending me and just dump a redirect response to the browser. So the browser knows, oh, I have to reconnect via HTTPS, and now it will be an encrypted connection. So now, even if you forget to type an HTTPS, it will redirect you, and you won't even notice. So it always works, which I thought is super helpful, because I didn't have that before, and it was super annoying. So this is a really neat little trick that I found, and I thought it was kind of cool. I guess we could talk a little bit about the Firebase config. Basically, in Go, you usually take any kind of JSON file by defining a struct, and that's what I did here. So I just wrote down what the JSON looks like as a struct, and the Go JSON parser just will fill in the fields for me. So it's super easy in Go to read JSON files. And then I just take, as I said, with a process function, take, response, and request, and go through all these rules and do whenever I find something that matches this request. The only problem here is that Firebase shows not an art format, but the way you define patterns to limit rules to only to certain requests, they use globbing. So I expect reg access, usually, but they use globbing. And globbing is what you usually use on shells. So if you type something like star.js, it means every file that ends in .js. You probably have encountered this. And these are extended globs, which add a few more capabilities to this so-called globbing. So while star only matches files on the current directory, star star means all the files in this directory and all other directories below this. You have a syntax to group multiple file endings. But the problem is that this is kind of a very note specific syntax, and there is no package for it and go. So I had no choice but to write my own. And I thought, I'm not going to explain how it works. But what I'm doing is I'm taking the glob string and using simple string replace functions to turn the glob into a rex. And I'm going to leave it as, let's call it an exercise for the reader to read this code and understand it and explain why there is a pig emoji in the middle. So enjoy that. But basically what it allows me to do is to compile these extended globs and turn it into rexes. And then I can use the old rex matching functions to see if a request should be mangled with this rule or not. So I thought, that's kind of like in need little detail. And something I want to touch on in the end is that in the repo, you find all the instructions on how to install it on your system. So if you have go installed, you can just type go get and install simple H2 server. If you don't have go installed, you can find binaries in the release section, which I link to here. So you just click there. And you'll see for every release, I upload binaries for macOS, Linux, and Windows. So whatever system you're on, you should be fine. I also have Linux on binary. So you can use it on your Raspberry Pi if you are into that. I have it running at home on my Raspberry Pi, which is kind of cool. I also added a brew formula, which makes it really easy if you're on macOS to just tap into the brew keg. I think they call it. And install it by that and keep up to date, because automatically updates with brew. And also recently, I added a Docker file, which I thought was pretty neat, because you don't need to have anything installed on your system except Docker and can serve the current directory via simple HTTP2 using the Docker image. And then if you wanted to, you could even push the Docker image to Google Cloud Platform and share it with a colleague. However, I just want to mention simple HTTP2 server is not a production-ready web server. It's meant for local development. So I didn't do any profiling performance optimizations. I didn't even think about security. I think by default, it's completely course-enabled. So it just opens up everything to the world. Don't use it in production. It's for local development. But if you want to fix something up, then I feel much more comfortable now inviting you into this repo, because now the code is actually more approachable. So if you want to do that, feel free to go to the repo. I'll put links to all of this in the description. So you can just click and go there, maybe start. That would be nice. Also, if you like this video and want more of those, you should probably subscribe, because then you'll get notified about new videos. And I think that's it for this video. And it hurts me to say, but I guess the next video is going to be Paul again. Well, stick around if you want to see that. See you next time.