AgeCommit message (Collapse)AuthorLines
Share one lock-file helper between the cachesBryce Kwon-29/+45
Keep the cache's trailing slash helper in cache.cBryce Kwon-3/+12
Let go of a slot lock that cannot take its keyBryce Kwon-0/+3
A failed truncate or key write returned with the descriptor still open, so the lock was held while the page rendered uncached and the file was left behind. It is removed before its last close, as every holder does.
Keep lock contention out of the error logBryce Kwon-11/+25
process_slot logged every failure to lock, so each request that found its slot being filled left a line, while refresh_slot logged none, so an expired slot in a directory the server cannot write was served stale for good without a word. lock_slot now logs the step that failed, as the scan does, and leaves out only another request at work.
Open the lock files close-on-execBryce Kwon-1/+3
Each exec filter and snapshot compressor a fill runs inherited the slot's lock descriptor beside the stdout it writes into. An flock lasts until its last copy closes and nothing waits for a process a filter leaves behind, so a fill killed before its rename could leave the slot locked, and served stale or uncached, for as long as such a process lived. The scan holds its lock across no exec and opens the same way so that the two stay alike.
Give stdout back from a slot in one placeBryce Kwon-10/+11
Return nothing from two calls nobody checksBryce Kwon-3/+2
Format the cache listing's times where it printsBryce Kwon-17/+6
Close the cache's descriptors through one helperBryce Kwon-33/+15
Drop the cache's checks for arguments never NULLBryce Kwon-14/+0
The cache root always holds a default or a copy, the key comes from a strbuf, and every string hashed is the same or a macro expansion.
Write the cache's errors with fprintf like the restBryce Kwon-25/+10
Lock a cache slot with flockBryce Kwon-7/+6
The slot lock was a POSIX record lock, which a process loses the moment any descriptor on the file closes, and the fill puts the lock file on stdout, which every exec filter and snapshot compressor closes with its dup2. A second request on the slot could then rebuild it under the first and splice the two pages. An flock holds until the last descriptor goes.
Abandon a fill whose last flush fails to writeBryce Kwon-2/+4
The slot being filled was forgotten before the page's final flush, so a write that failed there, on a full disk for one, could not abandon the fill: cgit died into the lock file instead and the visitor got nothing. The mid-page path already delivered the page from the lock file.
Widen the cache ttl before multiplying itBryce Kwon-1/+3
A ttl in the tens of millions of minutes overflowed the int it was multiplied in.
Read and write slot keys and pages in fullBryce Kwon-2/+2
xread and xwrite may move fewer bytes than asked. A short write of the key left a slot that could never match, a short read of it reported a collision, and a page write that moved nothing looped for ever.
Stop the sendfile loop at the end of a short slotBryce Kwon-0/+4
sendfile returns zero at the end of the file, and the loop only ended once the offset reached the size recorded when the slot was opened, so a slot cut shorter in between spun the request forever. Only Linux builds this path. A stand-in header type checked it here.
End a request quietly when the client has goneBryce Kwon-1/+2
A write that failed with EPIPE on an uncached page died into an error page, which died again at exit when the page could not be sent either, and git logged a recursion warning on every dropped connection. A filter that exits early fails a write the same way, so the quiet exit is kept for writes that reach the client itself.
Keep clone files and oversized responses out of the cacheBryce Kwon-3/+22
The dumb transport reads files that already sit on the disk, so a pack copied into a slot cost that disk twice and the request a second write of every byte. A snapshot took a slot whatever its size, so a visitor naming distinct refs and ids could fill the cache root with archives. `cache-max-slot-size`, 64 MB unless set, now serves a larger response from the lock file and drops it, along with any expired copy it would have replaced.
Align with spaces instead of tabsBryce Kwon-7/+7
Harden the request path, scan and error recoveryBryce Kwon-22/+49
Log a cache slot that cannot be publishedBryce Kwon-2/+14
Fail cleanly when a filter cannot runBryce Kwon-0/+3
A filter program that could not be run answered with two responses, and a filter that exited without reading its input ended cgit with the page half written.
Clean up the whole treeBryce Kwon-34/+29
Trim the comments and dead code across the treeBryce Kwon-24/+14
Log scan lock failures that are not contentionBryce Kwon-7/+7
Give up a scan or slot whose lock file was renamedBryce Kwon-0/+13
Serve nothing further once a fill is abandonedBryce Kwon-3/+34
Log when a cache slot is claimed by a colliding keyBryce Kwon-0/+8
Restyle the sources and fix the audit's findingsBryce Kwon-218/+246
Bound the search and cache key a request can askBryce Kwon-0/+15
Gather page output into one bufferBryce Kwon-0/+1
Settle the names, types and layout of the sourcesBryce Kwon-10/+9
Bound the cache listing key outputBryce Kwon-2/+9
Point the fork's links and credits at itselfBryce Kwon-1/+1
AUTHORS now records the upstream developers as the project's history rather than as maintainers of the fork.
Reorganize into source, assets and librariesBryce Kwon-0/+0
The C sources move to source/, the served files to assets/, the bundled Git submodule to libraries/git and the filter scripts to extensions/. Everything the build generates now lands in build/, so a clean is a single remove and the tree stays clean.
cache: truncate lock file before fillingJason A. Donenfeld-0/+2
lock_slot() opens the lock file with O_RDWR|O_CREAT but without O_TRUNC. If a previous cgit process was killed between lock_slot() and unlock_slot() (e.g. by a CGI timeout or OOM), the stale lock file remains on disk with the old content, and the kernel releases the fcntl lock. The next process to claim the same cache slot then opens this stale lock file, acquires the fcntl lock, writes its key and generated content on top of the old bytes. If the new response is shorter than what was previously in the file, trailing bytes from the old response survive beyond the end of the new content. fstat() in fill_slot() reports the total file size (including the stale tail), and print_slot() faithfully sends all of it -- producing a response that is the correct page followed by a fragment of whatever previously occupied that lock file. Fix this by truncating the lock file after acquiring the lock and before writing the new key. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
cache: tolerate short writes in print_slotHristo Venev-20/+25
sendfile() can return after a short read/write, so we may need to call it more than once. As suggested in the manual page, we fall back to read/write if sendfile fails with EINVAL or ENOSYS. On the read/write path, use write_in_full which deals with short writes. Signed-off-by: Hristo Venev <hristo@venev.name> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
git: update to v2.30.0Christian Hesse-3/+3
Update to git version v2.30.0, this requires changes for these upstream commits: * 88894aaeeae92e8cb41143cc2e045f50289dc790 blame: simplify 'setup_scoreboard' interface * 1fbfdf556f2abc708183caca53ae4e2881b46ae2 banned.h: mark non-reentrant gmtime, etc as banned Signed-off-by: Christian Hesse <mail@eworm.de>
cache: close race window when unlocking slotsJohn Keeping-23/+14
We use POSIX advisory record locks to control access to cache slots, but these have an unhelpful behaviour in that they are released when any file descriptor referencing the file is closed by this process. Mostly this is okay, since we know we won't be opening the lock file anywhere else, but there is one place that it does matter: when we restore stdout we dup2() over a file descriptor referring to the file, thus closing that descriptor. Since we restore stdout before unlocking the slot, this creates a window during which the slot content can be overwritten. The fix is reasonably straightforward: simply restore stdout after unlocking the slot, but the diff is a bit bigger because this requires us to move the temporary stdout FD into struct cache_slot. Signed-off-by: John Keeping <john@keeping.me.uk> Reviewed-by: Christian Hesse <mail@eworm.de>
global: spelling fixesVille Skyttä-1/+1
Signed-off-by: Ville Skyttä <ville.skytta@iki.fi>
cache: flush stdio before restoring FDsJohn Keeping-0/+6
As described in commit 2efb59e (ui-patch: Flush stdout after outputting data, 2014-06-11), we need to ensure that stdout is flushed before restoring the file descriptor when writing to the cache. It turns out that it's not just ui-patch that is affected by this but also raw diff which writes to stdout internally. Let's avoid risking more places doing this by ensuring that stdout is flushed after writing in fill_slot(). Signed-off-by: John Keeping <john@keeping.me.uk>
cache: don't check for match with no keyJohn Keeping-2/+3
We call open_slot() from cache_ls() without a key since we simply want to read the path out of the header. Should the file happen to contain an empty key then we end up calling memcmp() with NULL and a non-zero length. Fix this by assigning slot->match only if a key is set, which is always will be in the code paths where we use slot->match. Coverity-id: 13807 Signed-off-by: John Keeping <john@keeping.me.uk>
cache: use size_t for string lengthsJohn Keeping-2/+2
Avoid integer truncation on 64-bit systems. Coverity-id: 13864 Signed-off-by: John Keeping <john@keeping.me.uk>
cache: fix resource leak: close file handle before returnChristian Hesse-3/+9
Coverity-id: 13910 Signed-off-by: Christian Hesse <mail@eworm.de>
cache.c: fix header orderJohn Keeping-3/+3
git-compat-util.h may define values that affect how system headers are interpreted, so move sys/sendfile.h after cgit.h (which includes git-compat-util.h). Signed-off-by: John Keeping <john@keeping.me.uk>
cache: don't use an integer as a NULL pointerJohn Keeping-1/+1
Signed-off-by: John Keeping <john@keeping.me.uk>
cache: use F_SETLK to avoid stale lock filesJohn Keeping-1/+14
If CGit is killed while it holds a lock on a cache slot (for example because it is taking too long to generate a page), the lock file will be left in place. This prevents any future attempt to use the same slot since it will fail to exclusively create the lock file. Since CGit is the only program that should be manipulating lock files, we can use advisory locking to detect whether another process is actually using the lock file or if it is now stale. I have confirmed that this works on Linux by setting a short TTL in a custom cgitrc and running the following with CGit patched to print a message to stderr if the fcntl(2) fails: $ export CGIT_CONFIG=$PWD/cgitrc $ export QUERY_STRING=url=cgit/tree/ui-shared.c $ ./cgit | grep -v -e '^<div class=.footer.>' \ -e '^Last-Modified: ' \ -e ^'Expires: ' >expect $ seq 50000 | dd bs=8192 | parallel -j200 "diff -u expect <(./cgit | grep -v -e '^<div class=.footer.>' \ -e '^Last-Modified: ' \ -e ^'Expires: ') || echo BAD" This printed the fail message several times without ever printing "BAD". Signed-off-by: John Keeping <john@keeping.me.uk>
Skip cache slot when time-to-live is zeroLukas Fleischer-1/+1
If time-to-live is set to zero, we don't need to regenerate the cache slots on every request. Instead, just skip the caching process and immediately provide the dynamically generated version of the page. Setting time-to-live to zero is useful when you want to disable caching for certain pages. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de>
cache: use sendfile() instead of a pair of read() + write()Sebastian Andrzej Siewior-1/+25
sendfile() does the same job and avoids to copy the content into userland and back. One has to define NO_SENDFILE in case the OS (kernel / libc) does not supported. It is disabled by default on non-linux environemnts. According to the glibc, sendfile64() was added in Linux 2.4 (so it has been there for a while) but after browsing over the mapage of FreeBSD's I noticed that the prototype is little different. Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Switch to exclusively using global ctxLukas Fleischer-8/+6
Drop the context parameter from the following functions (and all static helpers used by them) and use the global context instead: * cgit_print_http_headers() * cgit_print_docstart() * cgit_print_pageheader() Remove context parameter from all commands Drop the context parameter from the following functions (and all static helpers used by them) and use the global context instead: * cgit_get_cmd() * All cgit command functions. * cgit_clone_info() * cgit_clone_objects() * cgit_clone_head() * cgit_print_plain() * cgit_show_stats() In initialization routines, use the global context variable instead of passing a pointer around locally. Remove callback data parameter for cache slots This is no longer needed since the context is always read from the global context variable. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de>