arrow 1.0.7
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 +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- metadata +339 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'configurability'
|
|
6
|
+
|
|
7
|
+
require 'arrow/object'
|
|
8
|
+
require 'arrow/config'
|
|
9
|
+
require 'arrow/applet'
|
|
10
|
+
require 'arrow/transaction'
|
|
11
|
+
require 'arrow/broker'
|
|
12
|
+
require 'arrow/template'
|
|
13
|
+
require 'arrow/templatefactory'
|
|
14
|
+
|
|
15
|
+
require 'arrow/fallbackhandler'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# The Arrow::Dispatcher class -- the mod_ruby handler frontend for Arrow.
|
|
19
|
+
#
|
|
20
|
+
# == Synopsis
|
|
21
|
+
#
|
|
22
|
+
# Simple configuration:
|
|
23
|
+
#
|
|
24
|
+
# RubyRequire 'arrow'
|
|
25
|
+
# RubyChildInitHandler "Arrow::Dispatcher.create( 'myapp.yaml' )"
|
|
26
|
+
#
|
|
27
|
+
# <Location /arrow>
|
|
28
|
+
# Handler ruby-object
|
|
29
|
+
# RubyHandler Arrow::Dispatcher.instance
|
|
30
|
+
# </Location>
|
|
31
|
+
#
|
|
32
|
+
# More-complex setup; run two Arrow dispatchers with different configurations
|
|
33
|
+
# from different Locations:
|
|
34
|
+
#
|
|
35
|
+
# RubyRequire 'arrow'
|
|
36
|
+
# RubyChildInitHandler "Arrow::Dispatcher.create( :myapp => 'myapp.yml', :help => 'help.yml' )"
|
|
37
|
+
#
|
|
38
|
+
# <Location /myapp>
|
|
39
|
+
# Handler ruby-object
|
|
40
|
+
# RubyHandler Arrow::Dispatcher.instance(:myapp)
|
|
41
|
+
# </Location>
|
|
42
|
+
#
|
|
43
|
+
# <Location /help>
|
|
44
|
+
# Handler ruby-object
|
|
45
|
+
# RubyHandler Arrow::Dispatcher.instance(:help)
|
|
46
|
+
# </Location>
|
|
47
|
+
#
|
|
48
|
+
# Same thing, but use a YAML file to control the dispatchers and where their configs are:
|
|
49
|
+
#
|
|
50
|
+
# RubyRequire 'arrow'
|
|
51
|
+
# RubyChildInitHandler "Arrow.load_dispatchers('/Library/WebServer/arrow-hosts.yml')"
|
|
52
|
+
#
|
|
53
|
+
# <Location /myapp>
|
|
54
|
+
# Handler ruby-object
|
|
55
|
+
# RubyHandler Arrow::Dispatcher.instance(:myapp)
|
|
56
|
+
# </Location>
|
|
57
|
+
#
|
|
58
|
+
# <Location /help>
|
|
59
|
+
# Handler ruby-object
|
|
60
|
+
# RubyHandler Arrow::Dispatcher.instance(:help)
|
|
61
|
+
# </Location>
|
|
62
|
+
#
|
|
63
|
+
# arrow-hosts.yml:
|
|
64
|
+
#
|
|
65
|
+
# myapp:
|
|
66
|
+
# /some/directory/myapp.yml
|
|
67
|
+
# help:
|
|
68
|
+
# /other/directory/help.yml
|
|
69
|
+
#
|
|
70
|
+
# == Authors
|
|
71
|
+
#
|
|
72
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
73
|
+
#
|
|
74
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
75
|
+
#
|
|
76
|
+
class Arrow::Dispatcher < Arrow::Object
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
#################################################################
|
|
80
|
+
### C L A S S M E T H O D S
|
|
81
|
+
#################################################################
|
|
82
|
+
|
|
83
|
+
@@Instance = {}
|
|
84
|
+
|
|
85
|
+
### Get the instance of the Dispatcher set up under the given +key+, which
|
|
86
|
+
### can either be a Symbol or a String containing the path to a
|
|
87
|
+
### configfile. If no key is given, it defaults to :__default__, which is
|
|
88
|
+
### the key assigned when .create is given just a configfile argument.
|
|
89
|
+
def self::instance( key=:__default__ )
|
|
90
|
+
rval = nil
|
|
91
|
+
|
|
92
|
+
# Fetch the instance which corresponds to the given key
|
|
93
|
+
if key.is_a?( Symbol )
|
|
94
|
+
Arrow::Logger.debug "Returning instance for key %p (one of %p): %p" %
|
|
95
|
+
[key, @@Instance.keys, @@Instance[key]]
|
|
96
|
+
rval = @@Instance[ key ]
|
|
97
|
+
else
|
|
98
|
+
Arrow::Logger.debug "Returning instance for configfile %p" % [key]
|
|
99
|
+
configfile = File.expand_path( key )
|
|
100
|
+
self.create( configfile )
|
|
101
|
+
rval = @@Instance[ configfile ]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Return either a configured Dispatcher instance or a FallbackHandler if
|
|
105
|
+
# no Dispatcher corresponds to the given key.
|
|
106
|
+
return rval || Arrow::FallbackHandler.new( key, @@Instance )
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
### Set up one or more new Arrow::Dispatcher objects. The +configspec+
|
|
111
|
+
### argument can either be the path to a config file, or a hash of config
|
|
112
|
+
### files. See the .instance method for more about how to use this method.
|
|
113
|
+
def self::create( configspec )
|
|
114
|
+
|
|
115
|
+
# Normalize configurations. Expected either a configfile path in a
|
|
116
|
+
# String, or a Hash of configfiles
|
|
117
|
+
case configspec
|
|
118
|
+
when String
|
|
119
|
+
configs = { :__default__ => configspec }
|
|
120
|
+
when Hash
|
|
121
|
+
configs = configspec
|
|
122
|
+
else
|
|
123
|
+
raise ArgumentError, "Invalid config hash %p" % [configspec]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Create the dispatchers and return the first one to support the
|
|
127
|
+
# old-style create, i.e.,
|
|
128
|
+
# dispatcher = Arrow::Dispatcher.create( configfile )
|
|
129
|
+
@@Instance = create_configured_dispatchers( configs )
|
|
130
|
+
@@Instance.values.first
|
|
131
|
+
rescue ::Exception => err
|
|
132
|
+
|
|
133
|
+
# Try to log fatal errors to both the Apache server log and a crashfile
|
|
134
|
+
# before passing the exception along.
|
|
135
|
+
errmsg = "%s failed to start (%s): %s: %s" % [
|
|
136
|
+
self.name,
|
|
137
|
+
err.class.name,
|
|
138
|
+
err.message,
|
|
139
|
+
err.backtrace.join("\n ")
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
logfile = File.join( Dir.tmpdir, "arrow-fatal.log.#{$$}" )
|
|
143
|
+
File.open( logfile, IO::WRONLY|IO::TRUNC|IO::CREAT ) {|ofh|
|
|
144
|
+
ofh.puts( errmsg )
|
|
145
|
+
ofh.flush
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if defined?( Apache )
|
|
149
|
+
Apache.request.server.log_crit( errmsg )
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
Kernel.raise( err )
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
### Create one or more dispatchers from the specified +hosts_file+, which is
|
|
157
|
+
### a YAML file that maps arrow configurations onto a symbol that can be
|
|
158
|
+
### used to refer to it.
|
|
159
|
+
def self::create_from_hosts_file( hosts_file )
|
|
160
|
+
configs = nil
|
|
161
|
+
|
|
162
|
+
if hosts_file.respond_to?( :read )
|
|
163
|
+
configs = YAML.load( hosts_file.read )
|
|
164
|
+
else
|
|
165
|
+
hosts_file.untaint
|
|
166
|
+
configs = YAML.load_file( hosts_file )
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Convert the keys to Symbols and the values to untainted Strings.
|
|
170
|
+
configs.each do |key,config|
|
|
171
|
+
sym = key.to_s.dup.untaint.to_sym
|
|
172
|
+
configs[ sym ] = configs.delete( key )
|
|
173
|
+
configs[ sym ].untaint
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
@@Instance = self.create_configured_dispatchers( configs )
|
|
177
|
+
return @@Instance
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
### Create dispatchers for the config files given in +configspec+ and return
|
|
182
|
+
### them in a Hash keyed by both the configname key and the expanded path to
|
|
183
|
+
### the configuration file.
|
|
184
|
+
def self::create_configured_dispatchers( configspec )
|
|
185
|
+
instances = {}
|
|
186
|
+
|
|
187
|
+
# Load a dispatcher for each config
|
|
188
|
+
configspec.each do |key, configfile|
|
|
189
|
+
|
|
190
|
+
# Normalize the path to the config file and make sure it's not
|
|
191
|
+
# loaded yet. If it is, link it to the current key and skip to the
|
|
192
|
+
# next.
|
|
193
|
+
configfile = File.expand_path( configfile )
|
|
194
|
+
if instances.key?( configfile )
|
|
195
|
+
instances[ key ] = instances[ configfile ]
|
|
196
|
+
next
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# If a config file is given, load it. If it's not, just use the
|
|
200
|
+
# default config.
|
|
201
|
+
if configfile
|
|
202
|
+
config = Arrow::Config.load( configfile )
|
|
203
|
+
else
|
|
204
|
+
config = Arrow::Config.new
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Create a dispatcher and put it in the table by both its key and
|
|
208
|
+
# the normalized path to its configfile.
|
|
209
|
+
msg = "Creating dispatcher %p from %p" % [ key, configfile ]
|
|
210
|
+
Apache.request.server.log_notice( msg ) if defined?( Apache )
|
|
211
|
+
instances[ key ] = instances[ configfile ] = new( key, config )
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
return instances
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
#############################################################
|
|
219
|
+
### I N S T A N C E M E T H O D S
|
|
220
|
+
#############################################################
|
|
221
|
+
|
|
222
|
+
### Set up an Arrow::Dispatcher object based on the specified +config+
|
|
223
|
+
### (an Arrow::Config object).
|
|
224
|
+
def initialize( name, config )
|
|
225
|
+
@name = name
|
|
226
|
+
@config = config
|
|
227
|
+
|
|
228
|
+
@broker = Arrow::Broker.new( config )
|
|
229
|
+
self.configure( config )
|
|
230
|
+
rescue ::Exception => err
|
|
231
|
+
msg = "%s while creating dispatcher: %s\n%s" %
|
|
232
|
+
[ err.class.name, err.message, err.backtrace.join("\n\t") ]
|
|
233
|
+
self.log.error( msg )
|
|
234
|
+
msg.gsub!( /%/, '%%' )
|
|
235
|
+
Apache.request.server.log_crit( msg ) unless !defined?( Apache )
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
######
|
|
240
|
+
public
|
|
241
|
+
######
|
|
242
|
+
|
|
243
|
+
### The key used to indentify this dispatcher
|
|
244
|
+
attr_reader :name
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
### (Re)configure the dispatcher based on the values in the given
|
|
248
|
+
### +config+ (an Arrow::Config object).
|
|
249
|
+
def configure( config )
|
|
250
|
+
self.log.notice "Configuring a dispatcher for '%s' from '%s': child server %d" %
|
|
251
|
+
[ Apache.request.server.hostname, config.name, Process.pid ]
|
|
252
|
+
|
|
253
|
+
# Configure any modules that have mixed in Configurability
|
|
254
|
+
if defined?( Apache )
|
|
255
|
+
require 'apache/logger'
|
|
256
|
+
Configurability.logger = Logger.new( Apache::LogDevice.new )
|
|
257
|
+
Configurability.logger.formatter = Apache::LogFormatter.new
|
|
258
|
+
else
|
|
259
|
+
Configurability.reset_logger
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
Configurability.configure_objects( config )
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
### mod_ruby Handlers
|
|
267
|
+
|
|
268
|
+
### Child init mod_ruby handler
|
|
269
|
+
def child_init( req ) # :nodoc
|
|
270
|
+
self.log.notice "Dispatcher configured for %s" % [ req.server.hostname ]
|
|
271
|
+
return Apache::OK
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
### The content handler method. Dispatches requests to registered
|
|
276
|
+
### applets based on the requests PATH_INFO.
|
|
277
|
+
def handler( req )
|
|
278
|
+
self.log.info "--- Dispatching request %p ---------------" % [req]
|
|
279
|
+
self.log.debug "Request headers are: %s" % [untable(req.headers_in)]
|
|
280
|
+
|
|
281
|
+
if (( reason = @config.changed_reason ))
|
|
282
|
+
self.log.notice "** Reloading configuration: #{reason} ***"
|
|
283
|
+
@config.reload
|
|
284
|
+
@broker = Arrow::Broker.new( @config )
|
|
285
|
+
self.configure( @config )
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
if ! @broker
|
|
289
|
+
self.log.error "Fatal: No broker."
|
|
290
|
+
return Apache::SERVER_ERROR
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
txn = Arrow::Transaction.new( req, @config, @broker )
|
|
294
|
+
|
|
295
|
+
self.log.debug "Delegating transaction %p" % [txn]
|
|
296
|
+
unless output = @broker.delegate( txn )
|
|
297
|
+
self.log.info "Declining transaction (Applets returned: %p)" % output
|
|
298
|
+
return Apache::DECLINED
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# If the transaction succeeded, set up the Apache::Request object, add
|
|
302
|
+
# headers, add session state, etc. If it failed, log the failure and let
|
|
303
|
+
# the status be returned as-is.
|
|
304
|
+
response_body = nil
|
|
305
|
+
self.log.debug "Transaction has status %d" % [txn.status]
|
|
306
|
+
|
|
307
|
+
# Render the output before anything else, as there might be
|
|
308
|
+
# session/header manipulation left to be done somewhere in the
|
|
309
|
+
# render. If the response is true, the applets have handled output
|
|
310
|
+
# themselves.
|
|
311
|
+
if output && output != true
|
|
312
|
+
rendertime = Benchmark.measure do
|
|
313
|
+
response_body = output.to_s
|
|
314
|
+
end
|
|
315
|
+
self.log.debug "Output render time: %s" %
|
|
316
|
+
rendertime.format( '%8.4us usr %8.4ys sys %8.4ts wall %8.4r' )
|
|
317
|
+
req.headers_out['content-length'] = response_body.length.to_s unless
|
|
318
|
+
req.headers_out['content-length']
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# If the transaction has a session, save it
|
|
322
|
+
txn.session.save if txn.session?
|
|
323
|
+
|
|
324
|
+
# Add cookies to the response headers
|
|
325
|
+
txn.add_cookie_headers
|
|
326
|
+
|
|
327
|
+
self.log.debug "HTTP response status is: %d" % [txn.status]
|
|
328
|
+
self.log.debug "Response headers were: %s" % [untable(req.headers_out)]
|
|
329
|
+
txn.send_http_header
|
|
330
|
+
txn.print( response_body ) if response_body
|
|
331
|
+
|
|
332
|
+
self.log.info "--- Done with request %p (%s)---------------" %
|
|
333
|
+
[ req, req.status_line ]
|
|
334
|
+
|
|
335
|
+
req.sync = true
|
|
336
|
+
return txn.handler_status
|
|
337
|
+
rescue ::Exception => err
|
|
338
|
+
self.log.error "Dispatcher caught an unhandled %s: %s:\n\t%s" %
|
|
339
|
+
[ err.class.name, err.message, err.backtrace.join("\n\t") ]
|
|
340
|
+
return Apache::SERVER_ERROR
|
|
341
|
+
|
|
342
|
+
ensure
|
|
343
|
+
# Make sure session locks are released
|
|
344
|
+
txn.session.finish if txn && txn.session?
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
### Return a human-readable representation of the receiver as a String.
|
|
349
|
+
def inspect
|
|
350
|
+
return "#<%s:0x%x config: %s>" % [
|
|
351
|
+
self.class.name,
|
|
352
|
+
self.object_id,
|
|
353
|
+
@config.name,
|
|
354
|
+
]
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def untable( table )
|
|
359
|
+
lines = []
|
|
360
|
+
table.each do |k,v|
|
|
361
|
+
lines << "%s: %s" % [ k, v ]
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
return lines.join( "; " )
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
end # class Arrow::Dispatcher
|
|
368
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'arrow'
|
|
4
|
+
require 'arrow/dispatcher'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### A +RubyChildInitHandler+ class which loads one or more dispatchers
|
|
8
|
+
### when a child server starts. This can eliminate the startup lag for
|
|
9
|
+
### the first request each child handles. See the docs for dispatcher.rb
|
|
10
|
+
### for an example of how to use this.
|
|
11
|
+
class Arrow::DispatcherLoader
|
|
12
|
+
|
|
13
|
+
### Create a loader that will create dispatchers from the given
|
|
14
|
+
### +hostsfile+, which is a YAML hash that maps dispatcher names to
|
|
15
|
+
### a configfile path.
|
|
16
|
+
def initialize( hostsfile )
|
|
17
|
+
require 'arrow/applet'
|
|
18
|
+
require 'arrow/dispatcher'
|
|
19
|
+
require 'arrow/broker'
|
|
20
|
+
|
|
21
|
+
@hostsfile = hostsfile
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Load the dispatchers according to the registered hosts file.
|
|
26
|
+
def child_init( req )
|
|
27
|
+
req.server.log_info( "Loading dispatcher configs from " + @hostsfile + "." )
|
|
28
|
+
Arrow::Dispatcher.create_from_hosts_file( @hostsfile )
|
|
29
|
+
|
|
30
|
+
return Apache::OK
|
|
31
|
+
rescue ::Exception => err
|
|
32
|
+
errmsg = "%s failed to load dispatchers (%s): %s: %s" % [
|
|
33
|
+
self.class.name,
|
|
34
|
+
err.class.name,
|
|
35
|
+
err.message,
|
|
36
|
+
err.backtrace.join("\n ")
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
logfile = Pathname.new( Dir.tmpdir ) + 'arrow-dispatcher-failure.log'
|
|
40
|
+
logfile.open( IO::WRONLY|IO::TRUNC|IO::CREAT ) do |ofh|
|
|
41
|
+
ofh.puts( errmsg )
|
|
42
|
+
ofh.flush
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Apache.request.server.log_crit( errmsg )
|
|
46
|
+
raise
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end # class Arrow::DispatcherLoader
|
|
50
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
module Arrow # :nodoc:
|
|
3
|
+
|
|
4
|
+
### Base exception class
|
|
5
|
+
class Exception < StandardError
|
|
6
|
+
Message = "Arrow framework error"
|
|
7
|
+
|
|
8
|
+
def initialize( message=nil )
|
|
9
|
+
message ||= self.class.const_get( "Message" )
|
|
10
|
+
super( message )
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
### Define an exception class with the specified <tt>name</tt> (a Symbol)
|
|
15
|
+
### with the specified <tt>message</tt>. The new exception class will
|
|
16
|
+
### inherit from the specified <tt>superclass</tt>, if specified, or
|
|
17
|
+
### <tt>StandardError</tt> if not specified.
|
|
18
|
+
def Arrow.def_exception( name, message, superclass=Arrow::Exception )
|
|
19
|
+
name = name.id2name if name.kind_of?( Fixnum )
|
|
20
|
+
eClass = Class.new( superclass )
|
|
21
|
+
eClass.module_eval %Q{
|
|
22
|
+
def initialize( *args )
|
|
23
|
+
if ! args.empty?
|
|
24
|
+
msg = args.collect {|a| a.to_s}.join
|
|
25
|
+
super( msg )
|
|
26
|
+
else
|
|
27
|
+
super( message )
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const_set( name, eClass )
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# System exceptions
|
|
37
|
+
def_exception :ConfigError, "Configuration error"
|
|
38
|
+
def_exception :LockingError, "Locking error"
|
|
39
|
+
def_exception :SessionError, "Error in session"
|
|
40
|
+
|
|
41
|
+
# Templating errors
|
|
42
|
+
def_exception :TemplateError, "Error in templating system"
|
|
43
|
+
def_exception :ParseError, "Error while parsing",
|
|
44
|
+
TemplateError
|
|
45
|
+
def_exception :ScopeError, "Error in rendering scope",
|
|
46
|
+
TemplateError
|
|
47
|
+
|
|
48
|
+
# Signal exceptions
|
|
49
|
+
def_exception :Reload, "Configuration out of date"
|
|
50
|
+
def_exception :Shutdown, "Server shutdown"
|
|
51
|
+
|
|
52
|
+
# Applet errors
|
|
53
|
+
def_exception :AppletError, "Applet error"
|
|
54
|
+
def_exception :AppletChainError, "Malformed applet chain"
|
|
55
|
+
|
|
56
|
+
# Datasource errors
|
|
57
|
+
def_exception :TypeError, "Data type incompatible"
|
|
58
|
+
def_exception :LoadError, "Loading failed"
|
|
59
|
+
|
|
60
|
+
end # module Arrow
|
|
61
|
+
|