super-test 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGE.txt +9 -0
- data/README.txt +13 -0
- data/bin/idb +19 -0
- data/bin/ii +113 -0
- data/bin/istart_mock +36 -0
- data/bin/istop_mock +16 -0
- data/bin/kk +181 -0
- data/bin/rubyatp +42 -0
- data/bin/start_mock +36 -0
- data/bin/stop_mock +16 -0
- data/bin/xgo +45 -0
- data/conf/conf.rb +11 -0
- data/conf/db03.yml +31 -0
- data/conf/db13.yml +37 -0
- data/conf/db19.yml +33 -0
- data/conf/online.yml +32 -0
- data/conf/super_test.yml +40 -0
- data/conf/system.yml +26 -0
- data/conf/sz00.yml +31 -0
- data/conf/sz06.yml +34 -0
- data/conf/wise00.yml +11 -0
- data/data/case.house +0 -0
- data/data/char.house +0 -0
- data/data/images/Bluehills.jpg +0 -0
- data/data/images/Sunset.jpg +0 -0
- data/data/images/Waterlilies.jpg +0 -0
- data/data/images/Winter.jpg +0 -0
- data/data/query.house +18595 -0
- data/data/user.house +8 -0
- data/lib/action/module/check_action.rb +58 -0
- data/lib/action/module/cnnt_action.rb +161 -0
- data/lib/action/module/datacenter_action.rb +48 -0
- data/lib/action/module/http_pack_helper.rb +163 -0
- data/lib/action/module/httpserver_action.rb +297 -0
- data/lib/action/module/inc.rb +21 -0
- data/lib/action/module/mcpack_action.rb +57 -0
- data/lib/action/module/sql_action.rb +84 -0
- data/lib/action/module/ssh_action.rb +37 -0
- data/lib/action/system/user_action.rb +180 -0
- data/lib/common/appium_helper.rb +217 -0
- data/lib/common/atp_helper.rb +74 -0
- data/lib/common/atp_report.rb +344 -0
- data/lib/common/data_house.rb +405 -0
- data/lib/common/data_model.rb +87 -0
- data/lib/common/http/assert_helper.rb +343 -0
- data/lib/common/http/fix_hpricot.rb +118 -0
- data/lib/common/http/html_helper.rb +362 -0
- data/lib/common/http/http_helper.rb +469 -0
- data/lib/common/http/multipart.rb +81 -0
- data/lib/common/isandbox_helper.rb +195 -0
- data/lib/common/json_helper.rb +43 -0
- data/lib/common/mock_helper.rb +168 -0
- data/lib/common/mtop_helper.rb +141 -0
- data/lib/common/myconf_helper.rb +49 -0
- data/lib/common/mylog_helper.rb +77 -0
- data/lib/common/pairwise.rb +121 -0
- data/lib/common/query_house.rb +89 -0
- data/lib/common/report_helper.rb +97 -0
- data/lib/common/robot_helper.rb +85 -0
- data/lib/common/socket/check.rb +325 -0
- data/lib/common/socket/conf_modifier.rb +149 -0
- data/lib/common/socket/context.rb +55 -0
- data/lib/common/socket/data.rb +392 -0
- data/lib/common/socket/data_helper.rb +41 -0
- data/lib/common/socket/env.rb +317 -0
- data/lib/common/socket/inc.rb +24 -0
- data/lib/common/socket/log.rb +213 -0
- data/lib/common/socket/log4s.rb +58 -0
- data/lib/common/socket/log_helper.rb +332 -0
- data/lib/common/socket/my_sql.rb +77 -0
- data/lib/common/socket/net.rb +74 -0
- data/lib/common/socket/network.rb +115 -0
- data/lib/common/socket/rlib/conf_modifier.rb +130 -0
- data/lib/common/socket/rlib/data_helper.rb +33 -0
- data/lib/common/socket/rlib/log_helper.rb +303 -0
- data/lib/common/socket/rlib/process_helper.rb +91 -0
- data/lib/common/socket/stub.rb +276 -0
- data/lib/common/socket/util.rb +266 -0
- data/lib/patterns/inc.rb +10 -0
- data/lib/patterns/mc_base_pattern.rb +474 -0
- data/lib/patterns/some_pattern.rb +145 -0
- data/lib/super_test.rb +114 -0
- data/log/super_test.log +0 -0
- data/log/super_test.log.wf +0 -0
- data/test/cover_me.rb +6 -0
- data/tool/jenny +0 -0
- data/tool/mcsend/mcsend2 +0 -0
- data/tool/mcsend/mcsend2_shead +0 -0
- data/tool/mcserver/conf/mcserver.conf +77 -0
- data/tool/mcserver/conf/mcserverauthip +17 -0
- data/tool/mcserver/mcserver +0 -0
- data/tool/mcserver/mcserver_trans +0 -0
- data/tool/mysql +0 -0
- data/tool/net/mcsend/mcsend +0 -0
- data/tool/net/mcsend/mcsend_trans +0 -0
- data/tool/net/mcsend/nshead.data +7 -0
- data/tool/net/mcsend/res_nshead.data +7 -0
- data/tool/net/my_client/my_client +0 -0
- data/tool/net/tsclient/client.tcl +205 -0
- data/tool/others/kk +190 -0
- data/tool/others/rubyatp +42 -0
- data/tool/others/supertest_install.sh +34 -0
- data/tool/trip/idb +0 -0
- data/tool/ts-agent/nshead.bft +12 -0
- data/tool/ts-agent/server.conf +10 -0
- data/tool/ts-agent/server.tcl +376 -0
- metadata +275 -0
@@ -0,0 +1,362 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
#
|
4
|
+
# Author:: hanyu
|
5
|
+
# Date:: 2009.5.7
|
6
|
+
|
7
|
+
|
8
|
+
require 'hpricot'
|
9
|
+
require 'common/http/fix_hpricot'
|
10
|
+
|
11
|
+
# 解析纯文本、HTML、JSON
|
12
|
+
#
|
13
|
+
# - 打印可读日志
|
14
|
+
module HtmlHelper
|
15
|
+
|
16
|
+
# === 功能:
|
17
|
+
# 正则表达式提取
|
18
|
+
#
|
19
|
+
# === 参数解释:
|
20
|
+
# - regexp 提取的正则表达式
|
21
|
+
# - group 正则表达式匹配组号,默认为1
|
22
|
+
#
|
23
|
+
# === Example:
|
24
|
+
# Example #1:
|
25
|
+
#
|
26
|
+
# get "http://www.baidu.com/"
|
27
|
+
# puts find_grep %r"<title>(.*?)</title>"
|
28
|
+
# # => 百度一下,你就知道
|
29
|
+
#
|
30
|
+
# Example #2:
|
31
|
+
#
|
32
|
+
# get "http://www.baidu.com/"
|
33
|
+
# puts find_grep /<title>(.*?),(.*?)<\/title>/, 2
|
34
|
+
# # => 你就知道
|
35
|
+
def find_grep(regexp, group=1)
|
36
|
+
raise "no any http request before!" if @response == nil
|
37
|
+
m = regexp.match @response.body
|
38
|
+
raise HtmlError,"find_grep regexp[#{regexp}] not exist!" if m.nil?
|
39
|
+
return m[group]
|
40
|
+
end
|
41
|
+
|
42
|
+
# === 功能:
|
43
|
+
# 验证是否包含某字符串,不带正则表达式的功能
|
44
|
+
#
|
45
|
+
# === 参数解释:
|
46
|
+
# - str 给定的字符串
|
47
|
+
#
|
48
|
+
# === Example:
|
49
|
+
# Example :
|
50
|
+
# get "http://hi.baidu.com/"
|
51
|
+
# p find_has? "百度空间" #=> true
|
52
|
+
def find_has?(str)
|
53
|
+
raise "no any http request before!" if @response == nil
|
54
|
+
@response.body.include? str
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
# === 功能:
|
60
|
+
# 使用正则表达式的扫描,取出满足的集合
|
61
|
+
#
|
62
|
+
# === 参数解释:
|
63
|
+
# - regexp 扫描的正则表达式
|
64
|
+
# - return 一个二维数组,第一维是匹配上的串,第二维是正则表达式里面的group情况
|
65
|
+
#
|
66
|
+
# === Example:
|
67
|
+
# Example #1: 非block
|
68
|
+
#
|
69
|
+
# get "http://hi.baidu.com/腚腚熊/album"
|
70
|
+
# p find_scan /^imgarr\[len\]=\{purl:"(.*)",psrc:"(.*)",pname:"(.*)",pnum:"(.*)"/
|
71
|
+
# # => [["/%EB%EB%EB%EB%D0%DC/album/%C4%AC%C8%CF%CF%E0%B2%E1", "http://hiphotos.baidu.com/%EB%EB%EB%EB%D0%DC/abpic/item/8ddde41f55e355daa78669b4.jpg", "默认相册", "32"], ["/%EB%EB%EB%EB%D0%DC/album/%CE%D2%B5%C4%D1%D0%BE%BF%C9%FA%CA%B1%B4%FA", "http://hiphotos.baidu.com/%EB%EB%EB%EB%D0%DC/abpic/item/b7c672197f61435542a9ad2f.jpg", "我的研究生时代", "14"], ["/%EB%EB%EB%EB%D0%DC/album/3", "http://hiphotos.baidu.com/%EB%EB%EB%EB%D0%DC/abpic/item/0ded0b80781ddbcb9123d9b2.jpg", "3", "1"], ["/%EB%EB%EB%EB%D0%DC/album/4", "http://hiphotos.baidu.com/%EB%EB%EB%EB%D0%DC/abpic/item/e62608ea188ae1cfd539c991.jpg", "4", "1"], ["/%EB%EB%EB%EB%D0%DC/album/Kongde", "http://hiphotos.baidu.com/%EB%EB%EB%EB%D0%DC/abpic/item/8c3e0aef76094b36acafd5f0.jpg", "Kongde", "0"]]
|
72
|
+
#
|
73
|
+
# Example #2: block方式
|
74
|
+
#
|
75
|
+
# get "http://hi.baidu.com/腚腚熊/album"
|
76
|
+
# find_scan /^imgarr\[len\]=\{purl:"(.*)",psrc:"(.*)",pname:"(.*)",pnum:"(.*)"/ do |url,src,name,num|
|
77
|
+
# p "url:#{url} src:#{src} name:#{name} num:#{num}"
|
78
|
+
# end
|
79
|
+
# # => url:/%EB%EB%EB%EB%D0%DC/album/%C4%AC%C8%CF%CF%E0%B2%E1 src:http://hiphotos.baidu.com/%EB%EB%EB%EB%D0%DC/abpic/item/8ddde41f55e355daa78669b4.jpg name:默认相册 num:32
|
80
|
+
# # => ...
|
81
|
+
def find_scan(regexp,&blk)
|
82
|
+
raise "no any http request before!" if @response == nil
|
83
|
+
return @response.body.scan regexp,&blk
|
84
|
+
end
|
85
|
+
|
86
|
+
# === 功能:
|
87
|
+
# 判断元素是否存在
|
88
|
+
#
|
89
|
+
# === 参数解释:
|
90
|
+
# - xpath 定位,可以使xpath or selector
|
91
|
+
# - return 返回boolean
|
92
|
+
#
|
93
|
+
# === Example:
|
94
|
+
# get "http://www.baidu.com/"
|
95
|
+
# p find_exist? "title" # => true
|
96
|
+
def find_exist?(xpath)
|
97
|
+
raise "no any http request before!" if @response == nil
|
98
|
+
@hpricot ||= Hpricot(@response.body)
|
99
|
+
elems = @hpricot.search(xpath)
|
100
|
+
if block_given?
|
101
|
+
index = -1
|
102
|
+
elems = elems.select do |elem|
|
103
|
+
index = index + 1
|
104
|
+
yield elem,index
|
105
|
+
end
|
106
|
+
end
|
107
|
+
return !elems.empty?
|
108
|
+
end
|
109
|
+
|
110
|
+
# === 功能:
|
111
|
+
# 使用XPath或CSS Selector来提取html片段
|
112
|
+
#
|
113
|
+
# === 参数解释:
|
114
|
+
# - xpath 定位,可以使xpath or selector
|
115
|
+
# - return 返回String
|
116
|
+
#
|
117
|
+
# === Example:
|
118
|
+
# Example #1:
|
119
|
+
#
|
120
|
+
# get "http://www.baidu.com/"
|
121
|
+
# # HTML片段如下
|
122
|
+
# # <p id=km><a href=http://hi.baidu.com>空间</a> <a href=http://www.hao123.com>hao123</a>
|
123
|
+
# # | <a href=/more/>更多<span style="font-family:宋体">>></span></a></p>
|
124
|
+
#
|
125
|
+
# puts find_html "p#km"
|
126
|
+
# # <a href=http://hi.baidu.com>空间</a> <a href=http://www.hao123.com>hao123</a>
|
127
|
+
# # | <a href=/more/>更多<span style="font-family:宋体">>></span></a>
|
128
|
+
#
|
129
|
+
# puts find_html "//p[@id='km']"
|
130
|
+
# # 与上同
|
131
|
+
def find_html(xpath)
|
132
|
+
raise "no any http request before!" if @response == nil
|
133
|
+
@hpricot ||= Hpricot(@response.body)
|
134
|
+
elems = @hpricot.search(xpath)
|
135
|
+
if block_given?
|
136
|
+
index = -1
|
137
|
+
elems = elems.select do |elem|
|
138
|
+
index = index + 1
|
139
|
+
yield elem,index
|
140
|
+
end
|
141
|
+
end
|
142
|
+
raise HtmlError, "find_html xpath[#{xpath}] is not exist!" if elems.empty?
|
143
|
+
return elems.first.html.force_encoding "gbk"
|
144
|
+
end
|
145
|
+
|
146
|
+
# === 功能:
|
147
|
+
# 使用XPath或CSS Selector来提取text内容,不会包含HTML标签
|
148
|
+
#
|
149
|
+
# === 参数解释:
|
150
|
+
# - xpath 定位,可以使xpath or selector
|
151
|
+
# - return 返回String
|
152
|
+
#
|
153
|
+
# === Example:
|
154
|
+
# Example #1:
|
155
|
+
#
|
156
|
+
# get "http://www.baidu.com/"
|
157
|
+
# # HTML片段如下
|
158
|
+
# # <p id=km><a href=http://hi.baidu.com>空间</a>
|
159
|
+
# # <a href=http://www.hao123.com>hao123</a> | <a href=/more/>更多<span style="font-family:宋体">
|
160
|
+
# # >></span></a></p>
|
161
|
+
#
|
162
|
+
# puts find_text "p#km"
|
163
|
+
# # => 空间 hao123 | 更多>>
|
164
|
+
#
|
165
|
+
# puts find_text "//p[@id='km']"
|
166
|
+
# # 与上同
|
167
|
+
def find_text(xpath)
|
168
|
+
raise "no any http request before!" if @response == nil
|
169
|
+
@hpricot ||= Hpricot(@response.body)
|
170
|
+
elems = @hpricot.search(xpath)
|
171
|
+
if block_given?
|
172
|
+
index = -1
|
173
|
+
elems = elems.select do |elem|
|
174
|
+
index = index + 1
|
175
|
+
yield elem,index
|
176
|
+
end
|
177
|
+
end
|
178
|
+
raise HtmlError, "find_html xpath[#{xpath}] is not exist!" if elems.empty?
|
179
|
+
return elems.first.inner_text
|
180
|
+
end
|
181
|
+
|
182
|
+
# === 功能:
|
183
|
+
# 使用XPath或CSS Selector来提取HTML元素的属性值
|
184
|
+
#
|
185
|
+
# === 参数解释:
|
186
|
+
# - xpath 定位,可以使xpath or selector
|
187
|
+
# - attr 属性名
|
188
|
+
# - return 返回String
|
189
|
+
#
|
190
|
+
# === Example:
|
191
|
+
# Example #1:
|
192
|
+
#
|
193
|
+
# get "http://www.baidu.com/"
|
194
|
+
# # HTML片段如下
|
195
|
+
# # <p id=km><a href=http://hi.baidu.com>空间</a> <a href=http://www.hao123.com>hao123</a> | <a href=/more/>更多<span style="font-family:宋体">>></span></a></p>
|
196
|
+
#
|
197
|
+
# puts find_attr "p#km a:first", "href"
|
198
|
+
# # => http://hi.baidu.com
|
199
|
+
def find_attr(xpath, attr)
|
200
|
+
raise "no any http request before!" if @response == nil
|
201
|
+
@hpricot ||= Hpricot(@response.body)
|
202
|
+
elems = @hpricot.search(xpath)
|
203
|
+
if block_given?
|
204
|
+
index = -1
|
205
|
+
elems = elems.select do |elem|
|
206
|
+
index = index + 1
|
207
|
+
yield elem,index
|
208
|
+
end
|
209
|
+
end
|
210
|
+
raise HtmlError, "find_attr xpath[#{xpath}] is not exist!" if elems.empty?
|
211
|
+
elem = elems.first
|
212
|
+
raise HtmlError, "find_attr xpath[#{xpath}] ok, but elem[#{elem}] has no attr[#{attr}]!" unless elem.has_attribute? attr
|
213
|
+
return elem.get_attribute(attr)
|
214
|
+
end
|
215
|
+
|
216
|
+
# === 功能:
|
217
|
+
# 此方法不推荐使用,请使用 find_attr
|
218
|
+
def find_raw_attr(xpath, attr)
|
219
|
+
raise "no any http request before!" if @response == nil
|
220
|
+
@hpricot ||= Hpricot(@response.body)
|
221
|
+
elems = @hpricot.search(xpath.downcase)
|
222
|
+
if block_given?
|
223
|
+
index = -1
|
224
|
+
elems = elems.select do |elem|
|
225
|
+
index = index + 1
|
226
|
+
yield elem,index
|
227
|
+
end
|
228
|
+
end
|
229
|
+
raise HtmlError, "find_attr xpath[#{xpath}] is not exist!" if elems.empty?
|
230
|
+
elem = elems.first
|
231
|
+
raise HtmlError, "find_attr xpath[#{xpath}] ok, but elem[#{elem}] has no attr[#{attr}]!" unless elem.has_attribute? attr
|
232
|
+
return elem.raw_attributes[attr]
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
# === 功能:
|
237
|
+
# 使用XPath或CSS Selector来提取HTML元素集合的个数
|
238
|
+
#
|
239
|
+
# === 参数解释:
|
240
|
+
# - xpath 定位,可以使xpath or selector
|
241
|
+
# - return 返回Fixnum
|
242
|
+
#
|
243
|
+
# === Example:
|
244
|
+
# Example #1:
|
245
|
+
#
|
246
|
+
# get "http://www.baidu.com/"
|
247
|
+
# # HTML片段如下
|
248
|
+
# # <p id=km><a href=http://hi.baidu.com>空间</a> <a href=http://www.hao123.com>hao123</a> | <a href=/more/>更多<span style="font-family:宋体">>></span></a></p>
|
249
|
+
#
|
250
|
+
# puts find_size "p#km a"
|
251
|
+
# # => 3
|
252
|
+
# # 上层的意义可能是“输入框下面这一行显示3个超链接
|
253
|
+
def find_size(xpath)
|
254
|
+
raise "no any http request before!" if @response == nil
|
255
|
+
@hpricot ||= Hpricot(@response.body)
|
256
|
+
elems = @hpricot.search(xpath)
|
257
|
+
if block_given?
|
258
|
+
index = -1
|
259
|
+
elems = elems.select do |elem|
|
260
|
+
index = index + 1
|
261
|
+
yield elem,index
|
262
|
+
end
|
263
|
+
end
|
264
|
+
return elems.size
|
265
|
+
end
|
266
|
+
|
267
|
+
# 使用XPath或CSS Selector来提取HTML元素集合的个数
|
268
|
+
#
|
269
|
+
# === 参数解释:
|
270
|
+
# - xpath 父亲节点,可以使xpath or selector
|
271
|
+
# - excludes 排除的子节点名,长度可变参数
|
272
|
+
# - RETURN 返回非elems内的儿子节点集合
|
273
|
+
#
|
274
|
+
# === Example:
|
275
|
+
# get "http://hi.baidu.com/sys/search?word=我&from=wise"
|
276
|
+
# p find_children("entry > list > blog:first")
|
277
|
+
# #=> ["title", "content", "spsspaceurlorilist", "url", "time", "spsspacenamelist"]
|
278
|
+
# p find_children("entry > list > blog:first",%w{title content url time spsSpaceURLOriList})
|
279
|
+
# #=> ["spsspacenamelist"]
|
280
|
+
def find_children(xpath,excludes=[])
|
281
|
+
raise "no any http request before!" if @response == nil
|
282
|
+
@hpricot ||= Hpricot(@response.body)
|
283
|
+
elems = @hpricot.search(xpath)
|
284
|
+
if block_given?
|
285
|
+
index = -1
|
286
|
+
elems = elems.select do |elem|
|
287
|
+
index = index + 1
|
288
|
+
yield elem,index
|
289
|
+
end
|
290
|
+
end
|
291
|
+
raise HtmlError, "find_attr xpath[#{xpath}] is not exist!" if elems.empty?
|
292
|
+
elem = elems.first
|
293
|
+
|
294
|
+
rs = []
|
295
|
+
elem.children.each do |el|
|
296
|
+
if el.class == Hpricot::Elem and !excludes.include?(el.name)
|
297
|
+
rs << el.name
|
298
|
+
end
|
299
|
+
end
|
300
|
+
return rs
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
# === 功能:
|
305
|
+
# 高级接口,将 Hpricot 暴露出来,请参看 Hpricot 的使用手册
|
306
|
+
# 返回数组
|
307
|
+
#
|
308
|
+
# === 参数解释:
|
309
|
+
# - xpath 定位,可以使xpath or selector
|
310
|
+
# - return 返回Hpricot::Elems
|
311
|
+
#
|
312
|
+
# === Example:
|
313
|
+
# get "http://www.baidu.com"
|
314
|
+
# hpricot_search("div").each |elem|
|
315
|
+
# p elem
|
316
|
+
# end
|
317
|
+
def hpricot_search(xpath, &blk)
|
318
|
+
raise "no any http request before!" if @response == nil
|
319
|
+
@hpricot ||= Hpricot(@response.body)
|
320
|
+
@hpricot.search(xpath, &blk)
|
321
|
+
end
|
322
|
+
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
#
|
328
|
+
class HtmlError < StandardError
|
329
|
+
# TODO
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
if __FILE__ == $0
|
334
|
+
p __FILE__
|
335
|
+
p $0
|
336
|
+
class MyTest
|
337
|
+
include HtmlHelper
|
338
|
+
|
339
|
+
# 高级接口,将 Hpricot 暴露出来
|
340
|
+
def hpricot_search(xpath, &blk)
|
341
|
+
@hpricot ||= Hpricot("<tr><td>111</td><td id='q'>222</td><br/><td>333</td></tr>")
|
342
|
+
@hpricot.search(xpath, &blk)
|
343
|
+
end
|
344
|
+
def test
|
345
|
+
#post("http://passport.baidu.com/?login","username=hannyu5122&password=aaaa")
|
346
|
+
h = Hpricot("<tr><td>111</td><td id='q'>222</td><br/><td>333</td></tr>")
|
347
|
+
p h.search("tr td").text
|
348
|
+
p h.search("tr td#q").html
|
349
|
+
p h.search("tr td#q")[0]
|
350
|
+
p h.search("tr td#q")[0].next.html
|
351
|
+
p h.search("tr td")[0].get_attribute("id")
|
352
|
+
p h.search("tr td")[0].inner_text
|
353
|
+
p h.search("tr td#q")[0].html
|
354
|
+
p h.search("tt td")
|
355
|
+
p h.search("td").size
|
356
|
+
p h.search("tt td")[0].html
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
360
|
+
MyTest.new.test2
|
361
|
+
end
|
362
|
+
|
@@ -0,0 +1,469 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
#
|
4
|
+
# Author:: hanyu
|
5
|
+
# Date:: 2009.5.7
|
6
|
+
|
7
|
+
require 'net/http'
|
8
|
+
require 'net/https'
|
9
|
+
require 'cgi'
|
10
|
+
require 'uri'
|
11
|
+
require 'webrick'
|
12
|
+
require "common/http/multipart"
|
13
|
+
|
14
|
+
# 实现HTTP协议的支持,可以在action或case中调用
|
15
|
+
#
|
16
|
+
# - 封装 Net:HTTP 和 Net:HTTPS
|
17
|
+
# - 模拟浏览器的Cookie策略,不完全实现,不支持Expire(没必要)
|
18
|
+
# - 上下文环境的保持,request & response
|
19
|
+
# - 编码转换(统一使用gbk)
|
20
|
+
# - Referer、User-Agent等的自动填入
|
21
|
+
# - 打印可读日志
|
22
|
+
module HttpHelper
|
23
|
+
|
24
|
+
# === 功能:
|
25
|
+
# 发送POST请求
|
26
|
+
#
|
27
|
+
# === 参数解释:
|
28
|
+
# - url http请求的url,比如: http://hi.baidu.com/,前面的http和后面的/都不能省略
|
29
|
+
# - data post的数据,Hash格式,键可以是字符串或符号,值可以是字符串或其他
|
30
|
+
# - header http请求携带的header,比如referer、p3p等,形式与data类似
|
31
|
+
# - file 支持上传文件,可以传多个,Hash格式,键为参数名,值为文件的本地路径
|
32
|
+
#
|
33
|
+
# === Example:
|
34
|
+
# Example #1:
|
35
|
+
# # 模拟登录
|
36
|
+
# post "http://passport.baidu.com/?login", {
|
37
|
+
# :username => 'xxx',
|
38
|
+
# :password => 'yyy'
|
39
|
+
# }
|
40
|
+
#
|
41
|
+
# Example #2:
|
42
|
+
# # 自定义header
|
43
|
+
# login user
|
44
|
+
# post "http://hi.baidu.com/xxx/commit", {
|
45
|
+
# :ct => 1,
|
46
|
+
# :cm => 2,
|
47
|
+
# ........
|
48
|
+
# }, {
|
49
|
+
# "Myhead" => "okoko"
|
50
|
+
# }
|
51
|
+
#
|
52
|
+
# Example #3:
|
53
|
+
# post "http://hi.baidu.com/upload",{
|
54
|
+
# :xxx => 'yyy'
|
55
|
+
# }
|
56
|
+
# # 环境变量的注入
|
57
|
+
# puts @request.method
|
58
|
+
# puts @response.body
|
59
|
+
# puts @response.header["Content-Length"]
|
60
|
+
# puts @cookies
|
61
|
+
#
|
62
|
+
# Example #4:
|
63
|
+
# # 上传文件
|
64
|
+
# post "http://hi.baidu.com/upload",{
|
65
|
+
# :xxx => 'yyy'
|
66
|
+
# },{},{
|
67
|
+
# "param_name" => "file_path"
|
68
|
+
# }
|
69
|
+
#
|
70
|
+
def post(url,data={},header={},file={})
|
71
|
+
#解析成URI
|
72
|
+
$myparse = $myparse || URI::Parser.new(:RESERVED=>URI::REGEXP::PATTERN::RESERVED+"%")
|
73
|
+
uri = $myparse.parse $myparse.escape(url)
|
74
|
+
raise HttpError, "url[#{url}] parse fail! e.g. http://hi.baidu.com/" if uri.scheme.nil? or uri.host.nil? or uri.path.empty?
|
75
|
+
|
76
|
+
# CGI:URI.path 需要加上query部分才能构成一个正常的请求
|
77
|
+
path = (uri.query==nil) ? uri.path : uri.path+"?"+uri.query
|
78
|
+
|
79
|
+
# 把header符号变成字符串
|
80
|
+
header.each do |k,v|
|
81
|
+
if k.class == Symbol
|
82
|
+
header[k.to_s] = v.to_s
|
83
|
+
header.delete k
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# 初始化Post请求
|
88
|
+
req = Net::HTTP::Post.new(path, header)
|
89
|
+
req.set_content_type "application/x-www-form-urlencoded" unless req.content_type
|
90
|
+
|
91
|
+
# 发送请求
|
92
|
+
send_http req,uri,data,file
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
# === 功能:
|
97
|
+
# 发送GET请求
|
98
|
+
#
|
99
|
+
# === 参数解释:
|
100
|
+
# - url http请求的url,比如: http://hi.baidu.com/,前面的http和后面的/都不能省略
|
101
|
+
# - data 数据将被编码并附在url的后面,Hash格式,键可以是字符串或符号,值可以是字符串或其他
|
102
|
+
# - header http请求携带的header,比如referer、p3p等,形式与data类似
|
103
|
+
#
|
104
|
+
# === Example:
|
105
|
+
# Example #1:
|
106
|
+
# # 注意url要写全,带上协议头"http",以及路径,若是根路径末尾要加"/"
|
107
|
+
# get "http://www.baidu.com/"
|
108
|
+
#
|
109
|
+
# Example #2:
|
110
|
+
# # 支持https
|
111
|
+
# get "https://passport.baidu.com/"
|
112
|
+
#
|
113
|
+
# Example #3:
|
114
|
+
# get "http://www.baidu.com/"
|
115
|
+
# # 环境变量的注入
|
116
|
+
# puts @request.method
|
117
|
+
# puts @response.body
|
118
|
+
# puts @response.header["Content-Length"]
|
119
|
+
# puts @cookies
|
120
|
+
#
|
121
|
+
# Example #4:
|
122
|
+
# # 可自定义 HTTP Header
|
123
|
+
# get "http://hi.baidu.com/",{
|
124
|
+
# :q => "空间",
|
125
|
+
# :t => "haha"
|
126
|
+
# },{
|
127
|
+
# "Cookie" => "BDUSS=xxx;",
|
128
|
+
# "Referer" => "google.com"
|
129
|
+
# }
|
130
|
+
#
|
131
|
+
# Example #5:
|
132
|
+
# # 带参数
|
133
|
+
# get "https://passport.baidu.com/",{
|
134
|
+
# :name => "walle",
|
135
|
+
# :password => "1111"
|
136
|
+
# }
|
137
|
+
#
|
138
|
+
def get(url,data={},header={})
|
139
|
+
#解析成URI
|
140
|
+
$myparse = $myparse || URI::Parser.new(:RESERVED=>URI::REGEXP::PATTERN::RESERVED+"%")
|
141
|
+
uri = $myparse.parse $myparse.escape(url)
|
142
|
+
raise HttpError, "url[#{url}] parse fail! e.g. http://hi.baidu.com/" if uri.scheme.nil? or uri.host.nil? or uri.path.empty?
|
143
|
+
|
144
|
+
# CGI:URI.path 需要加上query部分才能构成一个正常的请求
|
145
|
+
path = (uri.query==nil) ? uri.path : uri.path+"?"+uri.query
|
146
|
+
|
147
|
+
# 将data转成url中的参数
|
148
|
+
path << "?" if data.size>0 && !path.include?("?")
|
149
|
+
data.each do |k,v|
|
150
|
+
path << "&" if !path.end_with?("&") && !path.end_with?("?")
|
151
|
+
path << k.to_s + "=" + CGI::escape(v.to_s)
|
152
|
+
end
|
153
|
+
|
154
|
+
# 把header符号变成字符串
|
155
|
+
header.each do |k,v|
|
156
|
+
if k.class == Symbol
|
157
|
+
header[k.to_s] = v.to_s
|
158
|
+
header.delete k
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# 初始化Get请求
|
163
|
+
req = Net::HTTP::Get.new(path, header)
|
164
|
+
|
165
|
+
# 发送请求
|
166
|
+
send_http req,uri
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
def download(uri, path=nil)
|
171
|
+
begin
|
172
|
+
if path
|
173
|
+
file_name = path + uri.split('/').last
|
174
|
+
file_name.sub(/\/\//, '/')
|
175
|
+
else
|
176
|
+
file_name = uri.split('/').last
|
177
|
+
end
|
178
|
+
|
179
|
+
file_content = get uri
|
180
|
+
#puts file_name
|
181
|
+
File.open(file_name, "w+") do |file|
|
182
|
+
file.binmode # must be in binary mode
|
183
|
+
file.write file_content
|
184
|
+
file.rewind
|
185
|
+
end
|
186
|
+
rescue => err
|
187
|
+
puts err
|
188
|
+
return ''
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# === 功能:
|
193
|
+
# 发送PUT请求
|
194
|
+
# 未实现,有需求吗?
|
195
|
+
#
|
196
|
+
# === 参数解释:
|
197
|
+
#
|
198
|
+
# === Example:
|
199
|
+
#
|
200
|
+
def put(url,data="",header=nil,file=nil)
|
201
|
+
#TODO
|
202
|
+
end
|
203
|
+
|
204
|
+
# === 功能:
|
205
|
+
# 发送DELETE请求
|
206
|
+
# 未实现,有需求吗?
|
207
|
+
#
|
208
|
+
# === 参数解释:
|
209
|
+
#
|
210
|
+
# === Example:
|
211
|
+
#
|
212
|
+
def delete(url,data=nil,header=nil)
|
213
|
+
#TODO
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
# === 功能:
|
218
|
+
# 清空当前cookie
|
219
|
+
#
|
220
|
+
# === 参数解释:
|
221
|
+
#
|
222
|
+
# === Example:
|
223
|
+
# get "http://www.baidu.com/"
|
224
|
+
# clear_cookie # => 清空cookie
|
225
|
+
# get "http://hi.baidu.com/"
|
226
|
+
def clear_cookie
|
227
|
+
@cookies = {}
|
228
|
+
end
|
229
|
+
|
230
|
+
# === 功能:
|
231
|
+
# 指定不要进行转码
|
232
|
+
#
|
233
|
+
# === 参数解释:
|
234
|
+
#
|
235
|
+
# === Example:
|
236
|
+
# Example #1: block方式
|
237
|
+
#
|
238
|
+
# dont_encode do
|
239
|
+
# get "..."
|
240
|
+
# post "..."
|
241
|
+
# end
|
242
|
+
# # 凡是块里面的请求都不会有转码,但是块外面的代码仍然可以
|
243
|
+
#
|
244
|
+
# Example #2: 非block方式
|
245
|
+
#
|
246
|
+
# get "http://www.baidu.com/"
|
247
|
+
# # 返回页面经过转码,转成GBK
|
248
|
+
# dont_encode
|
249
|
+
# get "http://www.baidu.com/"
|
250
|
+
# # 返回页面在任何情况下都不会做任何转码
|
251
|
+
# # ...
|
252
|
+
# do_encode
|
253
|
+
# # 恢复转码方式
|
254
|
+
# get "http://www.baidu.com/"
|
255
|
+
# # 返回页面经过转码,转成GBK
|
256
|
+
def dont_encode
|
257
|
+
if block_given?
|
258
|
+
@dont_encode = true
|
259
|
+
yield
|
260
|
+
@dont_encode = false
|
261
|
+
else
|
262
|
+
@dont_encode = true
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# === 功能:
|
267
|
+
# 参见dont_encode
|
268
|
+
def do_encode
|
269
|
+
if block_given?
|
270
|
+
@dont_encode = false
|
271
|
+
yield
|
272
|
+
@dont_encode = true
|
273
|
+
else
|
274
|
+
@dont_encode = false
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# === 功能:
|
279
|
+
# 打印当前HTTP请求返回的content,可用于调试
|
280
|
+
#
|
281
|
+
# === 参数解释:
|
282
|
+
# 无
|
283
|
+
#
|
284
|
+
# === Example:
|
285
|
+
# get "http://www.baidu.com/"
|
286
|
+
# print_body
|
287
|
+
# #=> <html><head><meta http-equiv=Content-Type content="text/html;charset=gb2312"><title>百度一下,你就知道 </title>.....(省略)
|
288
|
+
#
|
289
|
+
def print_body
|
290
|
+
puts @response.body unless @response.nil?
|
291
|
+
end
|
292
|
+
|
293
|
+
# === 功能:
|
294
|
+
# 打印当前HTTP请求返回的所有Header,可用于调试
|
295
|
+
#
|
296
|
+
# === 参数解释:
|
297
|
+
# 无
|
298
|
+
#
|
299
|
+
# === Example:
|
300
|
+
# get "http://www.baidu.com/"
|
301
|
+
# print_head
|
302
|
+
# #=> {"date"=>["Sun, 27 Dec 2009 12:04:29 GMT"], "server"=>["BWS/1.0"], "content-length"=>["3657"], "content-type"=>["text/html;charset=gb2312"], "cache-control"=>["private"], "expires"=>["Sun, 27 Dec 2009 12:04:29 GMT"], "set-cookie"=>["BAIDUID=95C50755A927A287A68E2014CEF4CF1E:FG=1; expires=Sun, 27-Dec-39 12:04:29 GMT; path=/; domain=.baidu.com"], "p3p"=>["CP=\" OTI DSP COR IVA OUR IND COM \""]}
|
303
|
+
#
|
304
|
+
def print_head
|
305
|
+
puts @response.to_hash unless @response.nil?
|
306
|
+
end
|
307
|
+
alias print_header print_head
|
308
|
+
|
309
|
+
# 以下方法为私有
|
310
|
+
private
|
311
|
+
|
312
|
+
# 封装发送HTTP细节
|
313
|
+
def send_http(req,uri,data=nil,file={})
|
314
|
+
#注入上下文环境中的cookie
|
315
|
+
@cookies = {} if @cookies.nil?
|
316
|
+
@cookies.each do |key,coos|
|
317
|
+
if uri.host.end_with? key
|
318
|
+
coos.each do |coo|
|
319
|
+
if req.key? "cookie"
|
320
|
+
req["cookie"] += "#{coo.name}=#{coo.value};"
|
321
|
+
else
|
322
|
+
req["cookie"] = "#{coo.name}=#{coo.value};"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
# 填入默认header
|
329
|
+
# req["User-Agent"] = "#{ConfigHelper::CONF['user_agent']}" if req["User-Agent"] == "Ruby"
|
330
|
+
# req["Referer"] = "#{@referer}" unless req.key? "referer"
|
331
|
+
|
332
|
+
# 如果上传文件,需要Multipart的支持
|
333
|
+
if file.size > 0
|
334
|
+
file.each do |k,v|
|
335
|
+
file[k] = File.new v
|
336
|
+
end
|
337
|
+
data_str, headers = Multipart::Post.prepare_query data.merge(file)
|
338
|
+
req["Content-Type"] = headers["Content-Type"]
|
339
|
+
else
|
340
|
+
#转义data
|
341
|
+
if data.nil?
|
342
|
+
data_str = nil
|
343
|
+
elsif data.kind_of? Hash
|
344
|
+
data_str = data.inject("") do |mem, (key, value)|
|
345
|
+
mem << "&" if mem.size > 0
|
346
|
+
mem << key.to_s + "=" + CGI::escape(value.to_s)
|
347
|
+
end
|
348
|
+
else
|
349
|
+
raise "data must be Hash"
|
350
|
+
end
|
351
|
+
|
352
|
+
end
|
353
|
+
|
354
|
+
#如果是HTTPS 安全连接
|
355
|
+
conn = Net::HTTP.new(uri.host, uri.port)
|
356
|
+
if uri.scheme == "https"
|
357
|
+
conn.use_ssl = true
|
358
|
+
conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
359
|
+
end
|
360
|
+
|
361
|
+
take = 0
|
362
|
+
#加入异常捕获机器
|
363
|
+
begin
|
364
|
+
ts1 = Time.now
|
365
|
+
#发送HTTP请求
|
366
|
+
res = conn.start do |http|
|
367
|
+
#puts "data_str.size: #{data_str.size}" unless data_str.nil?
|
368
|
+
http.request(req,data_str)
|
369
|
+
end
|
370
|
+
ts2 = Time.now
|
371
|
+
take = ts2 - ts1
|
372
|
+
rescue SocketError => err
|
373
|
+
#域名不能解析,机器下线?
|
374
|
+
$log.error "#{req.method} url[#{uri}] data[#{data}] file[#{file}] time[#{take}s] FAIL! Host[#{uri.host}] is unknown! Maybe it is out of the DNS."
|
375
|
+
raise HttpError, "host[#{uri.host}] is unknown! Maybe it is out of the DNS."
|
376
|
+
rescue EOFError => err
|
377
|
+
#连接被中断,被transmit拒?
|
378
|
+
$log.error "#{req.method} url[#{uri}] data[#{data}] file[#{file}] time[#{take}s] FAIL! Connection with uri[#{uri}] is interrupted! Maybe transmit did this."
|
379
|
+
raise HttpError, "Connection with uri[#{uri}] is interrupted! Maybe transmit did this."
|
380
|
+
rescue SystemCallError => err
|
381
|
+
#服务被拒绝,端口未开放?
|
382
|
+
$log.error "#{req.method} url[#{uri}] data[#{data}] file[#{file}] time[#{take}s] FAIL! Connection with uri[#{uri}] is refused! Maybe the port[#{uri.port}] is not open."
|
383
|
+
raise HttpError, "Connection with uri[#{uri}] is refused! Maybe the port[#{uri.port}] is not open."
|
384
|
+
end
|
385
|
+
#将返回的cookie存入上下文环境中
|
386
|
+
if res.key?('set-cookie')
|
387
|
+
res.get_fields('set-cookie').each do |str|
|
388
|
+
cookie = WEBrick::Cookie.parse_set_cookie(str)
|
389
|
+
cookie.domain = uri.host if cookie.domain == nil
|
390
|
+
if @cookies.key?(cookie.domain)
|
391
|
+
@cookies[cookie.domain].delete_if do |coo|
|
392
|
+
coo.name == cookie.name
|
393
|
+
end
|
394
|
+
@cookies[cookie.domain] << cookie if cookie.value != "deleted"
|
395
|
+
else
|
396
|
+
@cookies[cookie.domain] = [cookie]
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
#置上下文变量
|
402
|
+
@referer = uri.to_s
|
403
|
+
@request = req
|
404
|
+
@response = res
|
405
|
+
@hpricot = nil
|
406
|
+
|
407
|
+
# #编码转换
|
408
|
+
# unless res.body.nil? or
|
409
|
+
# @dont_encode or
|
410
|
+
# res["Content-Type"].nil? or # 如果没有 content-type 字段,那么不做转换
|
411
|
+
# res["Content-Type"].include? "image" or # 图片不转
|
412
|
+
# res["Content-Type"].include? "video" or # 视频不转
|
413
|
+
# res["Content-Type"].include? "audio" # 声音不转
|
414
|
+
# ct = res["Content-Type"].scan(/charset=(.*?);?$/)[0]
|
415
|
+
# encod = ct[0].downcase unless ct.nil?
|
416
|
+
# if ! encod.nil?
|
417
|
+
# if encod=="gbk" or encod=="gb2312"
|
418
|
+
# res.body = res.body.force_encoding("gbk")
|
419
|
+
# else
|
420
|
+
# res.body = res.body.force_encoding(encod).encode "gbk"
|
421
|
+
# end
|
422
|
+
# else
|
423
|
+
# if ConfigHelper::CONF["default_encoding"]=="gbk"
|
424
|
+
# res.body = res.body.force_encoding("gbk")
|
425
|
+
# else
|
426
|
+
# res.body = res.body.force_encoding(ConfigHelper::CONF["default_encoding"]).encode "gbk"
|
427
|
+
# end
|
428
|
+
# end
|
429
|
+
# end
|
430
|
+
res.body
|
431
|
+
end
|
432
|
+
|
433
|
+
end
|
434
|
+
|
435
|
+
class HttpError < StandardError
|
436
|
+
# do nothing
|
437
|
+
end
|
438
|
+
|
439
|
+
|
440
|
+
|
441
|
+
if __FILE__ == $0
|
442
|
+
$LIB_ROOT = "#{File.dirname(__FILE__)}/.."
|
443
|
+
$TEST_ROOT = "#{$LIB_ROOT}/.."
|
444
|
+
$: << "#{$LIB_ROOT}"
|
445
|
+
require 'common/log_helper'
|
446
|
+
require 'common/config_helper'
|
447
|
+
|
448
|
+
class MyTest
|
449
|
+
include HttpHelper
|
450
|
+
|
451
|
+
def test1
|
452
|
+
@cookies = {}
|
453
|
+
#post("http://passport.baidu.com/?login","username=hannyu5122&password=aaaa")
|
454
|
+
get "http://www.baidu.com/"
|
455
|
+
puts @response.body
|
456
|
+
get "http://sz-testing-space07.sz01.baidu.com:5120/haoba?oko"
|
457
|
+
end
|
458
|
+
def test2
|
459
|
+
@cookies = {}
|
460
|
+
assert_raise HttpError do
|
461
|
+
get "http://db-testing-space13.db01.baidu.com:4444/developers"
|
462
|
+
#get "http://db-testing-space13.db01.baidu.com:8080/developers"
|
463
|
+
get "http://db-testing-sp.db01.baidu.com:8080/developers"
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
MyTest.new.test2
|
468
|
+
end
|
469
|
+
|