Show HN: 100 LOC Ruby forward proxy using only standard libraries
github.com
github.com
Edit: just checked on one of my projects. Looks like about 600 lines of C for an HTTP server that only uses stdlib’s memory allocation and string manipulation functions as well as socket IO. For an additional 20 or so it works over HTTPS. That was rather difficult to write and I’m sure has at least two bug I am not seeing. See http.c and server.c in https://github.com/ipartola/hawkeye
I appreciate projects like this as a newbie. People say, “you can learn a lot by reading other people’s code.”
Unfortunately, most of the projects I try to learn from are quite large. It can be overwhelming to dissect. A project like this which sticks to the language (with few or additional libraries) allows me to pick apart what everything does.
I am just being overly pedantic about the 100 LOC thing because it's been used over decades as a kind of badge of honor/bragging rights. If you implement something that really relies on nothing in N LOC then it's warranted. If it's just a teaching tool, like this is, I feel that it's better to present it as "Show HN: how I learned about HTTP support in the Ruby stdlib and wrote a toy proxy server". The README for this project actually makes it sound like this is something you could use in production, which you absolutely should not.
req_headers = Hash[req.header.map { |k, v| [k, v.first] }]
It's good that you figured out how to do that, and it's useful. But that is not a 1 LOC HTTP header parser. It's an invocation of an opaque header parser that you do not understand. You might not even know what an HTTP header looks like and still write and use the above code.Interestingly, above that code they write headers by hand. Those at least to me don't look right: they don't escape header values or handle multi-line headers. Probably should have used stdlib to write that part of the code.
I really don't mean to pick on this particular project. I just don't really get impressed with "X in Y LOC" when all it's doing is invoking the services of a standard library. I guess when you are coming from the NPM world where you need 1000 dependencies to concatenate two strings it seems really cool to only do something with the tools included. But better ecosystems allow you to do a lot more with the batteries included, which means your LOC will be really low until you do something more interesting.
Which isn't to say doing hard stuff is bad either. I've written simple servers in C as well, and those are fun projects that you can learn a lot doing. But I don't think that there's anything wrong with posting stuff like this.
https://smartproxy.com/blog/the-difference-between-a-reverse...
One of the first and most powerful reverse proxies was mod_perl running under httpd. Typically 5 or 6 mod_perl instances can handle requests from 300 normal httpd children.
So when somebody says "forward proxy" they usually mean "not a reverse proxy."
* may show that Ruby can do a lot on its own.
* may show that a developer doesn't have to depend on another gem just to get the job done.
The Ruby stdlib is powerful, and depending on another gem could bite you if it were to become unmaintained at some point.
However, low LOC and use of stdlib isn't always the goal for development in-general.
I want to develop solutions quickly that work well and are easy to maintain. If it's easy to learn also, even better.
In terms of the size of the code, even in text form, there's a lot I could do. I could reduce lines by replacing EOL with semicolon. I could remove unnecessary spaces. I could use shortest variable names. I could store a compressed version of the code in the file and then do eval of the decompressed version. Those don't make it a better solution, unless the goal is to obfuscate and/or minify it.
I know that's not the point, though, and I'm mentioning it only so that people will think about LOC as what it is- just a metric.
"WEBrick is an HTTP server toolkit that can be configured as an HTTPS server, a proxy server, and a virtual-host server."
So I'm reading it as 100 loc of setup to use a proxy toolkit to invoke a proxy.
It's got a couple more features than OP, check out the README.
Go was made for this kind of problems. It is very easy to write efficient networking code on go that can be read and understood by mere mortals.
BTW, Github counts 149 SLOC just for this file: https://github.com/jamesmoriarty/forward-proxy/blob/769b6424...
https://github.com/gophergala2016/goxy/blob/master/goxy.go
And a forward proxy that supports middleware like adding CORS headers, logging, etc...
I don't expect the performance to be great, considering it is opening up a new connection to the forwarded host for every request. https://github.com/jamesmoriarty/forward-proxy/blob/bc7d9ec1...
From the sloc count on GitHub just the server file alone is listed as 149.
This also uses WEBrick to do the HTTP parsing. The webrick gem is no longer bundled with Ruby as of 3.0.0.
(I myself would love to code in rust - once the spec and implementation become more stable. Given the current pace, maybe in 2030?)