Commit graph

40 commits

Author SHA1 Message Date
Laslo Hunhold
a36b901d40
Add http_send_body() and data_send_error() and refactor
This turns the data-functions into the only functions "allowed"
to send body-data (called with http_send_body()). The previous (hacky)
approach of doing this in http_send_header() is not only out of place,
it's an easy source of bugs given, for instance, the sending of body
data is not expected with HEAD-requests.

Given html_escape() is now only used in data.c, we move it there from
util.c and make it a static method again.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-29 00:49:16 +02:00
Laslo Hunhold
db127723c6
Rename functions in data.h and adapt ifdef
Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-28 23:46:12 +02:00
Laslo Hunhold
a94b15814c
Rename resp.{c,h} to data.{c,h}
The methods in data.h only deal with the actual response data, not
the request handling itself, which has been formalized a bit more
in http.h. To avoid confusion, we rename it to data.h.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-28 23:29:54 +02:00
Laslo Hunhold
9a95d9183c
Rename status to s in serve()
This is more consistent with the codebase.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-28 23:19:29 +02:00
Laslo Hunhold
68e4ff3021
Return proper error-status when http_send_header() fails
Explicitly show that we set the status of the response struct to the
returned error status. This makes it clear that we are beyond the point
where the "form" of the response struct matters and it's now only about
the log-output.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-28 23:16:47 +02:00
Laslo Hunhold
c0909c70e4
Improve http_prepare_response()'s error semantics
I don't like the juggling with status-values in serve. It makes
sense for http_recv_header() and http_parse_header(), because we
don't have a response-struct yet that we can "fill". We could pass
it to them, but that would make the usage a bit messy.

However, in http_prepare_response(), we are already entrusted with
a pointer to a response-struct, and just failing here (by returning
an error value) leaves the response-struct in an invalid state. Instead,
we make it a void function and reflect the status using the status field
in the passed response struct.

This way, there is no case where the response struct is in an
invalid state after calling a http_prepare_*()-method.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-28 22:52:04 +02:00
Laslo Hunhold
123f168a3b
Replace http_send_status() with http_prepare_error_response()
This approach fits better in line of first initializing the response
struct and then sending the header with http_send_header() later.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-28 22:34:46 +02:00
Laslo Hunhold
1ccaac023c
Rename s to srv
This improves readability a bit and helps iron out confusions with
status-variables called s in other methods.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-23 11:03:18 +02:00
Laslo Hunhold
50c85ec642
Rename "target" to "URI" where appropriate
Of course URIs point at "targets", but the URIs themselves should
be called what they are, not only in the interest of clarity in terms
of nomenclature.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-22 23:38:38 +02:00
Laslo Hunhold
58d0f44e03
Refactor http_send_response() into http_prepare_response()
The function http_send_response() did too much. It not only took
the request fields and built them together into a response, it
delegated too little and many functions were "hacked" into it, for
instance shady directory-changes for vhosts and hand-construction
of response structs.

The preparations for a rework were already made in previous commits,
including a tighter focus on the response-struct itself. Instead of
doing everything locally in the http_send_response() function, the
new http_prepare_response() only really takes the request-struct and
builds a response-struct. The response-struct is expanded such that
it's possible to do the data-sending simply with the response-struct
itself and not any other magic parameters that just drop out of the
function.

Another matter are the http_send_status()-calls. Because the
aforementioned function is so central, this refactoring has included
many areas. Instead of calling http_send_status() in every error-case,
which makes little sense now given we first delegate everything through
a response struct, errors are just sent as a return value and caught
centrally (in serve() in main.c), which centralizes the error handling
a bit.

It might look a bit strange now and it might not be clear in which
direction this is going, but subsequent commits will hopefully give
clarity in this regard.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-22 23:20:00 +02:00
Laslo Hunhold
a5163d0813
Split up http_get_request()
The function has become too long and basically did two things: Receiving
the header and parsing it. To better reflect this, we split it up into
the two functions http_recv_header() and http_parse_header(). This way,
we also obtain a better separation of concerns and can further reduce
the scope of each parameter-list.

http_recv_header() has been written in such a way that it can be
reentered and fill up the header-buffer bit by bit using a pointer to
an offset value.

