5 require 'mogilefs/backend'
6 require 'mogilefs/util'
9 # HTTPFile wraps up the new file operations for storing files onto an HTTP
12 # You really don't want to create an HTTPFile by hand. Instead you want to
13 # create a new file using MogileFS::MogileFS.new_file.
16 # TODO dup'd content in MogileFS::NFSFile
18 class MogileFS::HTTPFile < StringIO
19 include MogileFS::Util
21 class EmptyResponseError < MogileFS::Error; end
22 class BadResponseError < MogileFS::Error; end
23 class UnparseableResponseError < MogileFS::Error; end
24 class NoStorageNodesError < MogileFS::Error
25 def message; 'Unable to open socket to storage node'; end
29 # The path this file will be stored to.
34 # The key for this file. This key won't represent a real file until you've
40 # The class of this file.
45 # The bigfile name in case we have file > 256M
47 attr_accessor :bigfile
50 # Works like File.open. Use MogileFS::MogileFS#new_file instead of this
56 return fp unless block_given?
66 # Creates a new HTTPFile with MogileFS-specific data. Use
67 # MogileFS::MogileFS#new_file instead of this method.
69 def initialize(mg, fid, path, devid, klass, key, dests, content_length)
79 @dests = dests.map { |(_,u)| URI.parse u }
86 # Closes the file handle and marks it as closed in MogileFS.
93 # Don't try to run out of memory
94 fp = File.open(@bigfile)
95 file_size = File.size(@bigfile)
96 @socket.write "PUT #{@path.request_uri} HTTP/1.0\r\nContent-Length: #{file_size}\r\n\r\n"
97 sysrwloop(fp, @socket)
100 @socket.write "PUT #{@path.request_uri} HTTP/1.0\r\nContent-Length: #{length}\r\n\r\n#{string}"
106 raise EmptyResponseError, 'Unable to read response line from server'
109 if line =~ %r%^HTTP/\d+\.\d+\s+(\d+)% then
112 when 200..299 then # success!
114 raise BadResponseError, "HTTP response status from upload: #{status}"
117 raise InvalidResponseError, "Response line not understood: #{line}"
123 @mg.backend.create_close(:fid => @fid, :devid => @devid,
124 :domain => @mg.domain, :key => @key,
125 :path => @path, :size => length)
126 return file_size if @bigfile
133 return !(@socket.nil? or @socket.closed?)
137 return @socket if connected?
144 raise NoStorageNodesError if @path.nil?
147 @socket = TCPSocket.new @path.host, @path.port
152 @dests.each do |dest|
153 unless @tried.include? dest then