diff options
Diffstat (limited to 'app/controllers/projects/lfs_storage_controller.rb')
-rw-r--r-- | app/controllers/projects/lfs_storage_controller.rb | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/app/controllers/projects/lfs_storage_controller.rb b/app/controllers/projects/lfs_storage_controller.rb new file mode 100644 index 00000000000..69066cb40e6 --- /dev/null +++ b/app/controllers/projects/lfs_storage_controller.rb @@ -0,0 +1,92 @@ +class Projects::LfsStorageController < Projects::GitHttpClientController + include LfsHelper + + before_action :require_lfs_enabled! + before_action :lfs_check_access! + + def download + lfs_object = LfsObject.find_by_oid(oid) + unless lfs_object && lfs_object.file.exists? + render_lfs_not_found + return + end + + send_file lfs_object.file.path, content_type: "application/octet-stream" + end + + def upload_authorize + render( + json: { + StoreLFSPath: "#{Gitlab.config.lfs.storage_path}/tmp/upload", + LfsOid: oid, + LfsSize: size, + }, + content_type: 'application/json; charset=utf-8' + ) + end + + def upload_finalize + unless tmp_filename + render_lfs_forbidden + return + end + + if store_file(oid, size, tmp_filename) + head 200 + else + render plain: 'Unprocessable entity', status: 422 + end + end + + private + + def download_request? + action_name == 'download' + end + + def upload_request? + %w[upload_authorize upload_finalize].include? action_name + end + + def oid + params[:oid].to_s + end + + def size + params[:size].to_i + end + + def tmp_filename + name = request.headers['X-Gitlab-Lfs-Tmp'] + return if name.include?('/') + return unless oid.present? && name.start_with?(oid) + name + end + + def store_file(oid, size, tmp_file) + # Define tmp_file_path early because we use it in "ensure" + tmp_file_path = File.join("#{Gitlab.config.lfs.storage_path}/tmp/upload", tmp_file) + + object = LfsObject.find_or_create_by(oid: oid, size: size) + file_exists = object.file.exists? || move_tmp_file_to_storage(object, tmp_file_path) + file_exists && link_to_project(object) + ensure + FileUtils.rm_f(tmp_file_path) + end + + def move_tmp_file_to_storage(object, path) + File.open(path) do |f| + object.file = f + end + + object.file.store! + object.save + end + + def link_to_project(object) + if object && !object.projects.exists?(storage_project.id) + object.projects << storage_project + object.save + end + end +end |