The error handling was improved by only returning the immediate error
status codes and letting the caller do the error-handling with
http_send_status().

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-22 11:05:20 +02:00
Laslo Hunhold
c1b242e405
Add connection struct
This struct contains the request and response structs, represents a state
and has some utility-buffers.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-22 09:24:57 +02:00
Laslo Hunhold
6d2fe7f29e
Move infd and header into request-struct
This compacts the connection state into one struct.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-21 19:38:29 +02:00
Laslo Hunhold
65600ffe7a
Reduce global state by localizing the server-struct
The server-struct variable s was global, which made it readable and
modifiable from any point in the code. Making it a local variable in
main() instead and passing it as a pointer to constant memory to each
function needing it makes much more sense and allows the compiler to
warn us if we do try to modify it, which it wouldn't have before.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-17 11:37:25 +02:00
Laslo Hunhold
660699492f
Make user/group-handling-code more robust
As is there is no security issue, but _if_ we end up with a user
or group set to NULL after e.g. ARGEND, we would've hit a null-pointer-
dereference of grp in which is now line 311.

What we want to check instead is if user or group are NULL respectively
and throw an error. Consequently, we can remove the later checks in the
drop root section, as we now guarantee that grp and pwd are not NULL.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-09 23:20:06 +02:00
Laslo Hunhold
b1dca4cf97
Remove three dead stores in main()
Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-09 22:43:46 +02:00
Laslo Hunhold
03ee1df4c3
Add space in list
Thanks Hiltjo!

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-05 23:27:05 +02:00
Laslo Hunhold
2318a89ecd
Begin comment in lowercase
Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-05 19:14:10 +02:00
Laslo Hunhold
d105c28aad
Ensure const-correctness where possible and refactor parse_range()
I know that the effect of 'const' on compiler optimizations is smaller
than many believe, but it provides a good insight to the caller which
parameters are not modified and simplifies parallelization, in case
that is desired at a later point.

Throughout processing, the big structs mostly remained unmodified, with
the exception of parse_range(), which added a null-byte in the "Range"-
header to simplify its parsing. This commit refactors parse_range()
such that it won't modify this string anymore.

Additionally, the parser was made even stricter: Usually, strtoll()
(which is wrapped by strtonum()) allows whitespace and plus and minus
signs before the number, which is not part of the specification. The
stricter parser also better differentiates now between invalid requests
and range-lists. In that context, the switch in http_send_response()
was replaced for better readability.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-05 18:28:21 +02:00
Laslo Hunhold
2c50d0c654
Rename request "r" to "req"
Now that we have response-structs called "res", the naming "r" is a
bit ambiguous.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-08-05 15:43:29 +02:00
Nihal Jere
8ccef4b27a
Make host parameters optional
For me at least, the first valid configuration found by getaddrinfo
works fine most of the time. Obviously if this isn't the configuration
you want, you can specify the host explicitly.
2020-04-21 17:04:52 +02:00
Laslo Hunhold
5ee8c07e7e
Fix unveil(2) usage
Thanks to the feedback by z0lqLA! I forgot that unveil(NULL, NULL)
only locks further unveil calls when there has been at least _one_ prior
call to unveil!

To fix this, we reorder the calls and also make sure to call unveil()
before we disallow unveils via pledge.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2020-03-20 20:35:34 +01:00
Laslo Hunhold
3c7049e906
Use pledge(2) and unveil(2) on OpenBSD
It has been on my todo-list for a long time. I tested it on
OpenBSD 6.5.

Thanks Richard Ulmer for the reminder.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2019-09-23 16:56:28 +02:00
Laslo Hunhold
32223c96bd
Use compound literals and explicit initialization
I didn't really like the use of a "yes"-variable for setsockopt().
A better way is to use compound literals (part of C99).

Another point are the structs. Instead of memsetting to zero we make
use of the standard which guarantees that "unmentioned" fields
are set to zero anyways. Just to note it here: The use of memset()
also sets padding to zero, which is not guaranteed with the method
of "unmentioned" fields.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2019-05-30 23:15:47 +02:00
Laslo Hunhold
33def953e9
Improve tokenization for m- and v-flag parsing
I wasn't happy with the tokenizer for the m- and v-flags, because it
was handling space-separated input and there was no way to have spaces
within the tokens themselves. This is a fine detail, but I didn't want
to impose this restriction where it could be solved (path prefixes or
folder names can very well contain spaces).

Given it's a bit quirky to handle multiple arguments to a single flag
in the command line, especially when parameters are optional, this
alternative wasn't further considered and I instead implemented a
tokenizer that allows escaping spaces with '\'.

