class Projects::LfsStorageController < Projects::GitHttpClientController include LfsHelper before_action :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'] if name.present? name.gsub!(/^.*(\\|\/)/, '') name = name.match(/[0-9a-f]{73}/) name[0] if name else nil end end def store_file(oid, size, tmp_file) tmp_file_path = File.join("#{Gitlab.config.lfs.storage_path}/tmp/upload", tmp_file) object = LfsObject.find_or_create_by(oid: oid, size: size) if object.file.exists? success = true else success = move_tmp_file_to_storage(object, tmp_file_path) end if success success = link_to_project(object) end success ensure # Ensure that the tmp file is removed 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