
Facil.io: A micro-framework for C web applications - anderspitman
https://github.com/boazsegev/facil.io
======
tom_mellior
I like the use of keyword argument syntax to specify optional arguments. I
haven't seen anything like this before in C or C++, and now I would wish for
it to become standard.

It's simulated cleverly using a macro that wraps variable arguments in a
struct literal: See the definition of http_set_cookie in
[https://github.com/boazsegev/facil.io/blob/master/lib/facil/...](https://github.com/boazsegev/facil.io/blob/master/lib/facil/http/http.h)

~~~
jolmg
That's really cool, but don't unassigned fields have undefined values? How
would the function know what was set? I imagine that in practice they're
almost always 0, but that's not guaranteed, right? You'd need to set the
struct as {0}, to have everything be 0. Is this a feature of a new(ish)
standard?

~~~
hawski
It is guaranteed per C99. It's a compound initializer.

Also if you set a struct with {1} the first field is set to 1 and the rest to
0. AFAIR it was always like that (at least since standardized C, but probably
earlier).

------
beefhash
If you want to do web applications in C, you may also be interested in the
kcgi[1] and ksql[2]. kcgi takes a more traditional approach by using CGI
rather than embedding a static file server in the final binary.

[1] [https://kristaps.bsd.lv/kcgi/](https://kristaps.bsd.lv/kcgi/)

[2] [https://kristaps.bsd.lv/ksql/](https://kristaps.bsd.lv/ksql/)

~~~
jondubois
CGI adds simplicity and interoperability but takes away control and
performance. FastCGI suffers from the same fundamental issue as well but to a
lesser extent.

------
EdSchouten
There is also Ulfius:
[https://github.com/babelouest/ulfius/](https://github.com/babelouest/ulfius/)

~~~
striking
And [https://kore.io](https://kore.io)

~~~
bitconion
and worth to mention libh2o in h2o
[https://github.com/h2o/h2o](https://github.com/h2o/h2o)

------
badrabbit
Honset curiosity: is there a reason Golang or rust couldn't perform same or
better? I get why as a programmer I would use C, but what benefit does it have
for the users of the app?

~~~
loeg
Sure. Go is a garbage-collected language with an immature and unsophisticated
compiler toolchain, compared to the big free C compilers like GCC or Clang.
The compiler limitations are solvable but GC is a core part of the language.
Interoperability with C libraries is possible but not great.

Rust is built on LLVM, much like Clang. C integration is relatively easy. I
think this is more viable than Go. Unfortunately, Rust is only portable to
platforms LLVM supports. While that covers the majority of commonly used
hardware today, it is not comprehensive. Also, Rust compile times are pretty
bad, especially for optimized builds.

At the end of the day the author gets to write code in a language of their
choice to scratch their own itch. End users don't care at all what language a
web framework is written in.

~~~
burntsushi
Rust is no more a garbage collected language than C is. Just as one can
implement reference counting in C, one can do the same in Rust, but it is not
forced on you just like it is not forced on you in C.

~~~
loeg
I consider the standard libraries part of the language. C stdlib does not
include ref counting, nor is there any refcounting construct available without
building it yourself. Rust obviously has Rc<> and Arc<>.

~~~
burntsushi
> Rust obviously has Rc<> and Arc<> and uses it widely in the standard
> library.

No, it's not. None of the core data structures (String, Vec, HashMap,
BTreeMap, VecDeque), for example, use it.

Rust is not a garbage collected language in any meaningful sense of the word.
Its runtime is approximately the same size as C's, and the vast majority of
all memory management in the Rust ecosystem is done with traditional
malloc/free calls. The only difference between Rust and C at this level is
that Rust inserts those calls for you automatically. In exchange, the space of
programs accepted by the Rust compiler is smaller than what is accepted by a C
compiler.

> At the moment it is a garbage-collected language but IIRC they are trying to
> move away from that as a requirement.

No, we're not. Because no such requirement exists and the vast majority of
Rust code doesn't use reference counting at all. If anything, there are some
folks that have looked into _adding_ tracing garbage collection to Rust as a
library.

~~~
zozbot123
> In exchange, the space of programs accepted by the Rust compiler is smaller
> than what is accepted by a C compiler.

The space of _safe_ programs accepted by Rust is indeed smaller, but you can
use the `unsafe` keyword if that is an issue. There are even automated
transpilers from C to `unsafe` Rust.

------
polotics
The example has functions' string parameters and separate parameters for the
string's length. Is this really necessary what happens if the declared length
is more than the actual length?

~~~
tom_mellior
Knowing nothing about this, I would guess that this is to allow sending binary
data that contains embedded null bytes?

Though I guess it would be good to have nicer wrappers for the common case
where you do only send text.

~~~
loeg
Probably they use length-prefixed strings internally (which is probably a
requirement for taking a C web framework seriously), but allow C nul-
terminated strings at the API boundary for convenience of use.

------
IloveHN84
Where's TLS? And http/2?

~~~
doctorpangloss
People who serve SSL out of their Java servlets by installing certificates to
random Tomcat and Linux system directories are already a little crazy.

You'd have to be a real maniac to serve TLS in someone's random C framework.

------
scegit
Pretty cool! but it doesn't support HTTP2 which is a bit disappointing

~~~
loeg
The FreeBSD project has been dealing with HTTP2 interoperability hell over the
last month. (Curl 7.62 may or may not talk to Phabricator if HTTP2 is enabled;
it seems to depend on some local conditions and the phase of the moon whether
it works or not. HTTP1.1 just works.) Given that experience with HTTP2, I'm
quite happy to stick to HTTP1.1 for now.

~~~
scegit
HTTP1.1 is expected to just work it has been here for a very long time. It
takes time to understand, support and adopt new technology. I'm not sure if
the blame should be on HTTP2 in this case.

~~~
loeg
Regardless of who the blame should land on — I don't have a strongly held
opinion about that — the point remains that HTTP1.1 _is_ a super old, well
understood, relatively simple protocol that everyone has done correctly for
years. In comparison, HTTP2 is the new, more complex thing and it's
understandable there are growing pains and incompatibilities. I just don't
want to debug those issues in something that worked great for me on HTTP1.1.

------
pvtmert
only thing i did not understand is port being string/char*

other than that, clever api

~~~
loeg
Probably for getaddrinfo():

[http://beej.us/guide/bgnet/html/single/bgnet.html#getaddrinf...](http://beej.us/guide/bgnet/html/single/bgnet.html#getaddrinfo)

~~~
ape4
I see you can use a name (rather than a number) for the port like "ftp" or
"http".

~~~
loeg
Yep. On a unixy system, check out /etc/services.

