diff options
-rw-r--r--source/shared.c9
-rw-r--r--source/shared.h7
-rw-r--r--source/ui-blame.c5
-rw-r--r--source/ui-blob.c17
-rw-r--r--source/ui-plain.c7
-rw-r--r--source/ui-shared.c6
-rw-r--r--source/ui-shared.h5
-rw-r--r--source/ui-tree.c6
-rwxr-xr-xtests/t0204-limits.sh13
9 files changed, 48 insertions, 27 deletions
diff --git a/source/shared.c b/source/shared.c
index 9065693..3191742 100644
--- a/source/shared.c
+++ b/source/shared.c
@@ -410,9 +410,7 @@ int cgit_diff_files(const struct object_id *old_oid, const struct object_id *new
*old_size = old_bytes;
*new_size = new_bytes;
- if (ctx.cfg.max_blob_size &&
- (old_bytes / 1024 > (unsigned long)ctx.cfg.max_blob_size ||
- new_bytes / 1024 > (unsigned long)ctx.cfg.max_blob_size)) {
+ if (cgit_blob_too_large(old_bytes) || cgit_blob_too_large(new_bytes)) {
*binary = 1;
return 0;
}
@@ -450,6 +448,11 @@ int cgit_diff_files(const struct object_id *old_oid, const struct object_id *new
return 0;
}
+int cgit_blob_too_large(unsigned long size)
+{
+ return ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size;
+}
+
void cgit_diff_limit_path(struct diff_options *opt, const char *prefix)
{
struct pathspec_item *item;
diff --git a/source/shared.h b/source/shared.h
index 46324a1..df18772 100644
--- a/source/shared.h
+++ b/source/shared.h
@@ -66,6 +66,13 @@ extern int cgit_diff_files(const struct object_id *old_oid, const struct object_
linediff_fn fn);
/*
+ * Whether a blob of size bytes is past max-blob-size. Callers ask before
+ * reading the object, so a huge blob stays out of memory rather than being
+ * noticed once it is already there.
+ */
+extern int cgit_blob_too_large(unsigned long size);
+
+/*
* Limit a diff to the paths below prefix, which is taken literally.
*/
extern void cgit_diff_limit_path(struct diff_options *opt, const char *prefix);
diff --git a/source/ui-blame.c b/source/ui-blame.c
index 9395098..f3d58c0 100644
--- a/source/ui-blame.c
+++ b/source/ui-blame.c
@@ -274,9 +274,8 @@ static void print_blame_page(const struct object_id *oid, const char *path,
cgit_print_error_page(404, "Not Found", "Bad object id: %s", oid_to_hex(oid));
return;
}
- if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) {
- cgit_print_error_page(413, "Content Too Large", "Blob size (%lu KB) exceeds the limit (%d KB)",
- size / 1024, ctx.cfg.max_blob_size);
+ if (cgit_blob_too_large(size)) {
+ cgit_print_blob_too_large(size);
return;
}
diff --git a/source/ui-blob.c b/source/ui-blob.c
index 3c3ba71..f7047c7 100644
--- a/source/ui-blob.c
+++ b/source/ui-blob.c
@@ -11,6 +11,7 @@
#include "cgit.h"
#include "html.h"
+#include "shared.h"
#include "ui-blob.h"
#include "ui-shared.h"
@@ -94,15 +95,6 @@ static int find_path_oid(struct object_id *oid, char *path, int file_only)
return walk.found_path;
}
-/*
- * Callers ask before reading the object, so a huge blob stays out of
- * memory rather than being noticed once already there.
- */
-static int over_size_limit(unsigned long size)
-{
- return ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size;
-}
-
int cgit_ref_path_exists(const char *path, const char *ref, int file_only)
{
struct object_id oid;
@@ -139,7 +131,7 @@ int cgit_print_file(char *path, const char *head, int file_only, int html_escape
}
if (type == OBJ_BAD)
return -1;
- if (over_size_limit(size))
+ if (cgit_blob_too_large(size))
return -1;
buf = odb_read_object(the_repository->objects, &oid, &type, &size);
if (!buf)
@@ -210,9 +202,8 @@ void cgit_print_blob(const char *hex, char *path, const char *head, int file_onl
return;
}
- if (over_size_limit(size)) {
- cgit_print_error_page(413, "Content Too Large", "Blob size (%lu KB) exceeds the limit (%d KB)",
- size / 1024, ctx.cfg.max_blob_size);
+ if (cgit_blob_too_large(size)) {
+ cgit_print_blob_too_large(size);
return;
}
diff --git a/source/ui-plain.c b/source/ui-plain.c
index 2463cfc..136e1f4 100644
--- a/source/ui-plain.c
+++ b/source/ui-plain.c
@@ -58,11 +58,8 @@ static void print_object(const struct object_id *oid, const char *path)
return;
}
- // The limit counts kilobytes and is checked before the read, so a huge
- // blob is kept out of memory rather than noticed once it is there.
- if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) {
- cgit_print_error_page(413, "Content Too Large", "Blob size (%lu KB) exceeds the limit (%d KB)",
- size / 1024, ctx.cfg.max_blob_size);
+ if (cgit_blob_too_large(size)) {
+ cgit_print_blob_too_large(size);
return;
}
diff --git a/source/ui-shared.c b/source/ui-shared.c
index b793f74..fd9cd20 100644
--- a/source/ui-shared.c
+++ b/source/ui-shared.c
@@ -1625,6 +1625,12 @@ void cgit_vprint_error_page(int code, const char *msg, const char *fmt, va_list
cgit_print_layout_end();
}
+void cgit_print_blob_too_large(unsigned long size)
+{
+ cgit_print_error_page(413, "Content Too Large", "Blob size (%lu KB) exceeds the limit (%d KB)",
+ size / 1024, ctx.cfg.max_blob_size);
+}
+
void cgit_print_layout_start(void)
{
cgit_print_http_headers();
diff --git a/source/ui-shared.h b/source/ui-shared.h
index c4b96a9..93cc9d2 100644
--- a/source/ui-shared.h
+++ b/source/ui-shared.h
@@ -97,6 +97,11 @@ extern void cgit_print_docend(void);
__attribute__((format (printf,3,4)))
extern void cgit_print_error_page(int code, const char *msg, const char *fmt, ...);
extern void cgit_vprint_error_page(int code, const char *msg, const char *fmt, va_list ap);
+
+/*
+ * Answer with the error page for a blob of size bytes past max-blob-size.
+ */
+extern void cgit_print_blob_too_large(unsigned long size);
extern void cgit_print_pageheader(void);
extern void cgit_print_filemode(unsigned short mode);
extern void cgit_print_snapshot_links(const struct cgit_repo *repo, const char *ref,
diff --git a/source/ui-tree.c b/source/ui-tree.c
index 3e2fb5e..d023502 100644
--- a/source/ui-tree.c
+++ b/source/ui-tree.c
@@ -13,6 +13,7 @@
#include "cgit.h"
#include "filter.h"
#include "html.h"
+#include "shared.h"
#include "ui-shared.h"
#include "ui-tree.h"
@@ -175,9 +176,8 @@ static bool print_object(const struct object_id *oid, const char *path,
return false;
}
- if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) {
- cgit_print_error_page(413, "Content Too Large", "Blob size (%lu KB) exceeds the limit (%d KB)",
- size / 1024, ctx.cfg.max_blob_size);
+ if (cgit_blob_too_large(size)) {
+ cgit_print_blob_too_large(size);
return false;
}
diff --git a/tests/t0204-limits.sh b/tests/t0204-limits.sh
index 19df797..245c016 100755
--- a/tests/t0204-limits.sh
+++ b/tests/t0204-limits.sh
@@ -165,6 +165,19 @@ test_expect_success 'a diff of an oversized blob is not inlined' '
! grep "aaaaaaaa" tmp
'
+test_expect_success 'every page showing a blob refuses an oversized one alike' '
+ {
+ echo "enable-blame=1" &&
+ cat blobdiffrc
+ } >blobpagesrc &&
+ for page in tree plain blob blame
+ do
+ CGIT_CONFIG="$PWD/blobpagesrc" QUERY_STRING="url=blobdiff/$page/big.txt" cgit >tmp &&
+ grep "^Status: 413 Content Too Large" tmp &&
+ grep "Blob size (3 KB) exceeds the limit (1 KB)" tmp || return 1
+ done
+'
+
# A missing scintillua leaves the shipped filter with nothing to highlight
# with, and a filter that failed there would take the whole page down with
# it, so it has to hand the source back escaped instead.