rubysl-webrick 1.0.0
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/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/rubysl/webrick.rb +2 -0
- data/lib/rubysl/webrick/version.rb +5 -0
- data/lib/rubysl/webrick/webrick.rb +29 -0
- data/lib/webrick.rb +1 -0
- data/lib/webrick/accesslog.rb +67 -0
- data/lib/webrick/cgi.rb +257 -0
- data/lib/webrick/compat.rb +15 -0
- data/lib/webrick/config.rb +97 -0
- data/lib/webrick/cookie.rb +110 -0
- data/lib/webrick/htmlutils.rb +25 -0
- data/lib/webrick/httpauth.rb +45 -0
- data/lib/webrick/httpauth/authenticator.rb +79 -0
- data/lib/webrick/httpauth/basicauth.rb +65 -0
- data/lib/webrick/httpauth/digestauth.rb +343 -0
- data/lib/webrick/httpauth/htdigest.rb +91 -0
- data/lib/webrick/httpauth/htgroup.rb +61 -0
- data/lib/webrick/httpauth/htpasswd.rb +83 -0
- data/lib/webrick/httpauth/userdb.rb +29 -0
- data/lib/webrick/httpproxy.rb +254 -0
- data/lib/webrick/httprequest.rb +365 -0
- data/lib/webrick/httpresponse.rb +327 -0
- data/lib/webrick/https.rb +63 -0
- data/lib/webrick/httpserver.rb +210 -0
- data/lib/webrick/httpservlet.rb +22 -0
- data/lib/webrick/httpservlet/abstract.rb +71 -0
- data/lib/webrick/httpservlet/cgi_runner.rb +45 -0
- data/lib/webrick/httpservlet/cgihandler.rb +104 -0
- data/lib/webrick/httpservlet/erbhandler.rb +54 -0
- data/lib/webrick/httpservlet/filehandler.rb +398 -0
- data/lib/webrick/httpservlet/prochandler.rb +33 -0
- data/lib/webrick/httpstatus.rb +126 -0
- data/lib/webrick/httputils.rb +391 -0
- data/lib/webrick/httpversion.rb +49 -0
- data/lib/webrick/log.rb +88 -0
- data/lib/webrick/server.rb +200 -0
- data/lib/webrick/ssl.rb +126 -0
- data/lib/webrick/utils.rb +100 -0
- data/lib/webrick/version.rb +13 -0
- data/rubysl-webrick.gemspec +23 -0
- metadata +145 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# httpauth/htdigest.rb -- Apache compatible htdigest file
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
|
6
|
+
# reserved.
|
7
|
+
#
|
8
|
+
# $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $
|
9
|
+
|
10
|
+
require 'webrick/httpauth/userdb'
|
11
|
+
require 'webrick/httpauth/digestauth'
|
12
|
+
require 'tempfile'
|
13
|
+
|
14
|
+
module WEBrick
|
15
|
+
module HTTPAuth
|
16
|
+
class Htdigest
|
17
|
+
include UserDB
|
18
|
+
|
19
|
+
def initialize(path)
|
20
|
+
@path = path
|
21
|
+
@mtime = Time.at(0)
|
22
|
+
@digest = Hash.new
|
23
|
+
@mutex = Mutex::new
|
24
|
+
@auth_type = DigestAuth
|
25
|
+
open(@path,"a").close unless File::exist?(@path)
|
26
|
+
reload
|
27
|
+
end
|
28
|
+
|
29
|
+
def reload
|
30
|
+
mtime = File::mtime(@path)
|
31
|
+
if mtime > @mtime
|
32
|
+
@digest.clear
|
33
|
+
open(@path){|io|
|
34
|
+
while line = io.gets
|
35
|
+
line.chomp!
|
36
|
+
user, realm, pass = line.split(/:/, 3)
|
37
|
+
unless @digest[realm]
|
38
|
+
@digest[realm] = Hash.new
|
39
|
+
end
|
40
|
+
@digest[realm][user] = pass
|
41
|
+
end
|
42
|
+
}
|
43
|
+
@mtime = mtime
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def flush(output=nil)
|
48
|
+
output ||= @path
|
49
|
+
tmp = Tempfile.new("htpasswd", File::dirname(output))
|
50
|
+
begin
|
51
|
+
each{|item| tmp.puts(item.join(":")) }
|
52
|
+
tmp.close
|
53
|
+
File::rename(tmp.path, output)
|
54
|
+
rescue
|
55
|
+
tmp.close(true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_passwd(realm, user, reload_db)
|
60
|
+
reload() if reload_db
|
61
|
+
if hash = @digest[realm]
|
62
|
+
hash[user]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_passwd(realm, user, pass)
|
67
|
+
@mutex.synchronize{
|
68
|
+
unless @digest[realm]
|
69
|
+
@digest[realm] = Hash.new
|
70
|
+
end
|
71
|
+
@digest[realm][user] = make_passwd(realm, user, pass)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete_passwd(realm, user)
|
76
|
+
if hash = @digest[realm]
|
77
|
+
hash.delete(user)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def each
|
82
|
+
@digest.keys.sort.each{|realm|
|
83
|
+
hash = @digest[realm]
|
84
|
+
hash.keys.sort.each{|user|
|
85
|
+
yield([user, realm, hash[user]])
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#
|
2
|
+
# httpauth/htgroup.rb -- Apache compatible htgroup file
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
|
6
|
+
# reserved.
|
7
|
+
#
|
8
|
+
# $IPR: htgroup.rb,v 1.1 2003/02/16 22:22:56 gotoyuzo Exp $
|
9
|
+
|
10
|
+
require 'tempfile'
|
11
|
+
|
12
|
+
module WEBrick
|
13
|
+
module HTTPAuth
|
14
|
+
class Htgroup
|
15
|
+
def initialize(path)
|
16
|
+
@path = path
|
17
|
+
@mtime = Time.at(0)
|
18
|
+
@group = Hash.new
|
19
|
+
open(@path,"a").close unless File::exist?(@path)
|
20
|
+
reload
|
21
|
+
end
|
22
|
+
|
23
|
+
def reload
|
24
|
+
if (mtime = File::mtime(@path)) > @mtime
|
25
|
+
@group.clear
|
26
|
+
open(@path){|io|
|
27
|
+
while line = io.gets
|
28
|
+
line.chomp!
|
29
|
+
group, members = line.split(/:\s*/)
|
30
|
+
@group[group] = members.split(/\s+/)
|
31
|
+
end
|
32
|
+
}
|
33
|
+
@mtime = mtime
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def flush(output=nil)
|
38
|
+
output ||= @path
|
39
|
+
tmp = Tempfile.new("htgroup", File::dirname(output))
|
40
|
+
begin
|
41
|
+
@group.keys.sort.each{|group|
|
42
|
+
tmp.puts(format("%s: %s", group, self.members(group).join(" ")))
|
43
|
+
}
|
44
|
+
tmp.close
|
45
|
+
File::rename(tmp.path, output)
|
46
|
+
rescue
|
47
|
+
tmp.close(true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def members(group)
|
52
|
+
reload
|
53
|
+
@group[group] || []
|
54
|
+
end
|
55
|
+
|
56
|
+
def add(group, members)
|
57
|
+
@group[group] = members(group) | members
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#
|
2
|
+
# httpauth/htpasswd -- Apache compatible htpasswd file
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
|
6
|
+
# reserved.
|
7
|
+
#
|
8
|
+
# $IPR: htpasswd.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $
|
9
|
+
|
10
|
+
require 'webrick/httpauth/userdb'
|
11
|
+
require 'webrick/httpauth/basicauth'
|
12
|
+
require 'tempfile'
|
13
|
+
|
14
|
+
module WEBrick
|
15
|
+
module HTTPAuth
|
16
|
+
class Htpasswd
|
17
|
+
include UserDB
|
18
|
+
|
19
|
+
def initialize(path)
|
20
|
+
@path = path
|
21
|
+
@mtime = Time.at(0)
|
22
|
+
@passwd = Hash.new
|
23
|
+
@auth_type = BasicAuth
|
24
|
+
open(@path,"a").close unless File::exist?(@path)
|
25
|
+
reload
|
26
|
+
end
|
27
|
+
|
28
|
+
def reload
|
29
|
+
mtime = File::mtime(@path)
|
30
|
+
if mtime > @mtime
|
31
|
+
@passwd.clear
|
32
|
+
open(@path){|io|
|
33
|
+
while line = io.gets
|
34
|
+
line.chomp!
|
35
|
+
case line
|
36
|
+
when %r!\A[^:]+:[a-zA-Z0-9./]{13}\z!
|
37
|
+
user, pass = line.split(":")
|
38
|
+
when /:\$/, /:\{SHA\}/
|
39
|
+
raise NotImplementedError,
|
40
|
+
'MD5, SHA1 .htpasswd file not supported'
|
41
|
+
else
|
42
|
+
raise StandardError, 'bad .htpasswd file'
|
43
|
+
end
|
44
|
+
@passwd[user] = pass
|
45
|
+
end
|
46
|
+
}
|
47
|
+
@mtime = mtime
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def flush(output=nil)
|
52
|
+
output ||= @path
|
53
|
+
tmp = Tempfile.new("htpasswd", File::dirname(output))
|
54
|
+
begin
|
55
|
+
each{|item| tmp.puts(item.join(":")) }
|
56
|
+
tmp.close
|
57
|
+
File::rename(tmp.path, output)
|
58
|
+
rescue
|
59
|
+
tmp.close(true)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_passwd(realm, user, reload_db)
|
64
|
+
reload() if reload_db
|
65
|
+
@passwd[user]
|
66
|
+
end
|
67
|
+
|
68
|
+
def set_passwd(realm, user, pass)
|
69
|
+
@passwd[user] = make_passwd(realm, user, pass)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_passwd(realm, user)
|
73
|
+
@passwd.delete(user)
|
74
|
+
end
|
75
|
+
|
76
|
+
def each
|
77
|
+
@passwd.keys.sort.each{|user|
|
78
|
+
yield([user, @passwd[user]])
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# httpauth/userdb.rb -- UserDB mix-in module.
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
|
6
|
+
# reserved.
|
7
|
+
#
|
8
|
+
# $IPR: userdb.rb,v 1.2 2003/02/20 07:15:48 gotoyuzo Exp $
|
9
|
+
|
10
|
+
module WEBrick
|
11
|
+
module HTTPAuth
|
12
|
+
module UserDB
|
13
|
+
attr_accessor :auth_type # BasicAuth or DigestAuth
|
14
|
+
|
15
|
+
def make_passwd(realm, user, pass)
|
16
|
+
@auth_type::make_passwd(realm, user, pass)
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_passwd(realm, user, pass)
|
20
|
+
self[user] = pass
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_passwd(realm, user, reload_db=false)
|
24
|
+
# reload_db is dummy
|
25
|
+
make_passwd(realm, user, self[user])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
#
|
2
|
+
# httpproxy.rb -- HTTPProxy Class
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2002 GOTO Kentaro
|
6
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
7
|
+
# reserved.
|
8
|
+
#
|
9
|
+
# $IPR: httpproxy.rb,v 1.18 2003/03/08 18:58:10 gotoyuzo Exp $
|
10
|
+
# $kNotwork: straw.rb,v 1.3 2002/02/12 15:13:07 gotoken Exp $
|
11
|
+
|
12
|
+
require "webrick/httpserver"
|
13
|
+
require "net/http"
|
14
|
+
|
15
|
+
Net::HTTP::version_1_2 if RUBY_VERSION < "1.7"
|
16
|
+
|
17
|
+
module WEBrick
|
18
|
+
NullReader = Object.new
|
19
|
+
class << NullReader
|
20
|
+
def read(*args)
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
alias gets read
|
24
|
+
end
|
25
|
+
|
26
|
+
class HTTPProxyServer < HTTPServer
|
27
|
+
def initialize(config)
|
28
|
+
super
|
29
|
+
c = @config
|
30
|
+
@via = "#{c[:HTTPVersion]} #{c[:ServerName]}:#{c[:Port]}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def service(req, res)
|
34
|
+
if req.request_method == "CONNECT"
|
35
|
+
proxy_connect(req, res)
|
36
|
+
elsif req.unparsed_uri =~ %r!^http://!
|
37
|
+
proxy_service(req, res)
|
38
|
+
else
|
39
|
+
super(req, res)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def proxy_auth(req, res)
|
44
|
+
if proc = @config[:ProxyAuthProc]
|
45
|
+
proc.call(req, res)
|
46
|
+
end
|
47
|
+
req.header.delete("proxy-authorization")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Some header fields should not be transferred.
|
51
|
+
HopByHop = %w( connection keep-alive proxy-authenticate upgrade
|
52
|
+
proxy-authorization te trailers transfer-encoding )
|
53
|
+
ShouldNotTransfer = %w( set-cookie proxy-connection )
|
54
|
+
def split_field(f) f ? f.split(/,\s+/).collect{|i| i.downcase } : [] end
|
55
|
+
|
56
|
+
def choose_header(src, dst)
|
57
|
+
connections = split_field(src['connection'])
|
58
|
+
src.each{|key, value|
|
59
|
+
key = key.downcase
|
60
|
+
if HopByHop.member?(key) || # RFC2616: 13.5.1
|
61
|
+
connections.member?(key) || # RFC2616: 14.10
|
62
|
+
ShouldNotTransfer.member?(key) # pragmatics
|
63
|
+
@logger.debug("choose_header: `#{key}: #{value}'")
|
64
|
+
next
|
65
|
+
end
|
66
|
+
dst[key] = value
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
# Net::HTTP is stupid about the multiple header fields.
|
71
|
+
# Here is workaround:
|
72
|
+
def set_cookie(src, dst)
|
73
|
+
if str = src['set-cookie']
|
74
|
+
cookies = []
|
75
|
+
str.split(/,\s*/).each{|token|
|
76
|
+
if /^[^=]+;/o =~ token
|
77
|
+
cookies[-1] << ", " << token
|
78
|
+
elsif /=/o =~ token
|
79
|
+
cookies << token
|
80
|
+
else
|
81
|
+
cookies[-1] << ", " << token
|
82
|
+
end
|
83
|
+
}
|
84
|
+
dst.cookies.replace(cookies)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_via(h)
|
89
|
+
if @config[:ProxyVia]
|
90
|
+
if h['via']
|
91
|
+
h['via'] << ", " << @via
|
92
|
+
else
|
93
|
+
h['via'] = @via
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def proxy_uri(req, res)
|
99
|
+
@config[:ProxyURI]
|
100
|
+
end
|
101
|
+
|
102
|
+
def proxy_service(req, res)
|
103
|
+
# Proxy Authentication
|
104
|
+
proxy_auth(req, res)
|
105
|
+
|
106
|
+
# Create Request-URI to send to the origin server
|
107
|
+
uri = req.request_uri
|
108
|
+
path = uri.path.dup
|
109
|
+
path << "?" << uri.query if uri.query
|
110
|
+
|
111
|
+
# Choose header fields to transfer
|
112
|
+
header = Hash.new
|
113
|
+
choose_header(req, header)
|
114
|
+
set_via(header)
|
115
|
+
|
116
|
+
# select upstream proxy server
|
117
|
+
if proxy = proxy_uri(req, res)
|
118
|
+
proxy_host = proxy.host
|
119
|
+
proxy_port = proxy.port
|
120
|
+
if proxy.userinfo
|
121
|
+
credentials = "Basic " + [proxy.userinfo].pack("m*")
|
122
|
+
credentials.chomp!
|
123
|
+
header['proxy-authorization'] = credentials
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
response = nil
|
128
|
+
begin
|
129
|
+
http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port)
|
130
|
+
http.start{
|
131
|
+
if @config[:ProxyTimeout]
|
132
|
+
################################## these issues are
|
133
|
+
http.open_timeout = 30 # secs # necessary (maybe bacause
|
134
|
+
http.read_timeout = 60 # secs # Ruby's bug, but why?)
|
135
|
+
##################################
|
136
|
+
end
|
137
|
+
case req.request_method
|
138
|
+
when "GET" then response = http.get(path, header)
|
139
|
+
when "POST" then response = http.post(path, req.body || "", header)
|
140
|
+
when "HEAD" then response = http.head(path, header)
|
141
|
+
else
|
142
|
+
raise HTTPStatus::MethodNotAllowed,
|
143
|
+
"unsupported method `#{req.request_method}'."
|
144
|
+
end
|
145
|
+
}
|
146
|
+
rescue => err
|
147
|
+
logger.debug("#{err.class}: #{err.message}")
|
148
|
+
raise HTTPStatus::ServiceUnavailable, err.message
|
149
|
+
end
|
150
|
+
|
151
|
+
# Persistent connction requirements are mysterious for me.
|
152
|
+
# So I will close the connection in every response.
|
153
|
+
res['proxy-connection'] = "close"
|
154
|
+
res['connection'] = "close"
|
155
|
+
|
156
|
+
# Convert Net::HTTP::HTTPResponse to WEBrick::HTTPProxy
|
157
|
+
res.status = response.code.to_i
|
158
|
+
choose_header(response, res)
|
159
|
+
set_cookie(response, res)
|
160
|
+
set_via(res)
|
161
|
+
res.body = response.body
|
162
|
+
|
163
|
+
# Process contents
|
164
|
+
if handler = @config[:ProxyContentHandler]
|
165
|
+
handler.call(req, res)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def proxy_connect(req, res)
|
170
|
+
# Proxy Authentication
|
171
|
+
proxy_auth(req, res)
|
172
|
+
|
173
|
+
ua = Thread.current[:WEBrickSocket] # User-Agent
|
174
|
+
raise HTTPStatus::InternalServerError,
|
175
|
+
"[BUG] cannot get socket" unless ua
|
176
|
+
|
177
|
+
host, port = req.unparsed_uri.split(":", 2)
|
178
|
+
# Proxy authentication for upstream proxy server
|
179
|
+
if proxy = proxy_uri(req, res)
|
180
|
+
proxy_request_line = "CONNECT #{host}:#{port} HTTP/1.0"
|
181
|
+
if proxy.userinfo
|
182
|
+
credentials = "Basic " + [proxy.userinfo].pack("m*")
|
183
|
+
credentials.chomp!
|
184
|
+
end
|
185
|
+
host, port = proxy.host, proxy.port
|
186
|
+
end
|
187
|
+
|
188
|
+
begin
|
189
|
+
@logger.debug("CONNECT: upstream proxy is `#{host}:#{port}'.")
|
190
|
+
os = TCPSocket.new(host, port) # origin server
|
191
|
+
|
192
|
+
if proxy
|
193
|
+
@logger.debug("CONNECT: sending a Request-Line")
|
194
|
+
os << proxy_request_line << CRLF
|
195
|
+
@logger.debug("CONNECT: > #{proxy_request_line}")
|
196
|
+
if credentials
|
197
|
+
@logger.debug("CONNECT: sending a credentials")
|
198
|
+
os << "Proxy-Authorization: " << credentials << CRLF
|
199
|
+
end
|
200
|
+
os << CRLF
|
201
|
+
proxy_status_line = os.gets(LF)
|
202
|
+
@logger.debug("CONNECT: read a Status-Line form the upstream server")
|
203
|
+
@logger.debug("CONNECT: < #{proxy_status_line}")
|
204
|
+
if %r{^HTTP/\d+\.\d+\s+200\s*} =~ proxy_status_line
|
205
|
+
while line = os.gets(LF)
|
206
|
+
break if /\A(#{CRLF}|#{LF})\z/om =~ line
|
207
|
+
end
|
208
|
+
else
|
209
|
+
raise HTTPStatus::BadGateway
|
210
|
+
end
|
211
|
+
end
|
212
|
+
@logger.debug("CONNECT #{host}:#{port}: succeeded")
|
213
|
+
res.status = HTTPStatus::RC_OK
|
214
|
+
rescue => ex
|
215
|
+
@logger.debug("CONNECT #{host}:#{port}: failed `#{ex.message}'")
|
216
|
+
res.set_error(ex)
|
217
|
+
raise HTTPStatus::EOFError
|
218
|
+
ensure
|
219
|
+
if handler = @config[:ProxyContentHandler]
|
220
|
+
handler.call(req, res)
|
221
|
+
end
|
222
|
+
res.send_response(ua)
|
223
|
+
access_log(@config, req, res)
|
224
|
+
|
225
|
+
# Should clear request-line not to send the sesponse twice.
|
226
|
+
# see: HTTPServer#run
|
227
|
+
req.parse(NullReader) rescue nil
|
228
|
+
end
|
229
|
+
|
230
|
+
begin
|
231
|
+
while fds = IO::select([ua, os])
|
232
|
+
if fds[0].member?(ua)
|
233
|
+
buf = ua.sysread(1024);
|
234
|
+
@logger.debug("CONNECT: #{buf.size} byte from User-Agent")
|
235
|
+
os.syswrite(buf)
|
236
|
+
elsif fds[0].member?(os)
|
237
|
+
buf = os.sysread(1024);
|
238
|
+
@logger.debug("CONNECT: #{buf.size} byte from #{host}:#{port}")
|
239
|
+
ua.syswrite(buf)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
rescue => ex
|
243
|
+
os.close
|
244
|
+
@logger.debug("CONNECT #{host}:#{port}: closed")
|
245
|
+
end
|
246
|
+
|
247
|
+
raise HTTPStatus::EOFError
|
248
|
+
end
|
249
|
+
|
250
|
+
def do_OPTIONS(req, res)
|
251
|
+
res['allow'] = "GET,HEAD,POST,OPTIONS,CONNECT"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|