diff options
Diffstat (limited to 'app/controllers/concerns/sends_blob.rb')
-rw-r--r-- | app/controllers/concerns/sends_blob.rb | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/app/controllers/concerns/sends_blob.rb b/app/controllers/concerns/sends_blob.rb new file mode 100644 index 00000000000..971390d9118 --- /dev/null +++ b/app/controllers/concerns/sends_blob.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module SendsBlob + extend ActiveSupport::Concern + + included do + include BlobHelper + include SendFileUpload + end + + def send_blob(blob, params = {}) + if blob + headers['X-Content-Type-Options'] = 'nosniff' + + return if cached_blob?(blob) + + if blob.stored_externally? + send_lfs_object(blob) + else + send_git_blob(repository, blob, params) + end + else + render_404 + end + end + + private + + def cached_blob?(blob) + stale = stale?(etag: blob.id) # The #stale? method sets cache headers. + + # Because we are opinionated we set the cache headers ourselves. + response.cache_control[:public] = project.public? + + response.cache_control[:max_age] = + if @ref && @commit && @ref == @commit.id # rubocop:disable Gitlab/ModuleWithInstanceVariables + # This is a link to a commit by its commit SHA. That means that the blob + # is immutable. The only reason to invalidate the cache is if the commit + # was deleted or if the user lost access to the repository. + Blob::CACHE_TIME_IMMUTABLE + else + # A branch or tag points at this blob. That means that the expected blob + # value may change over time. + Blob::CACHE_TIME + end + + response.etag = blob.id + !stale + end + + def send_lfs_object(blob) + lfs_object = find_lfs_object(blob) + + if lfs_object && lfs_object.project_allowed_access?(project) + send_upload(lfs_object.file, attachment: blob.name) + else + render_404 + end + end + + def find_lfs_object(blob) + lfs_object = LfsObject.find_by_oid(blob.lfs_oid) + if lfs_object && lfs_object.file.exists? + lfs_object + else + nil + end + end +end |