From 34e694cba5c9b6e9c3d87941b043a3acae503938 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Wed, 25 Feb 2026 20:44:04 +0200 Subject: [PATCH] Bug 41929: Enable Cache-Control for UploadedFiles This patch adds Cache-Control header to Koha::UploadedFile->httpheaders. Cache-Control is set public and max-age at 12 hours for uploaded files that are marked as public, ie. retrieveable by opac-retrieve-file.pl. This reduces server load as browsers are allowed to cache the files. Useful for libraries that upload images and fonts via the upload tool, and serve them publicly in OPAC. As for files not marked public by the upload tool, Cache-Control tells browsers not to cache these files, as they may contain private and sensitive information. To test: 1. prove t/db_dependent/Upload.t Signed-off-by: Laura_Escamilla --- Koha/UploadedFile.pm | 14 ++++++++++++-- t/db_dependent/Upload.t | 36 ++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Koha/UploadedFile.pm b/Koha/UploadedFile.pm index 3fc626133ee..f06b9442941 100644 --- a/Koha/UploadedFile.pm +++ b/Koha/UploadedFile.pm @@ -129,15 +129,25 @@ Will be extended by report 14282 sub httpheaders { my ($self) = @_; + my $cache_control; + if ( $self->public ) { + + # 43200 = 12 hours, as defined in apache-shared.conf + $cache_control = 'public, max-age=43200'; + } else { + $cache_control = 'no-cache, no-store, max-age=0'; + } if ( $self->filename =~ /\.pdf$/ ) { return ( '-type' => 'application/pdf', + 'Cache-Control' => $cache_control, 'Content-Disposition' => 'inline; filename="' . $self->filename . '"', ); } else { return ( - '-type' => 'application/octet-stream', - '-attachment' => $self->filename, + '-type' => 'application/octet-stream', + '-attachment' => $self->filename, + 'Cache-Control' => $cache_control, ); } } diff --git a/t/db_dependent/Upload.t b/t/db_dependent/Upload.t index 469ff1200b3..8dcea986b15 100755 --- a/t/db_dependent/Upload.t +++ b/t/db_dependent/Upload.t @@ -255,7 +255,7 @@ subtest 'Simple tests for httpheaders and getCategories' => sub { my $rec = Koha::UploadedFiles->search_term( { term => 'file' } )->next; my @hdrs = $rec->httpheaders; - is( @hdrs == 4 && $hdrs[1] =~ /application\/octet-stream/, 1, 'Simple test for httpheaders' ); + is( @hdrs == 6 && $hdrs[1] =~ /application\/octet-stream/, 1, 'Simple test for httpheaders' ); $builder->build( { source => 'AuthorisedValue', @@ -364,15 +364,31 @@ subtest 'Testing delete_temporary' => sub { }; subtest 'Testing download headers' => sub { - plan tests => 2; - my $test_pdf = Koha::UploadedFile->new( { filename => 'pdf.pdf', uploadcategorycode => 'B', filesize => 1000 } ); - my $test_not = Koha::UploadedFile->new( { filename => 'pdf.not', uploadcategorycode => 'B', filesize => 1000 } ); - my @pdf_expect = ( '-type' => 'application/pdf', 'Content-Disposition' => 'inline; filename="pdf.pdf"' ); - my @not_expect = ( '-type' => 'application/octet-stream', '-attachment' => 'pdf.not' ); - my @pdf_head = $test_pdf->httpheaders; - my @not_head = $test_not->httpheaders; - is_deeply( \@pdf_head, \@pdf_expect, "Get inline pdf headers for pdf" ); - is_deeply( \@not_head, \@not_expect, "Get download headers for non pdf" ); + plan tests => 3; + my $test_pdf = + Koha::UploadedFile->new( { filename => 'pdf.pdf', uploadcategorycode => 'B', filesize => 1000, public => 0 } ); + my $test_not = + Koha::UploadedFile->new( { filename => 'pdf.not', uploadcategorycode => 'B', filesize => 1000, public => 0 } ); + my $test_public = + Koha::UploadedFile->new( { filename => 'pdf.not', uploadcategorycode => 'B', filesize => 1000, public => 1 } ); + my @pdf_expect = ( + '-type' => 'application/pdf', 'Cache-Control' => 'no-cache, no-store, max-age=0', + 'Content-Disposition' => 'inline; filename="pdf.pdf"' + ); + my @not_expect = ( + '-type' => 'application/octet-stream', '-attachment' => 'pdf.not', + 'Cache-Control' => 'no-cache, no-store, max-age=0' + ); + my @public_expect = ( + '-type' => 'application/octet-stream', '-attachment' => 'pdf.not', + 'Cache-Control' => 'public, max-age=43200' + ); + my @pdf_head = $test_pdf->httpheaders; + my @not_head = $test_not->httpheaders; + my @public_head = $test_public->httpheaders; + is_deeply( \@pdf_head, \@pdf_expect, "Get inline pdf headers for pdf" ); + is_deeply( \@not_head, \@not_expect, "Get download headers for non pdf" ); + is_deeply( \@public_head, \@public_expect, "Get download headers for public file" ); }; # The end -- 2.39.5