super-test 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|