In my previous article, I had written a very simple and basic reverse proxy. It is just like Nginx but without all the usefulness. I learned a lot from writing that and I hope it is useful to others as well. The previous version of the proxy server had a few issues. It was not a continuous stream. The connection often broke and was requested again. While doing a wget, it would send multiple requests to get the whole page. It could also not handle too many concurrent requests.
In this new code, I have used tokio.rs. Tokio provides runtimes for asynchronous programming. A runtime bundles services together and makes a single type of (for want of a better word) process, service, runtime, etc. This makes it easier to shut down, started, etc. In the code below, I have used TcpStream and TcpListener from the tokio library and not std. I have also spawned for tokio threads and within that, tokio tasks, which are sort of like green threads, but not quite because Rust does not natively support it.
Async/await along with tokio tasks improved concurrency by a lot! Wget does not stall no matter how fast you execute the next one. I even tried bombarding it with 1000 requests concurrently using 2 threads. The connection broke around 20 times, but it is quite a good result given the simplicity of the code.
There are many more improvements and fixes to be made. I still cannot handle large streams. I get a memory overflow error, and a new request will be sent to get the rest. I would like to dynamically allocate the buffer to read so that this can work better. I will be asking the Rust community for help on this. If anyone who reads this article, gets a solution please let me know. Please reach out with anything.
Here's the code: