- def create_slot
- bucket = Bucket.find_root(params[:captures].first)
- begin
- slot = bucket.find_slot(params[:captures].last)
- only_can_write slot unless slot.nil?
- rescue NoSuchKey
- only_can_write bucket
- end
- raise MissingContentLength unless env['CONTENT_LENGTH']
- if params.has_key?('acl')
- slot = bucket.find_slot(params[:captures].last)
- slot.grant(requested_acl(slot))
- headers 'ETag' => slot.etag, 'Content-Length' => 0.to_s
- body ""
- elsif env['HTTP_X_AMZ_COPY_SOURCE'].to_s =~ /\/?(.+?)%2F(.+)/
- source_bucket_name = $1
- source_oid = $2
- source_oid = source_oid.gsub("%2F","\/")
- source_slot = Bucket.find_root(source_bucket_name).find_slot(source_oid)
- @meta = source_slot.meta unless !env['HTTP_X_AMZ_METADATA_DIRECTIVE'].nil? && env['HTTP_X_AMZ_METADATA_DIRECTIVE'].upcase == "REPLACE"
- only_can_read source_slot
- unless env['HTTP_X_AMZ_COPY_SOURCE_IF_MATCH'].blank?
- raise PreconditionFailed if source_slot.obj.etag != env['HTTP_X_AMZ_COPY_SOURCE_IF_MATCH']
- end
- unless env['HTTP_X_AMZ_COPY_SOURCE_IF_NONE_MATCH'].blank?
- raise PreconditionFailed if source_slot.obj.etag == env['HTTP_X_AMZ_COPY_SOURCE_IF_NONE_MATCH']
- end
- unless env['HTTP_X_AMZ_COPY_SOURCE_IF_UNMODIFIED_SINCE'].blank?
- raise PreconditionFailed if Time.httpdate(env['HTTP_X_AMZ_COPY_SOURCE_IF_UNMODIFIED_SINCE']) > source_slot.updated_at
- end
- unless env['HTTP_X_AMZ_COPY_SOURCE_IF_MODIFIED_SINCE'].blank?
- raise PreconditionFailed if Time.httpdate(env['HTTP_X_AMZ_COPY_SOURCE_IF_MODIFIED_SINCE']) < source_slot.updated_at
- end
- temp_path = File.join(STORAGE_PATH, source_slot.obj.path)
- fileinfo = source_slot.obj
- fileinfo.etag='""' if params[:captures].last[-8,8] == '$folder$'
- fileinfo.path = File.join(params[:captures].first, rand(10000).to_s(36) + '_' + File.basename(temp_path))
- fileinfo.path.succ! while File.exists?(File.join(STORAGE_PATH, fileinfo.path))
- file_path = File.join(STORAGE_PATH, fileinfo.path)
- else
- temp_path = env['rack.input'][:path] rescue nil
- readlen = 0
- md5 = MD5.new
- Tempfile.open(File.basename(params[:captures].last)) do |tmpf|
- temp_path ||= tmpf.path
- tmpf.binmode
- while part = env['rack.input'].read(BUFSIZE)
- readlen += part.size
- md5 << part
- tmpf << part unless env['rack.input'].is_a?(Tempfile)
- end
- end
- fileinfo = FileInfo.new
- fileinfo.mime_type = env['CONTENT_TYPE'] || "binary/octet-stream"
- fileinfo.disposition = env['CONTENT_DISPOSITION']
- fileinfo.size = readlen
- fileinfo.md5 = Base64.encode64(md5.digest).strip
- fileinfo.etag = '"' + md5.hexdigest + '"'
- fileinfo.etag='""' if params[:captures].last[-8,8] == '$folder$'
- raise IncompleteBody if env['CONTENT_LENGTH'].to_i != readlen
- if env['HTTP_CONTENT_MD5']
- b64cs = /[0-9a-zA-Z+\/]/
- re = /
- ^
- (?:#{b64cs}{4})* # any four legal chars
- (?:#{b64cs}{2} # right-padded by up to two =s
- (?:#{b64cs}|=){2})?
- $
- /ox
- raise InvalidDigest unless env['HTTP_CONTENT_MD5'] =~ re
- raise BadDigest unless fileinfo.md5 == env['HTTP_CONTENT_MD5']
- end
- end
- mdata = {}
- slot = nil
- meta = @meta.nil? || @meta.empty? ? {} : {}.merge(@meta)
- owner_id = @user ? @user.id : bucket.owner_id
- begin
- slot = bucket.find_slot(params[:captures].last)
- if slot.versioning_enabled?
- nslot = slot.clone()
- slot.update_attributes(:deleted => true)
- slot = nslot
- end
- if source_slot.nil?
- fileinfo.path = slot.obj.path
- file_path = File.join(STORAGE_PATH,fileinfo.path)
- FileUtils.mv(temp_path, file_path,{ :force => true })
- else
- FileUtils.cp(temp_path, file_path)
- end
- slot.update_attributes(:owner_id => owner_id, :meta => meta, :obj => fileinfo, :size => fileinfo.size)
- rescue NoSuchKey
- if source_slot.nil?
- fileinfo.path = File.join(params[:captures].first, rand(10000).to_s(36) + '_' + File.basename(temp_path))
- fileinfo.path.succ! while File.exists?(File.join(STORAGE_PATH, fileinfo.path))
- file_path = File.join(STORAGE_PATH,fileinfo.path)
- FileUtils.mkdir_p(File.dirname(file_path))
- FileUtils.mv(temp_path, file_path)
- else
- FileUtils.cp(temp_path, file_path)
- end
- slot = Slot.create(:name => params[:captures].last, :owner_id => owner_id, :meta => meta, :obj => fileinfo, :size => fileinfo.size)
- bucket.add_child(slot)
- end
- slot.grant(requested_acl(slot))
- h = { 'Content-Length' => 0.to_s, 'ETag' => slot.etag }
- if slot.versioning_enabled?
- begin
- slot.git_repository.add(File.basename(fileinfo.path))
- tmp = slot.git_repository.commit("Added #{slot.name} to the Git repository.")
- slot.git_update
- slot.update_attributes(:version => slot.git_object.objectish)
- h.merge!({ 'x-amz-version-id' => slot.git_object.objectish })
- rescue Git::GitExecuteError => error_message
- puts "[#{Time.now}] GIT: #{error_message}"
- end
- end
- if env['HTTP_X_AMZ_COPY_SOURCE'].blank?
- redirect_url = (params[:success_action_redirect] || params[:redirect])
- redirect redirect_url unless redirect_url.blank?
- status params[:success_action_status].to_i if params[:success_action_status]
- headers h
- puts "----------------#{h.inspect}---------"
- body ""
- else
- h['Content-Length'] = nil
- headers h
- xml do |x|
- x.CopyObjectResult do
- x.LastModified slot.updated_at.xmlschema
- x.Etag slot.etag
- end
- end
- end
- end
- # delete slot
- delete %r{^/(.+?)/(.+)$} do
- bucket = Bucket.find_root(params[:captures].first)
- only_can_write bucket
- begin
- @slot = bucket.find_slot(params[:captures].last)
- if @slot.versioning_enabled?
- begin
- @slot.git_repository.remove(File.basename(@slot.obj.path))
- @slot.git_repository.commit("Removed #{@slot.name} from the Git repository.")
- @slot.git_update
- rescue Git::GitExecuteError => error_message
- puts "[#{Time.now}] GIT: #{error_message}"
- end
- end
- @slot.remove_from_filesystem
- @slot.destroy
- status 204
- body ""
- rescue NoSuchKey
- status 204
- body ""
- end
- end
- error do
- error = Builder::XmlMarkup.new
- error.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
- error.Error do
- error.Code request.env['sinatra.error'].code
- error.Message request.env['sinatra.error'].message
- error.Resource env['PATH_INFO']
- error.RequestId @request_id
- end
- status request.env['sinatra.error'].status.nil? ? 500 : request.env['sinatra.error'].status
- content_type 'application/xml'
- body error.target!
- run_callback_for :error => request.env['sinatra.error'].code
- end