While at it, I clarified the manual regarding this point.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2019-02-24 21:50:39 +01:00
Laslo Hunhold
065394cb64
Change target prefix mapping argument order
Put the chost-specification at the end and make it optional. This makes
more sense than having to give an arbitrary useless name in case you
weren't using virtual hosts in the first place.

While at it, clear up the wording in the manpage.

Signed-off-by: Laslo Hunhold <dev@frign.de>
2019-02-24 00:53:03 +01:00
Laslo Hunhold
48ddb8fefb
Sort flag-switch alphabetically
Signed-off-by: Laslo Hunhold <dev@frign.de>
2019-02-23 13:50:59 +01:00
Dominik Schmidt
094c8ba814 Open a new process group before setting up signal handler
When cleaning up after a caught signal, quark forwards the signal to all
processes in the process group with `kill(0, ...)`. If we do not open up a new
process group in the parent process, quarks parent will be sent a SIG... too,
resulting it to shut down (especially considering that the parent process might
run as root).

As a result, if we set up the service with djb's excellent daemontools,
`svc -d quark` will terminate the svscan-process and tear all other services
down with it.

See also <https://cr.yp.to/daemontools/faq/create.html#pgrphack>.
2018-07-02 07:14:00 +02:00
Laslo Hunhold
ba38b0969f Give an indication of the time zone in the log
We use Zulu-time (aka UTC) for the log timestamps.
2018-04-03 01:23:00 +02:00
Josuah Demangeon
c3ddb2dd14 permit prefix to be empty in -v format string
The previous parsing of the -v vhosts made sure there were 4 tokens.
If there was no prefix specified, usage() is called.  Now, it only
checks for the firsts 3, with .prefix set to null if there are only
3 tokens.
2018-04-02 09:57:58 +02:00
Josuah Demangeon
69bb7710eb fix segfault on parsing of -v and -m
The length is initially 0 so it needs to be incremented before
reallocarray to avoid ...alloc(0); and keep some space for the element
to insert.
2018-04-02 09:53:41 +02:00
Laslo Hunhold
a20136fa18 Update the documentation to reflect the new flag-centric usage 2018-03-05 09:51:29 +01:00
Laslo Hunhold
ed8b7e8954 Fix a logic error
We want to xor s.host and udsname, so it especially errors out when none
are given.
2018-03-05 01:04:51 +01:00
Laslo Hunhold
1879e14e79 Be extra pedantic again and remove all warnings
Since now config.def.h has been reduced we don't have any more unused
variables and thus the manual fiddling with error-levels is no longer
necessary.
To get a completely clean result though we have to still cast some
variables here and there.
2018-03-05 00:30:53 +01:00
Laslo Hunhold
6b55e36036 Introduce flag-centric usage
The config.h-interface has proven to be very effective for a lot of
suckless tools, but it just does not make too much sense for a web
server like quark.

 $ quark

If you run multiple instances of it, you want to see in the command line
(or top) what it does, and given the amount of options it's logical to
just express them as options given in the command line.
It also is a problem if you can modify quark via the config.h,
contradicting the manual. Just saying "Well, then don't touch config.h"
is also not good, as the vhost and map options were only exposed via
this interface.

What is left in config.h are mime-types and two constants relating to
the incoming HTTP-header-limits.

In order to introduce these changes, some structs and safe utility
functions were added and imported from OpenBSD respectively.
2018-03-05 00:14:25 +01:00
Laslo Hunhold
72aa1646f6 If fork fails, close the incoming socket 2018-02-23 22:40:47 +01:00
Laslo Hunhold
53c3963497 Actually exit the child process once finished serving
Thanks Rodrigo S. Cañibano for noticing this!
2018-02-23 22:29:00 +01:00
Laslo Hunhold
f6f98c9e64 Remove server-architecture specifics from serve() and add them to main()
To make the code a bit more flexible, let's get rid of the forking-code
in serve() and do it in main(). This way, we are more liberal in the
future to possibly handle it in a different way.
2018-02-05 17:15:29 +01:00
Laslo Hunhold
33d3d85f4f Refine error messages
I forgot that they can fail with errno = 0, which indicates that the
given entry was not found.
2018-02-04 21:40:51 +01:00
Laslo Hunhold
ccdb51b96d Refactor the single source file into multiple modules
And many other things, too many to list here. For example, it now
properly logs uds instead of erroring out.
Separating concerns in many places definitely improves the readability.
2018-02-04 21:27:33 +01:00