Class: PDTP::Client::Transfer::Listener

Inherits:
Base
  • Object
show all
Defined in:
lib/pdtp/client/transfer.rb

Overview

Implements the listening end (the server) of a peer to peer http connection

Instance Attribute Summary collapse

Attributes inherited from Base

#byte_range, #connection, #file_service, #hash, #method, #peer, #peer_id, #url

Instance Method Summary collapse

Methods inherited from Base

#matches_message?, #parse_http_range, #send_ask_verify_message, #send_completed_message

Constructor Details

#initialize(connection, request, response, file_service) ⇒ Listener

Called with the request and response parameters given by Mongrel



88
89
90
91
92
93
# File 'lib/pdtp/client/transfer.rb', line 88

def initialize(connection, request, response, file_service)
  @request, @response = request,response
  @file_service = file_service
  @authorized = false
  @connection = connection
end

Instance Attribute Details

#requestObject (readonly)

Returns the value of attribute request.



85
86
87
# File 'lib/pdtp/client/transfer.rb', line 85

def request
  @request
end

Instance Method Details

#handle_headerObject

Parse the HTTP header and ask for verification of transfer

Raises:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/pdtp/client/transfer.rb', line 110

def handle_header
  #@@log.debug "params=#{@request.params.inspect}"    

  @method=@request.params["REQUEST_METHOD"].downcase   
  @peer=@request.params["REMOTE_ADDR"]

  #here we construct the GUID for this file
  path=@request.params["REQUEST_PATH"]
  vhost=@request.params["HTTP_HOST"]
  @url="http://"+vhost+path
  
  # 404 unless we know about this URL
  return unless @file_service.get_info(@url)

  @byte_range=parse_http_range(request.params["HTTP_RANGE"])
  @peer_id=@request.params["HTTP_X_PDTP_PEER_ID"]

  #sanity checking
  raise HTTPException.new(400, "Missing X-PDTP-Peer-Id header") if @peer_id.nil?
  raise HTTPException.new(400, "Missing Host header") if vhost.nil?
  raise HTTPException.new(400, "Missing Range header") if @byte_range.nil?

  send_ask_verify_message
  @response.pending = true
  
  # return true meaning the URL and header info were accepted
  true
end

#tell_verify(authorized) ⇒ Object

Called after receiving verification message from the server



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/pdtp/client/transfer.rb', line 140

def tell_verify(authorized)
  #check if the server authorized us
  unless authorized
    raise HTTPException.new(403,"Forbidden: the server did not authorize this transfer")  
  end

  info = @file_service.get_info(@url)
  if @method == "put"
    #we are the taker
    #@@log.debug("Body Downloaded: url=#{@url} range=#{@byte_range} peer=#{@peer}")      

    @file_service.set_info(FileInfo.new) if info.nil? 
    info.write @byte_range.first, @request.body.read
    @hash = Digest::SHA256.hexdigest(res.body) rescue nil

    # Stock HTTP OK response
    @response.start(200) do |head,out| 
    end
  elsif @method=="get"
    #we are the giver
    raise HTTPException.new(404,"File not found: #{@url}") if info.nil?
    data = info.read @byte_range
    raise HTTPException.new(416,"Invalid range: #{@byte_range.inspect}") if data.nil?   

    #Request was GET, so now we need to send the data
    @response.start(206) do |head, out|
      head['Content-Type'] = 'application/octet-stream'
      head['Content-Range'] = "bytes #{@byte_range.first}-#{@byte_range.last}/*"
      #FIXME must include a DATE header according to http

      out.write data
    end
    
    # Call response.finished ourselves since we left the response pending
    @response.finished
  else
    raise HTTPException.new(405,"Invalid method: #{@method}")
  end
end

#write_http_exception(e) ⇒ Object

Send an HTTP error response to requester



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/pdtp/client/transfer.rb', line 96

def write_http_exception(e)
  if e.class == HTTPException
    @response.start(e.code) do |head,out|
      out.write(e.to_s + "\n\n" + e.backtrace.join("\n") )
    end
  else
    STDERR.write "MONGREL SERVER ERROR: exception: " + e.to_s+"\n\n"+e.backtrace.join("\n")+"\n" 
    @response.start(500) do |head,out|
      out.write("Server error, unknown exception: "+e.to_s + "\n\n" + e.backtrace.join("\n") )
    end
  end
end