10 ms·
Show HN: Micro HTTP server in 22 lines of C
- Galanwe 5y agoNot sure what's so amazing here that it deserves to be on HN front-page. So basically it's a C program that reads "GET /<something>" from a socket and replies with the content of file <something> (with some random error handling) . Is it really that amazing that it fits in 22 lines of funky formatted C code...?
- 0des 5y agoCome on man, it's Saturday. It's fine.
- exDM69 5y agoAnd it's a "Show HN" post. Pretty nice obfuscated C too. It's art, not serious.
- nuclearnice1 5y agoEverything is just dirt.
- cpach 5y agoAnd anyone who ever played a part Oh, they wouldn’t turn around and hate it
- deleted 5y ago[deleted]
- bruce343434 5y agoSure, IOCCC exercises are ones in futility, in the same way that breaking a speed running record achieves nothing real-world useful. But that doesn't mean it isn't spectacular and damn impressive.
- shric 5y agoAside from using small variable names and odd whitespace, it isn't particularly obfuscated.
- jpegqs 5y agoThis is what I am arguing about with another IOCCC winner. What can be called obfuscation, and where are its boundaries.
- snet0 5y agoThat's what I was going to say. If nondescript variable names and poor use of whitespace is obfuscation, a few of my friends could submit code they write every day.
- Galanwe 5y agoCome on there is no obfuscation here, you can literally read the code without issue. The only attempt seems to be 80*101 for 8080.
- jpegqs 5y agoIt's cool if you can read code like this without issue. I'm chasing Kolmogorov complexity, rather than obfuscation. I add things like this to fill gaps in a specific shape.
- cpach 5y agoBeauty is in the eye of the beholder
- Tempest1981 5y agoOr beautifully formatted: https://github.com/ilyakurdyukov/ioccc/blob/main/practice/2021.07-http/prog.c https://github.com/ilyakurdyukov/ioccc/blob/main/practice/20...
- mianos 5y agoAlso, if you want to include #include <microhttpd.h> you can write a useful, safe (well tested), http server in a similar number of lines.
- rijoja 5y agoWhy not #include<stdlib.h> and just run system("apache2")
- Koshkin 5y agoTried it, didn’t work. (Now I want to try system(argv[0]) for some reason…)
- secondcoming 5y agoThat would defeat the whole point of the post! But microhttpd is fine is you want a minimal server; its way of handling POST bodies is weird though.
- deleted 5y ago[deleted]
- milansuk 5y agoThat's the beauty of original HTTP - simplicity. Same as parsing HTML(in the 90s). With HTTPS(S as Secure) it's a whole different story and most programmers use some library.
- nly 5y agoNo, parsing HTTP/1.x is a nightmare and definitely not simple. It wasn't even particularly well defined until 2014 when the original RFCs were modernized, and even now there are bugs reported in HTTP parsers all the time. Node.js came out in 2009, a full ten years after HTTP/1.1 (RFC 2068) and its original http-parser is rather hard to follow, doesn't conform to the RFCs for performance reasons, and is considered unmaintainable by the author of it's replacement[0] As for parsing HTML, well go look at how Cloudflare have stumbled[1] [0] https://github.com/nodejs/llhttp https://github.com/nodejs/llhttp [1] https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/ https://blog.cloudflare.com/incident-report-on-memory-leak-c...
- ibraheemdev 5y ago> Node.js came out in 2009, a full ten years after HTTP/1.1 (RFC 2068) and it's original http-parser is full-on spaghetti code, doesn't conform to the RFCs for performance reasons, and is considered unmaintainable by the author of it's replacement That's because of the way the parser is written. There are other simpler parsers that are much more readable.
- hdjjhhvvhga 5y agoThe fact that someone wrote a parser that's hard to follow doesn't mean that parsing HTTP/1.x is extremely difficult. What is really hard is to construct a parser that is at the same time (1) fast, (2) complete, (3) secure. It is much easier to choose just two, compare e.g. the one based on Nginx[0] vs picohttpparser [1]. [0] https://github.com/Samsung/http-parser/blob/master/http_parser.c https://github.com/Samsung/http-parser/blob/master/http_pars... [1] https://github.com/h2o/picohttpparser/blob/master/picohttpparser.c https://github.com/h2o/picohttpparser/blob/master/picohttppa...
- gberger 5y agoI know this is just for fun and not intended for production use. But what could be potential exploits and vulnerabilities in this server?
- sneak 5y agoGET ../../../etc/passwd
- asah 5y agosandbox it? e.g. docker, OpenBSD chroot?
- jpegqs 5y agoI have provided protection against this.
- Someone 5y agoI don’t think it compiles on windows (netdb.h doesn’t exist there, I think), so you’re fine there, too, from a security viewpoint. However, if somebody did a quick and dirty “make it compile” port (include winsock2.h instead and, possibly, replace some functions/argument types), I think that would create security vulnerabilities because the fopen on Windows might support using backslashes as path separators. Even if it doesn’t, there’s UNC paths (https://en.wikipedia.org/wiki/Path_(computing)#Universal_Naming_Convention https://en.wikipedia.org/wiki/Path_(computing)#Universal_Nam...) to worry about. That made me wonder whether other OSes might have similar features. Reading https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap04.html https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd..., I’m not sure that forbids Unix from doing something similar. It says “A pathname that begins with two successive slashes may be interpreted in an implementation-defined manner, although more than two leading slashes shall be treated as a single slash.” That opens the door for doing special things for paths that start with //, for example by supporting “//machine:foo/bar/baz” on clusters.
- snet0 5y agoI was surprised to read that this is actually a totally valid HTTP/1.1 application, according to the RFC. The only thing you need is the status line (http version, status code, status message, CRLF) and then the message body. Things sure have come a long way.
- deathanatos 5y agoTwo CRLF pairs (one to terminate the status line, one to terminate the (empty) headers), which this is one CR short of. Trivially fixable, though it'd mess up the P slightly…
- jpegqs 5y agoThanks for noticing this, I fixed it on github. However, it seems that browsers are simply ignoring CRs. So that "\n\n" is enough.
- deathanatos 5y agoYeah, I would expect browsers to do a number of non-standard things. It is possible with most of them to construct & send malformed requests.
- kevinoid 5y agoIt's neat, but I don't believe it is a compliant implementation of HTTP/1.1 (or 1.0). For example, it does not handle percent-encoded characters in the request URI.[1][2] [1]: https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1 https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1 [2]: https://www.w3.org/Protocols/HTTP/1.0/spec.html#Request-URI https://www.w3.org/Protocols/HTTP/1.0/spec.html#Request-URI
- deleted 5y ago[deleted]
- codetrotter 5y agoThe ASCII-art formatted version is pretty nice looking. I was going to say that I don’t however get why the “almost readable version” is weirdly formatted. But then I ran it through clang-format and it looks the same still and I saw that indeed it’s because it’s made to do lots of things on the same line and so it is not for lack of white space that it looks so messy. In conclusion, the “almost readable version” is exactly what it should be in this case.
- 34qlgkaer 5y agoMan I wish I could just read some software articles wihthout covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid covid
- coderzx 5y agoGreat
- SV_BubbleTime 5y agoOn the line after the printf where it looks like they’re getting status strings for returns… it looks like there is are three ternary options. Is that right? How does that work? https://pbs.twimg.com/media/E7mllyLXoAQmjbT?format=png&name=large https://pbs.twimg.com/media/E7mllyLXoAQmjbT?format=png&name=...
- jpegqs 5y agoI can explain it: m = n ? /* if (n != 0) */ /* adds index.html if path ends with "/" (means the filename is omitted), otherwise copies zero */ strcpy(b+i-1,b[i-2]-'/'?"":"index.html"), /* log the requested filename to stdout */ printf("%s\n",b+5), /* if "/." is in the path or an error occurred while opening the file */ strstr(b,"/.")||!(f=fopen(b+5,"rb")) ? "404 Not Found" : "200 OK" : "501 Not Implemented"; /* if (n == 0) */ By filtering filenames with "/." I prevent exploits with ".." and also don't allow to read files starting with a dot, these are hidden files in Unix-like OS.
- SV_BubbleTime 5y agoAh. I see, figured it might be that but it was tough to read. Ok, so sometimes I think I know C pretty well, then I’ll see lunatic code like this and realize I Do Not! Thanks for the answer and reformat.
- formerly_proven 5y agoWhat about "GET //etc/passwd"?
- NieDzejkob 5y agoJust fired up the server and that does indeed break it. I suppose openat2 with RESOLVE_BENEATH and AT_FDCWD would be a bullet-proof fix, but that's not very codegolf.
- jpegqs 5y agoYes, that's a vulnerability, I have fixed it on github.
- lifthrasiir 5y agoReminds me of 2001/cheong [1]. #include <stdio.h> int l;int main(int o,char **O, int I){char c,*D=O[1];if(o>0){ for(l=0;D[l ];D[l ++]-=10){D [l++]-=120;D[l]-= 110;while (!main(0,O,l))D[l] += 20; putchar((D[l]+1032) /20 ) ;}putchar(10);}else{ c=o+ (D[I]+82)%10-(I>l/2)* (D[I-l+I]+72)/10-9;D[I]+=I<0?0 :!(o=main(c/10,O,I-1))*((c+999 )%10-(D[I]+92)%10);}return o;} [1] https://www.ioccc.org/2001/cheong.hint https://www.ioccc.org/2001/cheong.hint
- ducktective 5y ago`curl -s https://www.ioccc.org/2001/cheong.hint https://www.ioccc.org/2001/cheong.hint | nc termbin.com 9999` https://termbin.com/5yaq https://termbin.com/5yaq In short: for a 2n-digit input, returns the integer part of its square root (n-digits)
- Trung0246 5y agoIs there a tool that automatically generate minified code like this but with ascii art? Or do these code snippets are done by hands?
- lifthrasiir 5y agoThere are some tools, but in general it is easier to do so manually---you can alter the code when the picture doesn't seem to fit in the template, while tools generally can't.
- LinAGKar 5y agoIt's only that short because they've shoved a bunch of statements onto the same line.
- phoe-krk 5y agoThat's the whole point of IOCCC. The way code is formatted is as important as the way it functions.
- lmilcin 5y agoIt says "22 lines of C", not "22 statements of C". For this type of exercise it is assumed that some readability is going to be lost... just look at Perl golf competition. These tend to be written in a single line and it is not always given you are going to even be able to tell where statements start.
- LinAGKar 5y agoYes, and bragging about the line count is completely meaningless when you're arbitrarily merging lines.
- alanjay 5y agoReminds me of ultra: https://github.com/MarquisdeGeek/ultra https://github.com/MarquisdeGeek/ultra