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
data/data/user.house
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '.')
|
4
|
+
|
5
|
+
module CheckActionHelper
|
6
|
+
include MylogHelper
|
7
|
+
|
8
|
+
# === 功能
|
9
|
+
# IOHEAD的正则匹配
|
10
|
+
#
|
11
|
+
# === 参数
|
12
|
+
# - pattern 正则式
|
13
|
+
#
|
14
|
+
# Example
|
15
|
+
# assert_head "log_id:10"
|
16
|
+
def assert_head pattern
|
17
|
+
assert_match(pattern, Context.get("IOHEAD"), "IOHEAD mismatch")
|
18
|
+
puts "AssertOK IOHEAD #{pattern}"
|
19
|
+
$log.info "AssertOK IOHEAD #{pattern}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# === 功能
|
23
|
+
# IOBODY的正则匹配
|
24
|
+
#
|
25
|
+
# === 参数
|
26
|
+
# - pattern 正则式
|
27
|
+
#
|
28
|
+
# Example
|
29
|
+
# assert_body "a.*b.*c"
|
30
|
+
def assert_body pattern
|
31
|
+
assert_match(pattern, Context.get("IOBODY"), "IOBODY mismatch")
|
32
|
+
puts "AssertOK IOBODY #{pattern}"
|
33
|
+
$log.info "AssertOK IOBODY #{pattern}"
|
34
|
+
end
|
35
|
+
|
36
|
+
# === 检查是否存在core文件
|
37
|
+
#
|
38
|
+
# === 参数
|
39
|
+
# - host 机器
|
40
|
+
#
|
41
|
+
# === Example:
|
42
|
+
# core_check
|
43
|
+
def core_check host=HOST, user=USERNAME, password=PASSWORD
|
44
|
+
if Util.is_localhost? (host) then
|
45
|
+
ret = system "file ~/*.core"
|
46
|
+
else
|
47
|
+
ret = Util.exe_ssh_cmd! host, "file ~/*.core", user, password
|
48
|
+
end
|
49
|
+
Context.set("IOBODY", ret)
|
50
|
+
assert_body("cannot open")
|
51
|
+
$log.info "core_check"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '.')
|
4
|
+
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
|
8
|
+
module CNNTActionHelper
|
9
|
+
include Socket::Constants
|
10
|
+
|
11
|
+
# === 建立连接 用于长连接操作
|
12
|
+
#
|
13
|
+
# === 参数
|
14
|
+
# - ip
|
15
|
+
# - port
|
16
|
+
#
|
17
|
+
# === 返回
|
18
|
+
# socekt 句柄
|
19
|
+
#
|
20
|
+
# === Example:
|
21
|
+
# socket = cnnt_connect 127.0.0.1, 1900
|
22
|
+
def cnnt_connect ip, port
|
23
|
+
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
|
24
|
+
sockaddr = Socket.pack_sockaddr_in( port, ip )
|
25
|
+
socket.connect( sockaddr )
|
26
|
+
return socket
|
27
|
+
end
|
28
|
+
|
29
|
+
# === 发送数据 用于长连接操作
|
30
|
+
#
|
31
|
+
# === 参数
|
32
|
+
# socket 用于发送的socket句柄
|
33
|
+
# cont 发送的内容
|
34
|
+
#
|
35
|
+
# === 返回
|
36
|
+
# 发送的数据长度
|
37
|
+
#
|
38
|
+
# === Example
|
39
|
+
# cnnt_send socket, "dddd"
|
40
|
+
def cnnt_send socket, cont
|
41
|
+
socket.send cont, 0
|
42
|
+
end
|
43
|
+
|
44
|
+
# === 关闭连接 用于长连接操作
|
45
|
+
#
|
46
|
+
# === 参数
|
47
|
+
# socket 用于操作的socket句柄
|
48
|
+
#
|
49
|
+
# === Example
|
50
|
+
# cnnt_close socket
|
51
|
+
def cnnt_close socket
|
52
|
+
socket.close
|
53
|
+
end
|
54
|
+
|
55
|
+
# === 发送一次数据 用于短连接操作
|
56
|
+
#
|
57
|
+
# === 参数
|
58
|
+
# ip ip
|
59
|
+
# port 端口
|
60
|
+
# cont 要发送的内容
|
61
|
+
#
|
62
|
+
# === 返回
|
63
|
+
# 发送的数据长度
|
64
|
+
#
|
65
|
+
# === Example
|
66
|
+
# cnnt_short_send "127.0.0.1", 1900, "dddd"
|
67
|
+
def cnnt_direct_send ip, port, cont
|
68
|
+
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
|
69
|
+
sockaddr = Socket.pack_sockaddr_in( port, ip )
|
70
|
+
socket.connect( sockaddr )
|
71
|
+
ret = socket.send cont, 0
|
72
|
+
socket.close
|
73
|
+
return ret
|
74
|
+
end
|
75
|
+
|
76
|
+
# === 创建一个server 处理部分需要用户自己完成
|
77
|
+
# 该server可以接收多线程的连接
|
78
|
+
#
|
79
|
+
# === 参数
|
80
|
+
# port 端口
|
81
|
+
# yield 处理函数
|
82
|
+
#
|
83
|
+
# === 返回
|
84
|
+
# 服务器线程句柄
|
85
|
+
#
|
86
|
+
# === Example
|
87
|
+
# a1 = cnnt_create_server(1999) {|client|
|
88
|
+
# data = client.recvfrom(200)[0]
|
89
|
+
# if data.length>0
|
90
|
+
# p data
|
91
|
+
# end
|
92
|
+
#}
|
93
|
+
def cnnt_create_server port
|
94
|
+
svr_t = Thread.new {
|
95
|
+
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
|
96
|
+
sockaddr = Socket.pack_sockaddr_in( port, 'localhost' )
|
97
|
+
socket.bind( sockaddr )
|
98
|
+
socket.listen( 5 )
|
99
|
+
loop do
|
100
|
+
client, client_sockaddr = socket.accept
|
101
|
+
Thread.new{
|
102
|
+
loop do
|
103
|
+
yield client
|
104
|
+
end
|
105
|
+
}
|
106
|
+
end
|
107
|
+
socket.close
|
108
|
+
}
|
109
|
+
return svr_t
|
110
|
+
end
|
111
|
+
|
112
|
+
# === 创建一个server 接收到的数据被放到cont数组中
|
113
|
+
# 该函数仅支持一个线程的连接请求
|
114
|
+
#
|
115
|
+
# === 参数
|
116
|
+
# port 端口
|
117
|
+
# cont 接收数据用的数组
|
118
|
+
#
|
119
|
+
# === 返回
|
120
|
+
# 服务器线程句柄
|
121
|
+
#
|
122
|
+
# === Example
|
123
|
+
# cont=[]
|
124
|
+
# cnnt_create_practical_server 1999, cont
|
125
|
+
# cnnt_direct_send "127.0.0.1", 1999, "dddd"
|
126
|
+
# p cont[0]
|
127
|
+
def cnnt_create_practical_server port, cont
|
128
|
+
svr_t = Thread.new {
|
129
|
+
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
|
130
|
+
sockaddr = Socket.pack_sockaddr_in( port, 'localhost' )
|
131
|
+
socket.bind( sockaddr )
|
132
|
+
socket.listen( 5 )
|
133
|
+
client, client_sockaddr = socket.accept
|
134
|
+
loop do
|
135
|
+
cont << client.recvfrom(1024)[0]
|
136
|
+
end
|
137
|
+
socket.close
|
138
|
+
}
|
139
|
+
return svr_t
|
140
|
+
end
|
141
|
+
|
142
|
+
# === 停止服务线程
|
143
|
+
#
|
144
|
+
# === 参数
|
145
|
+
# svr 服务器线程句柄
|
146
|
+
#
|
147
|
+
# === Example
|
148
|
+
# cnnt_stop_server svr
|
149
|
+
def cnnt_stop_server svr
|
150
|
+
svr.exit
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
if __FILE__ == $0
|
159
|
+
end
|
160
|
+
|
161
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '.')
|
4
|
+
|
5
|
+
|
6
|
+
module DataCenterActionHelper
|
7
|
+
|
8
|
+
# 功能
|
9
|
+
# 对模块进行基线数据的恢复
|
10
|
+
#
|
11
|
+
# Example
|
12
|
+
=begin
|
13
|
+
mdl_friend = ModuleHouse.get_instance.get_by_name "friend"
|
14
|
+
datacenter = DCHouse.get_instance.get_by_name "datacenter"
|
15
|
+
new_conf = {
|
16
|
+
"adr"=>datacenter["host"],
|
17
|
+
"username"=>datacenter["db01"]["dbuser"],
|
18
|
+
"port"=>datacenter["db01"]["dbport"],
|
19
|
+
"passwd"=>datacenter["db01"]["dbpass"],
|
20
|
+
"dbname"=>mdl_friend["dbname"],
|
21
|
+
"dbport"=>datacenter["db01"]["dbport"]
|
22
|
+
}
|
23
|
+
MoudleHouse.get_instance.set_new_conf(mdl_friend, new_conf)
|
24
|
+
module_prepare datacenter, mdl_friend
|
25
|
+
=end
|
26
|
+
def module_prepare datacenter, mdl
|
27
|
+
if mdl["recoversql"] == 1
|
28
|
+
if mdl["dbversion"] == "5.1.30"
|
29
|
+
ssh_cmd datacenter["host"], datacenter["user"], datacenter["pass"], "#{datacenter["db01"]["dbpath"]}/bin/mysql -u#{datacenter["db01"]["dbuser"]} -p#{datacenter["db01"]["dbpass"]} #{mdl["dbname"]} < #{datacenter["datacenterpath"]}/#{mdl["basesql"]}"
|
30
|
+
end
|
31
|
+
if mdl["dbversion"] == "5.22"
|
32
|
+
ssh_cmd datacenter["host"], datacenter["user"], datacenter["pass"], "#{datacenter["db02"]["dbpath"]}/bin/mysql -u#{datacenter["db02"]["dbuser"]} -p#{datacenter["db02"]["dbpass"]} #{mdl["dbname"]} < #{datacenter["datacenterpath"]}/#{mdl["basesql"]}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
if mdl["recoverdata"] == 1
|
36
|
+
ssh_cmd datacenter["host"], datacenter["user"], datacenter["pass"], "H #{mdl["h_name"]} -pub #{datacenter["datacenterpath"]}/#{mdl["basedata"]} #{datacenter["datadownloadto"]}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
#if __FILE__ =
|
46
|
+
#end
|
47
|
+
|
48
|
+
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
#
|
4
|
+
# Author:: wangkaihua.
|
5
|
+
# Date:: 2009.12.18
|
6
|
+
|
7
|
+
require 'webrick'
|
8
|
+
|
9
|
+
class HttpRequest < WEBrick::HTTPRequest
|
10
|
+
attr_reader :io, :config
|
11
|
+
|
12
|
+
def initialize(io)
|
13
|
+
@io=io
|
14
|
+
@config={
|
15
|
+
:RequestTimeout =>30,
|
16
|
+
:InputBufferSize =>65536,
|
17
|
+
:HTTPVersion =>WEBrick::HTTPVersion.new("1.1"),
|
18
|
+
:Logger =>WEBrick::Log.new,
|
19
|
+
:Escape8bitURI =>false,
|
20
|
+
:ServerSoftware =>"Ruby HttpServer 1.0"
|
21
|
+
}
|
22
|
+
super(@config)
|
23
|
+
parse(io)
|
24
|
+
end
|
25
|
+
|
26
|
+
def content
|
27
|
+
query
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class HttpResponse
|
32
|
+
attr_reader :header
|
33
|
+
attr_accessor :body, :status, :status_message
|
34
|
+
|
35
|
+
def initialize(status=200)
|
36
|
+
@status = status
|
37
|
+
@status_message = nil
|
38
|
+
@header = Table.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def charset
|
42
|
+
return nil if @header["Content-Type"]==nil
|
43
|
+
charset_array=@header["Content-Type"].scan(/charset=([^; ]*)/)[0]
|
44
|
+
return nil if charset_array==nil
|
45
|
+
return charset_array[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_http_pack(status_code=nil, status_message=nil, header=nil, body=nil)
|
49
|
+
_status_code_=(status_code==nil) ? @status : status_code
|
50
|
+
_status_message_=(status_message==nil) ? StatusCodeMapping[_status_code_] : status_message
|
51
|
+
_header_=(header==nil) ? @header : header
|
52
|
+
_body_=(body==nil) ? @body : body
|
53
|
+
|
54
|
+
# _status_message_ ||= StatusCodeMapping[_status_code_]
|
55
|
+
|
56
|
+
#encoding body.
|
57
|
+
unless _body_.nil?
|
58
|
+
if charset==nil
|
59
|
+
_body_=_body_.force_encoding("gbk")
|
60
|
+
else
|
61
|
+
encod=charset.downcase
|
62
|
+
if encod=="gbk" or encod=="gb2312"
|
63
|
+
_body_=_body_.force_encoding("gbk")
|
64
|
+
else
|
65
|
+
_body_=_body_.force_encoding("gbk").encode(encod)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#to pack.
|
71
|
+
http_pack = ""
|
72
|
+
http_pack << "#{HTTP_PROTO} #{_status_code_} #{_status_message_}" << CRLF
|
73
|
+
http_header(_header_, _body_).writeTo(http_pack)
|
74
|
+
http_pack << CRLF
|
75
|
+
|
76
|
+
http_pack << _body_ unless _body_.nil?
|
77
|
+
http_pack
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
private
|
82
|
+
# Helper Methods ------------------------------------------
|
83
|
+
|
84
|
+
def http_header(header=nil, body=nil)
|
85
|
+
new_header = Table.new(DEFAULT_HEADER)
|
86
|
+
|
87
|
+
#auto modify content-length.
|
88
|
+
new_header["Content-Length"] = "0"
|
89
|
+
new_header["Content-Length"] = body.bytesize unless body == nil
|
90
|
+
new_header["Connection"] = "close"
|
91
|
+
new_header["Date"] = http_date(Time.now)
|
92
|
+
|
93
|
+
new_header.update(header) unless header.nil?
|
94
|
+
new_header
|
95
|
+
end
|
96
|
+
|
97
|
+
def http_date( aTime )
|
98
|
+
aTime.gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" )
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# Constants -----------------------------------------------
|
105
|
+
|
106
|
+
CRLF = "\r\n"
|
107
|
+
HTTP_PROTO = "HTTP/1.0"
|
108
|
+
SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})"
|
109
|
+
|
110
|
+
DEFAULT_HEADER = {
|
111
|
+
"Server" => SERVER_NAME
|
112
|
+
}
|
113
|
+
|
114
|
+
##
|
115
|
+
# Mapping of status code and error message
|
116
|
+
#
|
117
|
+
StatusCodeMapping = {
|
118
|
+
200 => "OK",
|
119
|
+
400 => "Bad Request",
|
120
|
+
403 => "Forbidden",
|
121
|
+
405 => "Method Not Allowed",
|
122
|
+
411 => "Length Required",
|
123
|
+
500 => "Internal Server Error"
|
124
|
+
}
|
125
|
+
|
126
|
+
##
|
127
|
+
# a case-insensitive Hash class for HTTP header
|
128
|
+
#
|
129
|
+
class Table
|
130
|
+
include Enumerable
|
131
|
+
|
132
|
+
def initialize(hash={})
|
133
|
+
@hash = hash
|
134
|
+
update(hash)
|
135
|
+
end
|
136
|
+
|
137
|
+
def [](key)
|
138
|
+
# @hash[key.to_s.capitalize]
|
139
|
+
@hash[key.to_s]
|
140
|
+
end
|
141
|
+
|
142
|
+
def []=(key, value)
|
143
|
+
#@hash[key.to_s.capitalize] = value
|
144
|
+
@hash[key.to_s] = value
|
145
|
+
end
|
146
|
+
|
147
|
+
def update(hash)
|
148
|
+
hash.each {|k,v| self[k] = v}
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
def each
|
153
|
+
#@hash.each {|k,v| yield k.capitalize, v }
|
154
|
+
@hash.each {|k,v| yield k, v }
|
155
|
+
end
|
156
|
+
|
157
|
+
def writeTo(port)
|
158
|
+
each { |k,v|
|
159
|
+
port << "#{k}: #{v}" << CRLF
|
160
|
+
}
|
161
|
+
end
|
162
|
+
end # class Table
|
163
|
+
|
@@ -0,0 +1,297 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
#
|
4
|
+
# Author:: wangkaihua.
|
5
|
+
# Date:: Wed Dec 16 22:21:34 CST 2009
|
6
|
+
|
7
|
+
##to-do-list:
|
8
|
+
##
|
9
|
+
##
|
10
|
+
|
11
|
+
require "socket"
|
12
|
+
require "thread"
|
13
|
+
require "#{File.dirname(__FILE__)}/http_pack_helper"
|
14
|
+
|
15
|
+
|
16
|
+
module HttpServerActionHelper
|
17
|
+
|
18
|
+
class GeneralServer
|
19
|
+
|
20
|
+
DEFAULT_HOST = "127.0.0.1"
|
21
|
+
|
22
|
+
def serve(io)
|
23
|
+
yield if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
@@services = {} # Hash of opened ports, i.e. services
|
27
|
+
@@servicesMutex = Mutex.new
|
28
|
+
|
29
|
+
def GeneralServer.stop(port, host = DEFAULT_HOST)
|
30
|
+
@@servicesMutex.synchronize {
|
31
|
+
@@services[host][port].stop
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def GeneralServer.in_service?(port, host = DEFAULT_HOST)
|
36
|
+
@@services.has_key?(host) and
|
37
|
+
@@services[host].has_key?(port)
|
38
|
+
end
|
39
|
+
|
40
|
+
def stop
|
41
|
+
@connectionsMutex.synchronize {
|
42
|
+
if @tcpServerThread
|
43
|
+
@tcpServerThread.raise "stop"
|
44
|
+
end
|
45
|
+
}
|
46
|
+
@tcpServerThread.join
|
47
|
+
end
|
48
|
+
|
49
|
+
def stopped?
|
50
|
+
@tcpServerThread == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def shutdown
|
54
|
+
@shutdown = true
|
55
|
+
end
|
56
|
+
|
57
|
+
def connections
|
58
|
+
@connections.size
|
59
|
+
end
|
60
|
+
|
61
|
+
def join
|
62
|
+
@tcpServerThread.join if @tcpServerThread
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :port, :host, :maxConnections
|
66
|
+
attr_accessor :stdlog, :audit, :debug
|
67
|
+
|
68
|
+
def connecting(client)
|
69
|
+
addr = client.peeraddr
|
70
|
+
log("#{self.class.to_s} #{@host}:#{@port} client:#{addr[1]} " +
|
71
|
+
"#{addr[2]}<#{addr[3]}> connect")
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
def disconnecting(clientPort)
|
76
|
+
log("#{self.class.to_s} #{@host}:#{@port} " +
|
77
|
+
"client:#{clientPort} disconnect")
|
78
|
+
end
|
79
|
+
|
80
|
+
protected :connecting, :disconnecting
|
81
|
+
|
82
|
+
def starting()
|
83
|
+
log("#{self.class.to_s} #{@host}:#{@port} start")
|
84
|
+
end
|
85
|
+
|
86
|
+
def stopping()
|
87
|
+
log("#{self.class.to_s} #{@host}:#{@port} stop")
|
88
|
+
end
|
89
|
+
|
90
|
+
protected :starting, :stopping
|
91
|
+
|
92
|
+
def error(detail)
|
93
|
+
log(detail.backtrace.join("\n"))
|
94
|
+
end
|
95
|
+
|
96
|
+
def log(msg)
|
97
|
+
if @stdlog
|
98
|
+
@stdlog.puts("[#{Time.new.ctime}] %s" % msg)
|
99
|
+
@stdlog.flush
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
protected :error, :log
|
104
|
+
|
105
|
+
|
106
|
+
def initialize(port, host = DEFAULT_HOST, maxConnections = 4,
|
107
|
+
stdlog = $stderr, audit = false, debug = false)
|
108
|
+
@tcpServerThread = nil
|
109
|
+
@port = port
|
110
|
+
@host = host
|
111
|
+
@maxConnections = maxConnections
|
112
|
+
@connections = []
|
113
|
+
@connectionsMutex = Mutex.new
|
114
|
+
@connectionsCV = ConditionVariable.new
|
115
|
+
@stdlog = stdlog
|
116
|
+
@audit = audit
|
117
|
+
@debug = debug
|
118
|
+
end
|
119
|
+
|
120
|
+
def start(maxConnections = -1, &blk)
|
121
|
+
raise "running" if !stopped?
|
122
|
+
@shutdown = false
|
123
|
+
@maxConnections = maxConnections if maxConnections > 0
|
124
|
+
@@servicesMutex.synchronize {
|
125
|
+
if GeneralServer.in_service?(@port,@host)
|
126
|
+
raise "Port already in use: #{host}:#{@port}!"
|
127
|
+
end
|
128
|
+
@tcpServer = TCPServer.new(@host,@port)
|
129
|
+
@port = @tcpServer.addr[1]
|
130
|
+
@@services[@host] = {} unless @@services.has_key?(@host)
|
131
|
+
@@services[@host][@port] = self;
|
132
|
+
}
|
133
|
+
@tcpServerThread = Thread.new {
|
134
|
+
begin
|
135
|
+
starting if @audit
|
136
|
+
while !@shutdown
|
137
|
+
@connectionsMutex.synchronize {
|
138
|
+
while @connections.size >= @maxConnections
|
139
|
+
@connectionsCV.wait(@connectionsMutex)
|
140
|
+
end
|
141
|
+
}
|
142
|
+
client = @tcpServer.accept
|
143
|
+
@connections << Thread.new(client) { |myClient|
|
144
|
+
begin
|
145
|
+
myPort = myClient.peeraddr[1]
|
146
|
+
serve(myClient, &blk) if !@audit or connecting(myClient)
|
147
|
+
rescue => detail
|
148
|
+
error(detail) if @debug
|
149
|
+
ensure
|
150
|
+
begin
|
151
|
+
myClient.close
|
152
|
+
rescue
|
153
|
+
end
|
154
|
+
@connectionsMutex.synchronize {
|
155
|
+
@connections.delete(Thread.current)
|
156
|
+
@connectionsCV.signal
|
157
|
+
}
|
158
|
+
disconnecting(myPort) if @audit
|
159
|
+
end
|
160
|
+
}
|
161
|
+
end
|
162
|
+
rescue => detail
|
163
|
+
error(detail) if @debug
|
164
|
+
ensure
|
165
|
+
begin
|
166
|
+
@tcpServer.close
|
167
|
+
rescue
|
168
|
+
end
|
169
|
+
if @shutdown
|
170
|
+
@connectionsMutex.synchronize {
|
171
|
+
while @connections.size > 0
|
172
|
+
@connectionsCV.wait(@connectionsMutex)
|
173
|
+
end
|
174
|
+
}
|
175
|
+
else
|
176
|
+
@connections.each { |c| c.raise "stop" }
|
177
|
+
end
|
178
|
+
@tcpServerThread = nil
|
179
|
+
@@servicesMutex.synchronize {
|
180
|
+
@@services[@host].delete(@port)
|
181
|
+
}
|
182
|
+
stopping if @audit
|
183
|
+
end
|
184
|
+
}
|
185
|
+
self
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
class HttpServer < GeneralServer
|
191
|
+
def initialize(port, host = DEFAULT_HOST, maxConnections = 4,
|
192
|
+
stdlog = $stdout, audit = false, debug = false)
|
193
|
+
super(port, host, maxConnections, stdlog, audit, debug)
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
# Main Serve Loop -----------------------------------------
|
199
|
+
|
200
|
+
def serve(io)
|
201
|
+
# # perform IP authentification
|
202
|
+
# unless @handler.ip_auth_handler(io)
|
203
|
+
# io << http_resp(403, "Forbidden")
|
204
|
+
# return
|
205
|
+
# end
|
206
|
+
#
|
207
|
+
# # parse first line
|
208
|
+
# if io.gets =~ /^(\S+)\s+(\S+)\s+(\S+)/
|
209
|
+
# request = Request.new(io, $1, $2, $3)
|
210
|
+
# else
|
211
|
+
# io << http_resp(400, "Bad Request")
|
212
|
+
# return
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# # parse HTTP headers
|
216
|
+
# while (line=io.gets) !~ /^(\n|\r)/
|
217
|
+
# if line =~ /^([\w-]+):\s*(.*)$/
|
218
|
+
# request.header[$1] = $2.strip
|
219
|
+
# end
|
220
|
+
# end
|
221
|
+
request = HttpRequest.new(io)
|
222
|
+
response = HttpResponse.new
|
223
|
+
|
224
|
+
# execute request handler
|
225
|
+
yield(request, response)
|
226
|
+
|
227
|
+
# write response back to the client
|
228
|
+
io << response.to_http_pack
|
229
|
+
|
230
|
+
rescue Exception => e
|
231
|
+
# io << http_resp(500, "Internal Server Error")
|
232
|
+
raise "[ERROR] Exception:#{e.to_s}"
|
233
|
+
end
|
234
|
+
|
235
|
+
end # class HttpServer
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
if __FILE__ == $0
|
241
|
+
require 'wise_test'
|
242
|
+
class MyTest <WiseTest
|
243
|
+
def test_httpserver_get
|
244
|
+
server=HttpServer.new(8787)
|
245
|
+
server.start do |request, response|
|
246
|
+
#process request
|
247
|
+
puts "[SERVER][get] request from client:"
|
248
|
+
p request.header
|
249
|
+
p request.body
|
250
|
+
|
251
|
+
#customize your own response
|
252
|
+
puts "[SERVER][get] response to client:"
|
253
|
+
#response.status=403
|
254
|
+
response.header["Content-Type"]= "application/xhtml+xml;charset=gbk"
|
255
|
+
response.body="hello world!<-------path:/-------->哈喽我热烈的" if request.path=='/'
|
256
|
+
response.body="hello world!<-------path:/test/-------->哈喽我热烈的" if request.path.include? '/test/'
|
257
|
+
p response
|
258
|
+
end
|
259
|
+
|
260
|
+
get "http://127.0.0.1:8787/"
|
261
|
+
puts "[CLIENT] [1st] received from server:"
|
262
|
+
p @response.body
|
263
|
+
p @response.header.to_hash
|
264
|
+
|
265
|
+
get "http://127.0.0.1:8787/test/b/"
|
266
|
+
puts "[CLIENT] [2nd] received from server:"
|
267
|
+
p @response.body
|
268
|
+
p @response.header.to_hash
|
269
|
+
|
270
|
+
server.stop
|
271
|
+
#HttpServer.stop(8787)
|
272
|
+
end
|
273
|
+
def test_httpserver_post
|
274
|
+
server=HttpServer.new(8787)
|
275
|
+
server.start do |request, response|
|
276
|
+
puts "[SERVER][post] request from client:"
|
277
|
+
p request.header
|
278
|
+
p request.content
|
279
|
+
|
280
|
+
puts "[SERVER][post] response to client:"
|
281
|
+
response.header["Content-Type"]= "application/xhtml+xml;charset=utf-8"
|
282
|
+
response.body="hello world!<-------path:/-------->哈喽我热烈的" if request.path=='/'
|
283
|
+
p response
|
284
|
+
end
|
285
|
+
|
286
|
+
`echo "this is a file" >/tmp/test`
|
287
|
+
post "http://127.0.0.1:8787/", {}, {}, {"testfile"=>"/tmp/test"}
|
288
|
+
puts "[CLIENT][post] received from server:"
|
289
|
+
p @response.body
|
290
|
+
p @response.header.to_hash
|
291
|
+
|
292
|
+
server.stop
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
|