1
2
3
4
5
6
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
require 'net/http'
require 'rack'
require 'rack/cache'
module Nanoc3::Extra
module CHiCk
class Client
DEFAULT_OPTIONS = {
:cache => {
:metastore => 'file:tmp/rack/cache.meta',
:entitystore => 'file:tmp/rack/cache.body'
},
:cache_controller => {
:max_age => 60
}
}
def initialize(options={})
@options = DEFAULT_OPTIONS.merge(options)
@options[:cache] = DEFAULT_OPTIONS[:cache].merge(@options[:cache])
end
def get(url, additional_headers={})
options = @options
@app ||= Rack::Builder.new {
use Rack::Cache, options[:cache]
use Nanoc3::Extra::CHiCk::CacheController, options[:cache_controller]
run Nanoc3::Extra::CHiCk::RackClient
}
env = Rack::MockRequest.env_for(url, :method => 'GET')
status, headers, body_parts = @app.call(env)
body = ''
body_parts.each { |part| body << part }
[ status, headers, body ]
end
end
class CacheController
DEFAULT_OPTIONS = {
:max_age => 10 }
def initialize(app, options={})
@app = app
@options = DEFAULT_OPTIONS.merge(options)
end
def call(env)
res = @app.call(env)
unless res[1].has_key?('Cache-Control') || res[1].has_key?('Expires')
res[1]['Cache-Control'] = "max-age=#{@options[:max_age]}"
end
res
end
end
class RackClient
METHOD_TO_CLASS_MAPPING = {
'DELETE' => Net::HTTP::Delete,
'GET' => Net::HTTP::Get,
'HEAD' => Net::HTTP::Head,
'POST' => Net::HTTP::Post,
'PUT' => Net::HTTP::Put
}
def self.call(env)
request = Rack::Request.new(env)
request_headers = env.inject({}) do |m,(k,v)|
k =~ /^HTTP_(.*)$/ ? m.merge($1.gsub(/_/, '-') => v) : m
end
http = Net::HTTP.new(request.host, request.port)
net_http_request_class = METHOD_TO_CLASS_MAPPING[request.request_method]
raise ArgumentError, "Unsupported method: #{request.request_method}" if net_http_request_class.nil?
net_http_request = net_http_request_class.new(request.fullpath, request_headers)
net_http_request.body = env['rack.input'].read if [ 'POST', 'PUT' ].include?(request.request_method)
http.request(net_http_request) do |response|
return [
response.code.to_i,
response.to_hash.inject({}) { |m,(k,v)| m.merge(k => v[0]) },
[ response.body ]
]
end
end
end
end
end
|