Class: Rack::StreamingProxy::ProxyRequest

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/rack/streaming_proxy/proxy_request.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request, uri) ⇒ ProxyRequest

Returns a new instance of ProxyRequest.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rack/streaming_proxy/proxy_request.rb', line 7

def initialize(request, uri)
  uri = URI.parse(uri)

  method = request.request_method.downcase
  method[0..0] = method[0..0].upcase
  
  proxy_request = Net::HTTP.const_get(method).new("#{uri.path}#{"?" if uri.query}#{uri.query}")

  if proxy_request.request_body_permitted? and request.body
    proxy_request.body_stream = request.body
    proxy_request.content_length = request.content_length if request.content_length
    proxy_request.content_type = request.content_type if request.content_type
  end

  %w(Accept Accept-Encoding Accept-Charset
    X-Requested-With Referer User-Agent Cookie
    Authorization
    ).each do |header|
    key = "HTTP_#{header.upcase.gsub('-', '_')}"
    proxy_request[header] = request.env[key] if request.env[key]
  end
  proxy_request["X-Forwarded-For"] =
    (request.env["X-Forwarded-For"].to_s.split(/, +/) + [request.env["REMOTE_ADDR"]]).join(", ")

  @piper = Servolux::Piper.new 'r', :timeout => 30

  @piper.child do
    http_req = Net::HTTP.new(uri.host, uri.port)
    http_req.use_ssl = uri.is_a?(URI::HTTPS)
    http_req.start do |http|
      http.request(proxy_request) do |response|
        # at this point the headers and status are available, but the body
        # has not yet been read. start reading it and putting it in the parent's pipe.
        response_headers = {}
        response.each_header {|k,v| response_headers[k] = v}
        @piper.puts response.code.to_i
        @piper.puts response_headers

        response.read_body do |chunk|
          @piper.puts chunk
        end
        @piper.puts :done
      end
    end
  end

  @piper.parent do
    # wait for the status and headers to come back from the child
    @status = read_from_child
    @headers = HeaderHash.new(read_from_child)
  end
rescue => e
  if @piper
    @piper.parent { raise }
    @piper.child { @piper.puts e }
  else
    raise
  end
ensure
  # child needs to exit, always.
  @piper.child { exit!(0) } if @piper
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



5
6
7
# File 'lib/rack/streaming_proxy/proxy_request.rb', line 5

def headers
  @headers
end

#statusObject (readonly)

Returns the value of attribute status.



5
6
7
# File 'lib/rack/streaming_proxy/proxy_request.rb', line 5

def status
  @status
end

Instance Method Details

#each {|["0", term, "", term].join| ... } ⇒ Object

Yields:

  • (["0", term, "", term].join)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rack/streaming_proxy/proxy_request.rb', line 70

def each
  chunked = @headers["Transfer-Encoding"] == "chunked"
  term = "\r\n"

  while chunk = read_from_child
    break if chunk == :done
    if chunked
      size = bytesize(chunk)
      next if size == 0
      yield [size.to_s(16), term, chunk, term].join
    else
      yield chunk
    end
  end

  yield ["0", term, "", term].join if chunked
end