nitro 0.13.0 → 0.14.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.
- data/CHANGELOG +91 -1632
- data/INSTALL +44 -0
- data/README +1 -1
- data/Rakefile +3 -3
- data/doc/CHANGELOG.2 +1688 -0
- data/doc/RELEASES +84 -1
- data/examples/blog/cache/entriesadmin +12 -0
- data/examples/blog/conf/apache.conf.new +53 -0
- data/examples/blog/conf/lhttpd.conf +23 -180
- data/examples/blog/log/apache.error_log +271 -0
- data/examples/blog/log/rewrite_log +161 -0
- data/examples/blog/public/fcgi.rb +2 -0
- data/examples/blog/run.rb +4 -3
- data/examples/blog/src/controller.rb +10 -4
- data/examples/blog/src/views/index.xhtml +3 -0
- data/examples/blog/src/xsl/base.xsl +7 -0
- data/examples/no_xsl_blog/conf/lhttpd.conf +24 -181
- data/examples/tiny/conf/lhttpd.conf +24 -181
- data/examples/tiny/log/apache.error_log +24 -0
- data/examples/tiny/public/index.xhtml +0 -6
- data/examples/tiny/public/upload.xhtml +12 -14
- data/examples/wee_style/run.rb +2 -0
- data/examples/why_wiki/run.rb +2 -0
- data/lib/nitro.rb +2 -2
- data/lib/nitro/adapters/cgi.rb +36 -109
- data/lib/nitro/adapters/webrick.rb +76 -62
- data/lib/nitro/caching.rb +29 -0
- data/lib/nitro/caching/actions.rb +67 -0
- data/lib/nitro/caching/fragments.rb +72 -0
- data/lib/nitro/caching/invalidation.rb +51 -0
- data/lib/nitro/caching/output.rb +72 -0
- data/lib/nitro/caching/stores.rb +84 -0
- data/lib/nitro/controller.rb +3 -1
- data/lib/nitro/dispatcher.rb +0 -1
- data/lib/nitro/filters.rb +112 -55
- data/lib/nitro/mail.rb +6 -3
- data/lib/nitro/render.rb +27 -4
- data/lib/nitro/request.rb +13 -1
- data/test/nitro/tc_controller.rb +6 -4
- data/test/nitro/tc_filters.rb +111 -0
- metadata +19 -29
- data/examples/why_wiki/wiki.yml +0 -1
- data/vendor/README +0 -11
- data/vendor/binding_of_caller.rb +0 -81
- data/vendor/blankslate.rb +0 -53
- data/vendor/breakpoint.rb +0 -523
- data/vendor/breakpoint_client.rb +0 -196
- data/vendor/extensions/_base.rb +0 -153
- data/vendor/extensions/_template.rb +0 -36
- data/vendor/extensions/all.rb +0 -21
- data/vendor/extensions/array.rb +0 -68
- data/vendor/extensions/binding.rb +0 -224
- data/vendor/extensions/class.rb +0 -50
- data/vendor/extensions/continuation.rb +0 -71
- data/vendor/extensions/enumerable.rb +0 -250
- data/vendor/extensions/hash.rb +0 -23
- data/vendor/extensions/io.rb +0 -58
- data/vendor/extensions/kernel.rb +0 -42
- data/vendor/extensions/module.rb +0 -114
- data/vendor/extensions/numeric.rb +0 -230
- data/vendor/extensions/object.rb +0 -164
- data/vendor/extensions/ostruct.rb +0 -41
- data/vendor/extensions/string.rb +0 -316
- data/vendor/extensions/symbol.rb +0 -28
@@ -3,44 +3,24 @@
|
|
3
3
|
# $Id$
|
4
4
|
|
5
5
|
require 'webrick'
|
6
|
+
require 'stringio'
|
6
7
|
|
7
8
|
require 'glue/flexob'
|
8
|
-
|
9
9
|
require 'nitro/context'
|
10
10
|
require 'nitro/dispatcher'
|
11
11
|
|
12
|
-
module WEBrick
|
13
|
-
|
14
|
-
class HTTPRequest
|
15
|
-
attr :socket
|
16
|
-
end
|
17
|
-
|
18
|
-
class HTTPResponse
|
19
|
-
def header=(header)
|
20
|
-
@header = header
|
21
|
-
end
|
22
|
-
|
23
|
-
def cookies=(cookies)
|
24
|
-
@cookies = cookies
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
12
|
module N
|
31
13
|
|
32
14
|
# Helper methods for the WebrickAdapter.
|
33
15
|
|
34
16
|
class Webrick
|
35
|
-
|
17
|
+
|
36
18
|
class << self
|
37
19
|
attr_accessor :server
|
38
20
|
|
39
21
|
def start(conf)
|
40
22
|
conf = Conf.new(conf) unless conf.is_a?(Conf)
|
41
23
|
|
42
|
-
# patch for OSX
|
43
|
-
|
44
24
|
Socket.do_not_reverse_lookup = true
|
45
25
|
|
46
26
|
if :none == conf.log and RUBY_PLATFORM !~ /mswin32/
|
@@ -80,6 +60,7 @@ end
|
|
80
60
|
#++
|
81
61
|
|
82
62
|
class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
|
63
|
+
include WEBrick
|
83
64
|
|
84
65
|
# REQUEST_MUTEX = Mutex.new
|
85
66
|
|
@@ -89,60 +70,93 @@ class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
|
|
89
70
|
# Handles static resources. Useful when running
|
90
71
|
# a stand-alone webrick server.
|
91
72
|
|
92
|
-
@file_handler = WEBrick::HTTPServlet::FileHandler.new(
|
93
|
-
server,
|
94
|
-
conf.dispatcher.public_root, conf.webrick_options || {})
|
73
|
+
@file_handler = WEBrick::HTTPServlet::FileHandler.new(server, conf.dispatcher.public_root, conf.webrick_options || {})
|
95
74
|
end
|
96
|
-
|
97
|
-
def handle(req, res)
|
98
|
-
path = req.request_uri.path
|
99
75
|
|
100
|
-
|
76
|
+
# Handle a static file. Also handles cached pages.
|
77
|
+
|
78
|
+
def handle_file(req, res)
|
79
|
+
begin
|
80
|
+
rewrite(req)
|
101
81
|
@file_handler.do_GET(req, res)
|
102
|
-
|
103
|
-
|
104
|
-
|
82
|
+
return true
|
83
|
+
rescue WEBrick::HTTPStatus::PartialContent, WEBrick::HTTPStatus::NotModified => err
|
84
|
+
res.set_error(err)
|
85
|
+
return true
|
86
|
+
rescue
|
87
|
+
return false
|
88
|
+
ensure
|
89
|
+
unrewrite(req)
|
90
|
+
end
|
91
|
+
end
|
105
92
|
|
106
|
-
|
93
|
+
# Handle the request.
|
107
94
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
req.header.each { |h, v| context.headers[h.upcase] = v.first }
|
112
|
-
context.headers.update(req.meta_vars)
|
113
|
-
|
114
|
-
context.params = {}
|
115
|
-
req.query.each do |k, v|
|
116
|
-
if k =~ /(.*)\[\]$/
|
117
|
-
context.params[k] = v
|
118
|
-
else
|
119
|
-
context.params[k] = v.to_s
|
120
|
-
end
|
121
|
-
end
|
122
|
-
# context.in = req.socket
|
123
|
-
# CgiUtils.parse_params(context)
|
95
|
+
def handle(req, res)
|
96
|
+
unless handle_file(req, res)
|
97
|
+
path = req.request_uri.path
|
124
98
|
|
125
|
-
|
126
|
-
|
127
|
-
|
99
|
+
unless path =~ /\./
|
100
|
+
begin
|
101
|
+
path = req.request_uri.path
|
128
102
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
103
|
+
# gmosx, TODO: move this into a filter.
|
104
|
+
Og.db.get_connection if defined?(Og) and Og.db
|
105
|
+
|
106
|
+
# REQUEST_MUTEX.lock
|
107
|
+
|
108
|
+
context = Context.new(@conf)
|
109
|
+
|
110
|
+
context.in = StringIO.new(req.body || "")
|
111
|
+
|
112
|
+
context.headers = {}
|
113
|
+
req.header.each { |h, v| context.headers[h.upcase] = v.first }
|
114
|
+
context.headers.update(req.meta_vars)
|
115
|
+
# gmosx: make compatible with fastcgi.
|
116
|
+
context.headers['REQUEST_URI'].slice!(/http:\/\/(.*)\//)
|
117
|
+
context.headers['REQUEST_URI'] << '/'
|
118
|
+
|
119
|
+
CgiUtils.parse_params(context)
|
120
|
+
CgiUtils.parse_cookies(context)
|
135
121
|
|
136
|
-
|
122
|
+
context.render(path)
|
123
|
+
|
124
|
+
res.status = context.status
|
125
|
+
res.instance_variable_set(:@header, context.response_headers || {})
|
126
|
+
res.instance_variable_set(:@cookies, context.response_cookies || {})
|
127
|
+
res.body = context.out
|
128
|
+
|
129
|
+
context.close
|
130
|
+
ensure
|
131
|
+
# REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
|
132
|
+
Og.db.put_connection if defined?(Og) and Og.db
|
133
|
+
end
|
134
|
+
end
|
137
135
|
end
|
138
|
-
ensure
|
139
|
-
# REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
|
140
|
-
Og.db.put_connection if defined?(Og) and Og.db
|
141
136
|
end
|
142
137
|
|
143
138
|
alias do_GET handle
|
144
139
|
alias do_POST handle
|
145
140
|
|
141
|
+
# Try to rewrite the path to a filename.
|
142
|
+
|
143
|
+
def rewrite(req)
|
144
|
+
if req.path == '/'
|
145
|
+
req.instance_variable_set(:@path_info, '/index.html')
|
146
|
+
elsif req.path =~ /^([^.]+)$/
|
147
|
+
req.instance_variable_set(:@path_info, "#{$1}.html")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Rewrite back to the original path.
|
152
|
+
|
153
|
+
def unrewrite(req)
|
154
|
+
if req.path == '/'
|
155
|
+
req.instance_variable_set(:@path_info, '/')
|
156
|
+
elsif req.path =~ /^([^.]+).html$/
|
157
|
+
req.instance_variable_set(:@path_info, $1)
|
158
|
+
end
|
159
|
+
end
|
146
160
|
end
|
147
161
|
|
148
162
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: caching.rb 326 2005-03-28 11:07:17Z gmosx $
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
require 'glue/attribute'
|
8
|
+
|
9
|
+
require 'nitro/caching/output'
|
10
|
+
require 'nitro/caching/actions'
|
11
|
+
require 'nitro/caching/fragments'
|
12
|
+
|
13
|
+
module N
|
14
|
+
|
15
|
+
# Adds support for caching.
|
16
|
+
|
17
|
+
module Caching
|
18
|
+
|
19
|
+
def self.append_features(base) #:nodoc:
|
20
|
+
super
|
21
|
+
base.send :include, Output, Actions, Fragments
|
22
|
+
base.class_eval do
|
23
|
+
cattr_accessor :caching_enabled, true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: actions.rb 326 2005-03-28 11:07:17Z gmosx $
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module N
|
8
|
+
|
9
|
+
# Adds support for caching.
|
10
|
+
|
11
|
+
module Caching
|
12
|
+
|
13
|
+
# Action caching.
|
14
|
+
|
15
|
+
module Actions
|
16
|
+
|
17
|
+
def self.append_features(base) # :nodoc:
|
18
|
+
super
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
|
24
|
+
def cache_action(*actions)
|
25
|
+
return unless caching_enabled
|
26
|
+
|
27
|
+
before_filter(
|
28
|
+
%{
|
29
|
+
fragment_name = "\#\{@action_name\}\#{@request.query_string}"
|
30
|
+
if fragment = Fragment.get(fragment_name)
|
31
|
+
@out = fragment
|
32
|
+
return
|
33
|
+
end
|
34
|
+
},
|
35
|
+
:only => actions
|
36
|
+
)
|
37
|
+
|
38
|
+
after_filter(
|
39
|
+
%{
|
40
|
+
fragment_name = "\#\{@action_name\}\#{@request.query_string}"
|
41
|
+
Fragment.put(fragment_name, @out)
|
42
|
+
},
|
43
|
+
:only => actions
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
#--
|
52
|
+
# FIXME: not implemented.
|
53
|
+
#++
|
54
|
+
|
55
|
+
def expire_action(*actions)
|
56
|
+
return unless caching_enabled
|
57
|
+
|
58
|
+
for action in [actions].flatten
|
59
|
+
expire_fragment(action)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: fragments.rb 326 2005-03-28 11:07:17Z gmosx $
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
require 'glue/attribute'
|
8
|
+
require 'nitro/caching/stores'
|
9
|
+
|
10
|
+
module N
|
11
|
+
|
12
|
+
# Adds support for caching.
|
13
|
+
|
14
|
+
module Caching
|
15
|
+
|
16
|
+
# Action caching.
|
17
|
+
|
18
|
+
module Fragments
|
19
|
+
|
20
|
+
@@store = FileStore.new # MemoryStore.new
|
21
|
+
|
22
|
+
def self.store
|
23
|
+
@@store
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.store=(store)
|
27
|
+
@@store = store
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get(name, options = {})
|
31
|
+
return @@store.read(name, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.put(name, content = nil, options = {})
|
35
|
+
@@store.write(name, content, options)
|
36
|
+
return content
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.append_features(base) # :nodoc:
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def cache(name = nil, options = {}, &block)
|
46
|
+
name = @action_name unless name
|
47
|
+
cache_fragment(block, "#{name}#{options}", options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def cache_fragment(block, name, options = {})
|
51
|
+
unless caching_enabled
|
52
|
+
block.call
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
if fragment = Fragments.get(name, options)
|
57
|
+
@out << fragment
|
58
|
+
else
|
59
|
+
pos = @out.length
|
60
|
+
block.call
|
61
|
+
Fragments.put(name, @out[pos..-1], options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def expire_fragment(name, options = {})
|
66
|
+
Fragments.store.delete(name, options)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: invalidation.rb 327 2005-03-28 11:09:58Z gmosx $
|
4
|
+
|
5
|
+
module N
|
6
|
+
|
7
|
+
module Caching
|
8
|
+
|
9
|
+
# Support for invalidating output/fragment caches.
|
10
|
+
|
11
|
+
module Invalidation
|
12
|
+
|
13
|
+
def self.append_features(base) #:nodoc:
|
14
|
+
super
|
15
|
+
base.extend(ClassMethods)
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
__END__
|
29
|
+
|
30
|
+
class MyController < Controller
|
31
|
+
|
32
|
+
cache_output :list
|
33
|
+
|
34
|
+
cache_monitor :on => [ :add, :delete ]
|
35
|
+
|
36
|
+
def list
|
37
|
+
end
|
38
|
+
|
39
|
+
def add
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Invalidator
|
48
|
+
def filter(controller)
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: output.rb 322 2005-03-21 18:15:52Z gmosx $
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module N
|
8
|
+
|
9
|
+
# Adds support for caching.
|
10
|
+
|
11
|
+
module Caching
|
12
|
+
|
13
|
+
# Output caching.
|
14
|
+
|
15
|
+
module Output
|
16
|
+
|
17
|
+
def self.append_features(base) # :nodoc:
|
18
|
+
super
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
base.module_eval do
|
21
|
+
cattr_accessor :output_cache_root, 'public'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
|
27
|
+
def do_cache_output(path, content)
|
28
|
+
filepath = output_cache_path(path)
|
29
|
+
FileUtils.makedirs(File.dirname(filepath))
|
30
|
+
File.open(filepath, 'w+') { |f| f.write(content) }
|
31
|
+
Logger.debug "Cached page: #{filepath}" if $DBG
|
32
|
+
end
|
33
|
+
|
34
|
+
# Enable output caching for the given actions.
|
35
|
+
|
36
|
+
def cache_output(*actions)
|
37
|
+
return unless caching_enabled
|
38
|
+
|
39
|
+
str = actions.collect { |a| ":#{a}" }.join(', ')
|
40
|
+
|
41
|
+
module_eval %{
|
42
|
+
after_filter "do_cache_output", :only => [ #{str} ]
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def output_cache_path(path)
|
49
|
+
filename = ((path.empty? || path == '/') ? '/index' : path)
|
50
|
+
filename << '.html' unless (name.split('/').last || name).include? '.'
|
51
|
+
return output_cache_root + filename
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def do_cache_output
|
59
|
+
if caching_enabled and caching_allowed?
|
60
|
+
self.class.do_cache_output(@request.path, @out)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def caching_allowed?
|
65
|
+
!@request.post?
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|