webricknio 0.6.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.
@@ -0,0 +1,157 @@
1
+ #--
2
+ # accesslog.rb -- Access log handling utilities
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2002 keita yamaguchi
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers
7
+ # Copyright (c) 2012 Pradeep Singh
8
+ #
9
+ # $IPR: accesslog.rb,v 1.1 2002/10/01 17:16:32 gotoyuzo Exp $
10
+
11
+ module WEBrickNIO
12
+
13
+ ##
14
+ # AccessLog provides logging to various files in various formats.
15
+ #
16
+ # Multiple logs may be written to at the same time:
17
+ #
18
+ # access_log = [
19
+ # [$stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT],
20
+ # [$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT],
21
+ # ]
22
+ #
23
+ # server = WEBrick::HTTPServer.new :AccessLog => access_log
24
+ #
25
+ # Custom log formats may be defined. WEBrick::AccessLog provides a subset
26
+ # of the formatting from Apache's mod_log_config
27
+ # http://httpd.apache.org/docs/mod/mod_log_config.html#formats. See
28
+ # AccessLog::setup_params for a list of supported options
29
+ #
30
+ # 99% copy of WEBrick::AccessLog to avoid polluting its namespace
31
+ # 1% change is in method <code>setup_params</code>
32
+
33
+ module AccessLog
34
+
35
+ ##
36
+ # Raised if a parameter such as %e, %i, %o or %n is used without fetching
37
+ # a specific field.
38
+
39
+ class AccessLogError < StandardError; end
40
+
41
+ ##
42
+ # The Common Log Format's time format
43
+
44
+ CLF_TIME_FORMAT = "[%d/%b/%Y:%H:%M:%S %Z]"
45
+
46
+ ##
47
+ # Common Log Format
48
+
49
+ COMMON_LOG_FORMAT = "%h %l %u %t \"%r\" %s %b"
50
+
51
+ ##
52
+ # Short alias for Common Log Format
53
+
54
+ CLF = COMMON_LOG_FORMAT
55
+
56
+ ##
57
+ # Referer Log Format
58
+
59
+ REFERER_LOG_FORMAT = "%{Referer}i -> %U"
60
+
61
+ ##
62
+ # User-Agent Log Format
63
+
64
+ AGENT_LOG_FORMAT = "%{User-Agent}i"
65
+
66
+ ##
67
+ # Combined Log Format
68
+
69
+ COMBINED_LOG_FORMAT = "#{CLF} \"%{Referer}i\" \"%{User-agent}i\""
70
+
71
+ module_function
72
+
73
+ # This format specification is a subset of mod_log_config of Apache:
74
+ #
75
+ # %a:: Remote IP address
76
+ # %b:: Total response size
77
+ # %e{variable}:: Given variable in ENV
78
+ # %f:: Response filename
79
+ # %h:: Remote host name
80
+ # %{header}i:: Given request header
81
+ # %l:: Remote logname, always "-"
82
+ # %m:: Request method
83
+ # %{attr}n:: Given request attribute from <tt>req.attributes</tt>
84
+ # %{header}o:: Given response header
85
+ # %p:: Server's request port
86
+ # %{format}p:: The canonical port of the server serving the request or the
87
+ # actual port or the client's actual port. Valid formats are
88
+ # canonical, local or remote.
89
+ # %q:: Request query string
90
+ # %r:: First line of the request
91
+ # %s:: Request status
92
+ # %t:: Time the request was recieved
93
+ # %T:: Time taken to process the request
94
+ # %u:: Remote user from auth
95
+ # %U:: Unparsed URI
96
+ # %%:: Literal %
97
+
98
+ def setup_params(config, req, res)
99
+ params = Hash.new("")
100
+ #params["a"] = req.peeraddr[3]
101
+ params["a"] = req.peeraddr.get_address.get_host_address
102
+ params["b"] = res.sent_size
103
+ params["e"] = ENV
104
+ params["f"] = res.filename || ""
105
+ #params["h"] = req.peeraddr[2]
106
+ params["h"] = req.peeraddr.get_host_name
107
+ params["i"] = req
108
+ params["l"] = "-"
109
+ params["m"] = req.request_method
110
+ params["n"] = req.attributes
111
+ params["o"] = res
112
+ params["p"] = req.port
113
+ params["q"] = req.query_string
114
+ params["r"] = req.request_line.sub(/\x0d?\x0a\z/o, '')
115
+ params["s"] = res.status # won't support "%>s"
116
+ params["t"] = req.request_time
117
+ params["T"] = Time.now - req.request_time
118
+ params["u"] = req.user || "-"
119
+ params["U"] = req.unparsed_uri
120
+ params["v"] = config[:ServerName]
121
+ params
122
+ end
123
+
124
+ def format(format_string, params)
125
+ format_string.gsub(/\%(?:\{(.*?)\})?>?([a-zA-Z%])/){
126
+ param, spec = $1, $2
127
+ case spec[0]
128
+ when ?e, ?i, ?n, ?o
129
+ raise AccessLogError,
130
+ "parameter is required for \"#{spec}\"" unless param
131
+ (param = params[spec][param]) ? escape(param) : "-"
132
+ when ?t
133
+ params[spec].strftime(param || CLF_TIME_FORMAT)
134
+ when ?p
135
+ case param
136
+ when 'remote'
137
+ escape(params["i"].peeraddr[1].to_s)
138
+ else
139
+ escape(params["p"].to_s)
140
+ end
141
+ when ?%
142
+ "%"
143
+ else
144
+ escape(params[spec].to_s)
145
+ end
146
+ }
147
+ end
148
+
149
+ def escape(data)
150
+ if data.tainted?
151
+ data.gsub(/[[:cntrl:]\\]+/) {$&.dump[1...-1]}.untaint
152
+ else
153
+ data
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,271 @@
1
+ #--
2
+ # block.rb
3
+ #
4
+ # Author: Pradeep Singh
5
+ # Copyright (c) 2012 Pradeep Singh
6
+ # All rights reserved.
7
+
8
+ require 'java'
9
+
10
+ require 'yaml'
11
+
12
+ module WEBrickNIO
13
+
14
+ class BaseBlock
15
+ def initialize(options = {})
16
+ @logger = options["logger"] || FakeLogger.new
17
+ end
18
+ def valid?(ip)
19
+ raise "valid? Not implemented"
20
+ end
21
+ def add_ip(ip)
22
+ raise "add_ip Not implemented"
23
+ end
24
+ def block_ip?(ip)
25
+ raise "block_ip? Not implemented"
26
+ end
27
+ def self.inherited(subclass)
28
+ subclass.instance_eval {
29
+ alias old_new new
30
+ def new
31
+ alias_method :matches?, :block_ip?
32
+ old_new
33
+ end
34
+ }
35
+ end
36
+ end
37
+
38
+ #
39
+ # Wrapper that chains other blockers
40
+ #
41
+
42
+ class ChainedBlock < BaseBlock
43
+
44
+ def initialize(options = {})
45
+ begin
46
+ load
47
+ rescue Exception => ex
48
+ puts ex
49
+ create_default_chain
50
+ end
51
+
52
+ super
53
+
54
+ # at_exit do
55
+ # file = File.new(File.expand_path('block.yaml', File.dirname(__FILE__)), "w")
56
+ # dump = YAML::dump(@chain)
57
+ # file.write(dump)
58
+ # file.close
59
+ # end
60
+ end
61
+
62
+ def load
63
+ file = File.new(File.expand_path('block.yaml', File.dirname(__FILE__)), "r")
64
+ @chain = YAML::load(file)
65
+ ensure_default_chain @chain
66
+ puts @chain
67
+ end
68
+
69
+ def reload
70
+ load
71
+ end
72
+
73
+ def add_ip(ip)
74
+ @chain.each do |blocker|
75
+ if blocker.valid? ip
76
+ blocker.add_ip ip
77
+ return true
78
+ end
79
+ end
80
+ return false
81
+ end
82
+
83
+ def block_ip?(ip)
84
+ @chain.each do |blocker|
85
+ if blocker.block_ip?(ip)
86
+ return true
87
+ end
88
+ end
89
+ return false
90
+ end
91
+
92
+ private
93
+
94
+ def create_default_chain
95
+ @chain = []
96
+ add_chain_elements @chain
97
+ end
98
+
99
+ def add_chain_elements(arr)
100
+ arr << PrefixBlock.new
101
+ arr << ListBlock.new
102
+ arr
103
+ end
104
+
105
+ def ensure_default_chain(chain)
106
+ if chain.nil? || !chain.is_a?(Array)
107
+ create_default_chain
108
+ elsif chain.length == 0
109
+ add_chain_elements chain
110
+ elsif chain.length == 1
111
+ if chain[0].class.name == "WEBrickNIO::PrefixBlock"
112
+ chain << ListBlock.new
113
+ elsif chain[0].class.name == "WEBrickNIO::ListBlock"
114
+ chain << PrefixBlock.new
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+
122
+ #
123
+ # Blocks IPs with given prefix
124
+ #
125
+
126
+ class PrefixBlock < BaseBlock
127
+
128
+ def initialize(options = {})
129
+ @block_list = options["block_list"] || []
130
+ super
131
+ end
132
+
133
+ def self.from_array(arr)
134
+ blocker = self.new
135
+ block_list = []
136
+ arr.each do |item|
137
+ blocker.add_ip item.to_s
138
+ end unless arr.nil?
139
+ blocker
140
+ end
141
+
142
+ def block_ip?(ip)
143
+ @block_list.each do |item|
144
+ if ip.start_with? item
145
+ @logger.info "ip matches: PrefixBlock - #{ip}"
146
+ return true
147
+ end
148
+ end
149
+ return false
150
+ end
151
+
152
+ def valid?(ip)
153
+ ip.split(".").size <= 3
154
+ end
155
+
156
+ def add_ip(ip)
157
+ return false if ip.nil? || ip.strip.length == 0
158
+ if valid?(ip) && !@block_list.include?(ip)
159
+ @block_list << ip
160
+ true
161
+ else
162
+ false
163
+ end
164
+ end
165
+
166
+ def to_yaml( opts = {} )
167
+ YAML.quick_emit( nil, opts ) { |out|
168
+ out.map("!IPBlockerPrefixBlock,1234/PrefixBlock" ) { |map|
169
+ map.add("block_list", @block_list)
170
+ }
171
+ }
172
+ end
173
+
174
+ def to_s
175
+ "PrefixBlock<#{object_id}>:#{@block_list}"
176
+ end
177
+
178
+ end
179
+
180
+
181
+ #
182
+ # Blocks IPs that are exact match
183
+ #
184
+
185
+ class ListBlock < BaseBlock
186
+
187
+ def initialize(options = {})
188
+ @block_list = options["block_list"] || java.util.concurrent.ConcurrentSkipListSet.new
189
+ super
190
+ end
191
+
192
+ def self.from_array(arr)
193
+ blocker = self.new
194
+ arr.each do |item|
195
+ blocker.add_ip item.to_s
196
+ end unless arr.nil?
197
+ blocker
198
+ end
199
+
200
+ def block_ip?(ip)
201
+ if @block_list.include? ip
202
+ @logger.info "ip matches: ListBlock - #{ip}"
203
+ true
204
+ else
205
+ false
206
+ end
207
+ end
208
+
209
+ def valid?(ip)
210
+ ip.split(".").size > 3
211
+ end
212
+
213
+ def add_ip(ip)
214
+ return false if ip.nil? || ip.strip.length == 0
215
+ if valid? ip
216
+ @block_list.add ip
217
+ true
218
+ else
219
+ false
220
+ end
221
+ end
222
+
223
+ def to_yaml( opts = {} )
224
+ YAML.quick_emit( nil, opts ) { |out|
225
+ out.map("!IPBlockerListBlock,1234/ListBlock" ) { |map|
226
+ map.add("block_list", @block_list.to_a)
227
+ }
228
+ }
229
+ end
230
+
231
+ def to_s
232
+ "ListBlock<#{object_id}>:#{@block_list.to_a}"
233
+ end
234
+
235
+ end
236
+
237
+
238
+
239
+ YAML::add_domain_type("IPBlockerListBlock,1234", "ListBlock") do |type, val|
240
+ ListBlock.from_array(val["block_list"])
241
+ end
242
+
243
+ YAML::add_domain_type("IPBlockerPrefixBlock,1234", "PrefixBlock") do |type, val|
244
+ PrefixBlock.from_array(val["block_list"])
245
+ end
246
+
247
+
248
+
249
+ class FakeLogger
250
+ def method_missing(method, *args, &block)
251
+ puts args
252
+ end
253
+ end
254
+
255
+ end
256
+
257
+ #chain = WEBrickNIO::ChainedBlock.new
258
+
259
+ #ip ="180.76"
260
+ #chain.add(ip)
261
+
262
+ #ip ="92.240.68.152"
263
+ #chain.add(ip)
264
+ #ip ="180.76"
265
+ #chain.block_ip? ip
266
+
267
+ #ip ="92.240.68.152"
268
+ #chain.matches? ip
269
+
270
+
271
+
@@ -0,0 +1,7 @@
1
+ ---
2
+ - !IPBlockerPrefixBlock,1234/PrefixBlock
3
+ block_list:
4
+ - '999.0'
5
+ - !IPBlockerListBlock,1234/ListBlock
6
+ block_list:
7
+ - 999.0.0.1
@@ -0,0 +1,125 @@
1
+ #
2
+ # config.rb -- Default configurations.
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
6
+ # Copyright (c) 2003 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: config.rb,v 1.52 2003/07/22 19:20:42 gotoyuzo Exp $
10
+
11
+ require 'webricknio/version'
12
+ require 'webrick/httpversion'
13
+ require 'webrick/httputils'
14
+ require 'webrick/utils'
15
+ require 'webrick/log'
16
+ require 'webricknio/log'
17
+
18
+ module WEBrickNIO
19
+ module Config
20
+ LIBDIR = File::dirname(__FILE__)
21
+
22
+ # for GenericServer
23
+ General = {
24
+ :ServerName => ::WEBrick::Utils::getservername,
25
+ :BindAddress => nil, # "0.0.0.0" or "::" or nil
26
+ :Port => nil, # users MUST specify this!!
27
+ :ServerType => nil, # default: WEBrick::SimpleServer
28
+ :Logger => nil, # default: WEBrick::Log.new
29
+ #:ServerSoftware => "WEBrickNIO/#{WEBrickNIO::VERSION} " +
30
+ # "(Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})",
31
+ :ServerSoftware => "pks/#{WEBrickNIO::VERSION} ",
32
+ :TempDir => ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp',
33
+ :DoNotListen => false,
34
+ :StartCallback => nil,
35
+ :StopCallback => nil,
36
+ :AcceptCallback => nil,
37
+ :DoNotReverseLookup => nil,
38
+ :ShutdownSocketWithoutClose => false,
39
+ }
40
+
41
+ # for HTTPServer, HTTPRequest, HTTPResponse ...
42
+ HTTP = General.dup.update(
43
+ :Port => 80,
44
+ :RequestTimeout => 5,
45
+ :NumThreads => 20,
46
+ :HTTPVersion => ::WEBrick::HTTPVersion.new("1.1"),
47
+ :AccessLog => nil,
48
+ :LogLocation => nil, #"log/webrick.log"
49
+ :LogLevel => ::WEBrick::Log::DEBUG,
50
+ :MimeTypes => ::WEBrick::HTTPUtils::DefaultMimeTypes,
51
+ :DirectoryIndex => ["index.html","index.htm","index.cgi","index.rhtml"],
52
+ :DocumentRoot => nil,
53
+ :DocumentRootOptions => { :FancyIndexing => true },
54
+ :RequestCallback => nil,
55
+ :ServerAlias => nil,
56
+ :InputBufferSize => 65536, # input buffer size in reading request body
57
+ :OutputBufferSize => 65536, # output buffer size in sending File or IO
58
+
59
+ # for HTTPProxyServer
60
+ :ProxyAuthProc => nil,
61
+ :ProxyContentHandler => nil,
62
+ :ProxyVia => true,
63
+ :ProxyTimeout => true,
64
+ :ProxyURI => nil,
65
+
66
+ :CGIInterpreter => nil,
67
+ :CGIPathEnv => nil,
68
+
69
+ # workaround: if Request-URIs contain 8bit chars,
70
+ # they should be escaped before calling of URI::parse().
71
+ :Escape8bitURI => false
72
+ )
73
+
74
+ FileHandler = {
75
+ :NondisclosureName => [".ht*", "*~"],
76
+ :FancyIndexing => false,
77
+ :HandlerTable => {},
78
+ :HandlerCallback => nil,
79
+ :DirectoryCallback => nil,
80
+ :FileCallback => nil,
81
+ :UserDir => nil, # e.g. "public_html"
82
+ :AcceptableLanguages => [] # ["en", "ja", ... ]
83
+ }
84
+
85
+ BasicAuth = {
86
+ :AutoReloadUserDB => true,
87
+ }
88
+
89
+ ##
90
+ # Default configuration for WEBrick::HTTPAuth::DigestAuth.
91
+ #
92
+ # :Algorithm:: MD5, MD5-sess (default), SHA1, SHA1-sess
93
+ # :Domain:: An Array of URIs that define the protected space
94
+ # :Qop:: 'auth' for authentication, 'auth-int' for integrity protection or
95
+ # both
96
+ # :UseOpaque:: Should the server send opaque values to the client? This
97
+ # helps prevent replay attacks.
98
+ # :CheckNc:: Should the server check the nonce count? This helps the
99
+ # server detect replay attacks.
100
+ # :UseAuthenticationInfoHeader:: Should the server send an
101
+ # AuthenticationInfo header?
102
+ # :AutoReloadUserDB:: Reload the user database provided by :UserDB
103
+ # automatically?
104
+ # :NonceExpirePeriod:: How long should we store used nonces? Default is
105
+ # 30 minutes.
106
+ # :NonceExpireDelta:: How long is a nonce valid? Default is 1 minute
107
+ # :InternetExplorerHack:: Hack which allows Internet Explorer to work.
108
+ # :OperaHack:: Hack which allows Opera to work.
109
+
110
+ DigestAuth = {
111
+ :Algorithm => 'MD5-sess', # or 'MD5'
112
+ :Domain => nil, # an array includes domain names.
113
+ :Qop => [ 'auth' ], # 'auth' or 'auth-int' or both.
114
+ :UseOpaque => true,
115
+ :UseNextNonce => false,
116
+ :CheckNc => false,
117
+ :UseAuthenticationInfoHeader => true,
118
+ :AutoReloadUserDB => true,
119
+ :NonceExpirePeriod => 30*60,
120
+ :NonceExpireDelta => 60,
121
+ :InternetExplorerHack => true,
122
+ :OperaHack => true,
123
+ }
124
+ end
125
+ end