-
Notifications
You must be signed in to change notification settings - Fork 92
/
http-client.rb
executable file
·173 lines (150 loc) · 3.63 KB
/
http-client.rb
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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
#!/usr/bin/env ruby
require 'net/http'
require 'net/https'
require 'optparse'
require 'uri'
def verbose_printer(verbosity)
if verbosity
pid = Process.pid
Proc.new do |msg|
$stderr.puts "[#{pid}]: #{msg}"
end
else
Proc.new do |a|
end
end
end
def parse_option(argv)
parser = OptionParser.new
opt = Hash.new
print_help = Proc.new do |msg, *args|
exits = if args.size > 0
args.shift
else
true
end
if msg
puts msg
puts
end
puts "Usage: #{$0} [OPTIONS] HOSTNAME"
puts parser.help
if exits
exit(1)
end
end
parser.on('-h') do
print_help.call(nil)
end
# TODO: should be rewrite in cURL style option
opt[:verbose] = nil
parser.on('-v', '--verbose',
"\n\t\tverbose") do
opt[:verbose] = true
end
opt[:headers] = Hash.new
parser.on('-H', '--header HEADER',
"\n\t\tadditional HTTP header field." +
"\n\t\tuse like -h \"User-Agent: Ruby\"") do |header|
unless header =~ /^([-A-Za-z]+):\s*(.+)$/
print_help.call("Invalid HTTP header format: #{header}")
end
opt[:headers][$~[1]] = $~[2]
end
opt[:method] = 'GET'
parser.on('-m', '--method METHOD',
"\n\t\tHTTP request method"+
" (GET and POST are supported)") do |method|
unless method =~ /\A(GET|POST)\Z/
print_help.call("Not such HTTP method: #{method}")
end
opt[:method] = method
end
opt[:path] = '/'
parser.on('-P', '--path PATH',
"\n\t\tHTTP request path (default: \"/\")") do |path|
opt[:path] = path
end
opt[:encode] = nil
parser.on('-e', '--encode',
"\n\t\tpercent encode HTTP request path (default: no)") do
opt[:encode] = true
end
opt[:ssl] = nil
parser.on('-s', '--ssl', "\n\t\tuse SSL (default: no)") do
opt[:ssl] = true
end
opt[:port] = nil
parser.on('-p', '--port PORT',
"\n\t\tdestination port number" +
" (default: 80 on non-SSL, 443 on SSL)") do |port|
opt[:port] = port.to_i
puts "port: #{opt[:port]}"
end
opt[:ssl_cert] = nil
parser.on('-c', '--cert PATH',
"\n\t\tCA certificate file(*.pem)" +
" for verifying certificates") do |path|
unless File.exist?(path)
print_help.call("No such file: #{path}")
end
opt[:ssl_cert] = path
end
parser.parse!(argv)
if argv.size == 0
print_help.call('HOSTNAME required')
end
opt[:host] = argv.first
if !opt[:port]
opt[:port] = if opt[:ssl]
443
else
80
end
end
opt[:path] = URI.encode(opt[:path]) if opt[:encode]
opt
end
def print_header_string(res)
print "HTTP/#{res.http_version} #{res.code} #{res.message}"
res.canonical_each do |name,value|
print("\r\n#{name}: #{value}")
end
end
def main(argv)
Net::HTTP.version_1_2
opt = parse_option(argv)
vprint = verbose_printer(opt[:verbose])
http = Net::HTTP.new(opt[:host], opt[:port])
if opt[:ssl]
http.use_ssl = true
vprint.call("SSL enabled")
if opt[:ssl_cert]
http.ca_file = opt[:ssl_cert]
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 5
end
end
res = nil
begin
http.start do |client|
res = case opt[:method]
when /GET/
client.get(opt[:path], opt[:headers])
when /POST/
client.post(opt[:path], opt[:headers])
end
end
end
if res
print_header_string(res)
print "\r\n\r\n"
print res.body
$stdout.flush
else
$stderr.puts "error"
end
end
if __FILE__ == $0
main(ARGV.dup)
end