2016-07-20 12:41:26 -04:00
|
|
|
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(
|
2016-07-22 10:40:22 -04:00
|
|
|
json: {
|
|
|
|
StoreLFSPath: "#{Gitlab.config.lfs.storage_path}/tmp/upload",
|
|
|
|
LfsOid: oid,
|
|
|
|
LfsSize: size,
|
|
|
|
},
|
|
|
|
content_type: 'application/json; charset=utf-8'
|
2016-07-20 12:41:26 -04:00
|
|
|
)
|
|
|
|
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
|