Class: RoadForest::HTTP::UserAgent

Inherits:
Object
  • Object
show all
Defined in:
lib/roadforest/http/user-agent.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(http_client) ⇒ UserAgent

Returns a new instance of UserAgent.



7
8
9
10
11
12
13
# File 'lib/roadforest/http/user-agent.rb', line 7

def initialize(http_client)
  @http_client = http_client
  @trace = nil
  @cache = Hash.new do |cache, url|
    cache[url] = {}
  end
end

Instance Attribute Details

#cacheObject (readonly)

Returns the value of attribute cache.



16
17
18
# File 'lib/roadforest/http/user-agent.rb', line 16

def cache
  @cache
end

#http_clientObject

Returns the value of attribute http_client.



15
16
17
# File 'lib/roadforest/http/user-agent.rb', line 15

def http_client
  @http_client
end

#traceObject

Returns the value of attribute trace.



15
16
17
# File 'lib/roadforest/http/user-agent.rb', line 15

def trace
  @trace
end

Instance Method Details

#add_authorization(request) ⇒ Object



97
98
99
# File 'lib/roadforest/http/user-agent.rb', line 97

def add_authorization(request)
  request.headers["Authorization"] = keychain.preemptive_response(request.url)
end

#add_cache_headers(request) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/roadforest/http/user-agent.rb', line 101

def add_cache_headers(request)
  case request.method
  when "GET"
    return unless cache.has_key?(request.url)
    cached = cache[request.url]
    return if cached.empty?
    request.headers["If-None-Match"] = cached.keys.join(", ")
  when "POST", "PUT"
    return unless cache.has_key?(request.url)
    cached = cache[request.url]
    return if cached.empty?
    request.headers["If-Match"] = cached.keys.join(", ")
  end
end

#cache_response(url, response) ⇒ Object



78
79
80
81
82
83
# File 'lib/roadforest/http/user-agent.rb', line 78

def cache_response(url, response)
  return if response.etag.nil?
  return if response.etag.empty?
  #XXX large bodies
  cache[url][response.etag] = response
end

#keychainObject



74
75
76
# File 'lib/roadforest/http/user-agent.rb', line 74

def keychain
  @keychain ||= Keychain.new
end

#make_request(method, url, headers = nil, body = nil, retry_limit = 5) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/roadforest/http/user-agent.rb', line 18

def make_request(method, url, headers = nil, body=nil, retry_limit=5)
  headers ||= {}

  method = method.to_s.upcase

  validate(method, url, headers, body)

  request = setup_request(method, url, headers, body)

  response = send_request(request, retry_limit)

  cache_response(url, response)

  return response
end

#send_request(request, retry_limit = 5) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/roadforest/http/user-agent.rb', line 43

def send_request(request, retry_limit=5)
  #Check expires headers on received

  trace_message(request)
  response = http_client.do_request(request)
  trace_message(response)
  case response.status
  when 304 #Not Modified
    response = cache.fetch(request.url).fetch(response.etag)
    trace_message(response)
    return response
  when 401
    #XXX What if challenge matches existing Auth header? i.e. current
    #creds are wrong?
    authn_response = keychain.challenge_response(request.url, response.headers["WWW-Authenticate"])
    if !authn_response.nil? and authn_response != request.headers["Authorization"]
      request.headers["Authorization"] = authn_response
      raise Retryable
    end
  end
  return response
rescue Retryable
  retry
end

#setup_request(method, url, headers, body) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/roadforest/http/user-agent.rb', line 34

def setup_request(method, url, headers, body)
  request = Request.new(method, url)
  request.headers.merge!(headers)
  request.body = body
  add_authorization(request)
  add_cache_headers(request)
  request
end

#trace_message(message) ⇒ Object



68
69
70
71
72
# File 'lib/roadforest/http/user-agent.rb', line 68

def trace_message(message)
  return unless @trace
  @trace = $stderr unless @trace.respond_to?(:puts)
  @trace.puts message.inspect
end

#validate(method, url, headers, body) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/roadforest/http/user-agent.rb', line 85

def validate(method, url, headers, body)
  case method
  when "GET", "HEAD", "DELETE"
    raise "Method #{method} requires an empty body" unless body.nil?
  when "POST", "PATCH", "PUT"
    raise "Method #{method} requires a body" if body.nil?
  #when "OPTION", "TRACE" #Need to put verbs where they go
  else
    raise "Unrecognized method: #{method}"
  end
end