egalite 0.0.1 → 0.0.2

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.
Files changed (33) hide show
  1. data/Gemfile +4 -0
  2. data/LICENSE.txt +22 -0
  3. data/Rakefile +1 -0
  4. data/egalite.gemspec +24 -0
  5. data/lib/egalite/auth/basic.rb +32 -0
  6. data/lib/egalite/blank.rb +53 -0
  7. data/lib/egalite/errorconsole.rb +77 -0
  8. data/lib/egalite/helper.rb +251 -0
  9. data/lib/egalite/keitai/keitai.rb +107 -0
  10. data/lib/egalite/keitai/ketai.rb +11 -0
  11. data/lib/egalite/keitai/rack/ketai/carrier/abstract.rb +131 -0
  12. data/lib/egalite/keitai/rack/ketai/carrier/au.rb +78 -0
  13. data/lib/egalite/keitai/rack/ketai/carrier/docomo.rb +80 -0
  14. data/lib/egalite/keitai/rack/ketai/carrier/emoji/ausjisstrtoemojiid.rb +1391 -0
  15. data/lib/egalite/keitai/rack/ketai/carrier/emoji/docomosjisstrtoemojiid.rb +759 -0
  16. data/lib/egalite/keitai/rack/ketai/carrier/emoji/emojidata.rb +836 -0
  17. data/lib/egalite/keitai/rack/ketai/carrier/emoji/softbankutf8strtoemojiid.rb +1119 -0
  18. data/lib/egalite/keitai/rack/ketai/carrier/emoji/softbankwebcodetoutf8str.rb +499 -0
  19. data/lib/egalite/keitai/rack/ketai/carrier/iphone.rb +8 -0
  20. data/lib/egalite/keitai/rack/ketai/carrier/softbank.rb +82 -0
  21. data/lib/egalite/keitai/rack/ketai/carrier.rb +17 -0
  22. data/lib/egalite/keitai/rack/ketai/middleware.rb +24 -0
  23. data/lib/egalite/m17n.rb +193 -0
  24. data/lib/egalite/route.rb +231 -0
  25. data/lib/egalite/sendmail.rb +222 -0
  26. data/lib/egalite/sequel_helper.rb +20 -0
  27. data/lib/egalite/session.rb +132 -0
  28. data/lib/egalite/stringify_hash.rb +63 -0
  29. data/lib/egalite/support.rb +35 -0
  30. data/lib/egalite/template.rb +287 -0
  31. data/lib/egalite/version.rb +3 -0
  32. data/lib/egalite.rb +744 -0
  33. metadata +35 -3
data/lib/egalite.rb ADDED
@@ -0,0 +1,744 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+
3
+ require "egalite/version"
4
+
5
+ require 'rack'
6
+ require 'egalite/blank'
7
+
8
+ require 'egalite/stringify_hash'
9
+
10
+ require 'egalite/template'
11
+ require 'egalite/route'
12
+ require 'egalite/session'
13
+ require 'egalite/helper'
14
+
15
+ require 'time'
16
+ require 'monitor'
17
+ require 'digest/md5'
18
+
19
+ module Rack
20
+ module Utils
21
+ def normalize_params(params,name,v)
22
+ params[name] = v
23
+ end
24
+ module_function :normalize_params
25
+ end
26
+ end
27
+
28
+ class CriticalError < RuntimeError
29
+ end
30
+
31
+ module Egalite
32
+
33
+ module AccessLogger
34
+ @@io = nil
35
+ @@time = nil
36
+ @@lock = Monitor.new
37
+ class <<self
38
+ def io=(io)
39
+ @@io=io
40
+ end
41
+ def _open
42
+ @@dir = dir
43
+ @@time = Time.now
44
+ fn = sprintf("egaliteaccess-%04d-%02d-%02d-p%d.log", @@time.year, @@time.month, @@time.mday, Process.pid)
45
+ @@io = open(File.join(dir,fn), "a")
46
+ end
47
+ def open(dir)
48
+ @@dir = dir
49
+ yield
50
+ ensure
51
+ @@io.close if @@io
52
+ end
53
+ def write(line)
54
+ return nil unless @@io
55
+
56
+ @@lock.synchronize {
57
+ if @@time and (@@time.mday != Time.now.mday)
58
+ ## log rotation
59
+ @@io.close
60
+ _open
61
+ end
62
+ @@io.puts(line)
63
+ }
64
+ end
65
+ end
66
+ end
67
+
68
+ class DebugLogger
69
+ def initialize(path)
70
+ @path = path
71
+ end
72
+ def puts(s)
73
+ open(@path, "a") { |f|
74
+ begin
75
+ f.flock(File::LOCK_EX)
76
+ f.puts s
77
+ f.flush
78
+ ensure
79
+ f.flock(File::LOCK_UN)
80
+ end
81
+ }
82
+ end
83
+ end
84
+
85
+ module ErrorLogger
86
+ @@table = nil
87
+ @@admin_emails = nil
88
+ class <<self
89
+ def table=(t)
90
+ @@table=t
91
+ end
92
+ def admin_emails=(t)
93
+ @@admin_emails=t
94
+ end
95
+ def write(hash)
96
+ hash[:md5] = Digest::MD5.hexdigest(hash[:text]) unless hash[:md5]
97
+ if hash[:severity] == 'critical' and @@admin_emails
98
+ Sendmail.send(hash[:text],{
99
+ :from => 'info@xcream.net',
100
+ :to => @@admin_emails,
101
+ :subject => 'Critical error at xcream.net'
102
+ })
103
+ end
104
+ @@table.insert(hash) if @@table
105
+ end
106
+ def write_exception(e, hash)
107
+ severity = 'exception'
108
+ severity = 'security' if e.is_a?(SecurityError)
109
+ severity = 'critical' if e.is_a?(CriticalError)
110
+
111
+ text = "#{e.to_s}\n#{e.backtrace.join("\n")}"
112
+
113
+ ErrorLogger.write({:severity => severity, :text => text}.merge(hash))
114
+ end
115
+ end
116
+ end
117
+
118
+ class Controller
119
+ attr_accessor :env, :req, :params, :template_file, :log_values
120
+ undef id
121
+
122
+ # filters
123
+ def before_filter
124
+ true
125
+ end
126
+ def after_filter_return_value(response) # right after controller
127
+ response
128
+ end
129
+ def after_filter(response) # after filter for final http output
130
+ response
131
+ end
132
+ def filter_on_html_load(html, htmlfile)
133
+ html
134
+ end
135
+
136
+ # accessors
137
+ def db
138
+ @env.db
139
+ end
140
+ def cookies
141
+ @req.cookies
142
+ end
143
+ def session
144
+ @req.session
145
+ end
146
+ def id
147
+ @params[:id]
148
+ end
149
+
150
+ # results
151
+ def notfound
152
+ EgaliteResponse.new(:notfound)
153
+ end
154
+ def redirect(url)
155
+ url = url_for(url) if url.is_a?(Hash)
156
+ EgaliteResponse.new(:redirect, url)
157
+ end
158
+ alias :redirect_to :redirect
159
+
160
+ def redirect_permanent(url)
161
+ url = url_for(url) if url.is_a?(Hash)
162
+ [301,{'Location' => url}, [url]]
163
+ end
164
+
165
+ def delegate(params)
166
+ EgaliteResponse.new(:delegate, params)
167
+ end
168
+ def include(params)
169
+ raw(req.handler.inner_dispatch(req, params)[2].to_s)
170
+ end
171
+ def send_file(path, content_type = nil)
172
+ ext = File.extname(path)[1..-1]
173
+
174
+ if File.file?(path) && File.readable?(path)
175
+ s = nil
176
+ open(path, "rb") { |file|
177
+ s = file.read
178
+ }
179
+ return [200, {
180
+ "Last-Modified" => File.mtime(path).rfc822,
181
+ "Content-Type" => content_type || MIME_TYPES[ext] || "text/plain",
182
+ "Content-Length" => File.size(path).to_s
183
+ }, s]
184
+ else
185
+ return [404, {"Content-Type" => "text/plain"}, ["File not found\n"]]
186
+ end
187
+ end
188
+ def send_data(data, content_type)
189
+ [200,{"Content-Type" => content_type},[data]]
190
+ end
191
+
192
+ # helpers
193
+ def url_for(prms)
194
+ @req.route.url_for(prms, req.host, req.port, req.scheme)
195
+ end
196
+ def link_to(title,prms)
197
+ return tags.a(prms,title) if prms.is_a?(String)
198
+ raw(@req.route.link_to(title,prms, req.host, req.port, req.scheme))
199
+ end
200
+ def raw(text)
201
+ NonEscapeString.new(text)
202
+ end
203
+ def escape_html(s)
204
+ tags.escape_html(s)
205
+ end
206
+ def tags
207
+ HTMLTagBuilder
208
+ end
209
+ def table_by_array(header,content,opts={})
210
+ TableHelper.table_by_array(header,content,opts)
211
+ end
212
+ def form(data={},param_name = nil, opts = {})
213
+ FormHelper.new(data,param_name,opts)
214
+ end
215
+ def file_form(data={},param_name = nil, opts = {})
216
+ FormHelper.new(data,param_name,opts.merge(:enctype => 'multipart/form-data'))
217
+ end
218
+ def errorlog(severity, text)
219
+ logid = Egalite::ErrorLogger.write(:severity => severity, :ipaddress => @req.ipaddr, :text => text, :url => @req.url)
220
+ logid
221
+ end
222
+
223
+ # From WEBrick.
224
+ MIME_TYPES = {
225
+ "ai" => "application/postscript",
226
+ "asc" => "text/plain",
227
+ "avi" => "video/x-msvideo",
228
+ "bin" => "application/octet-stream",
229
+ "bmp" => "image/bmp",
230
+ "class" => "application/octet-stream",
231
+ "cer" => "application/pkix-cert",
232
+ "crl" => "application/pkix-crl",
233
+ "crt" => "application/x-x509-ca-cert",
234
+ #"crl" => "application/x-pkcs7-crl",
235
+ "css" => "text/css",
236
+ "dms" => "application/octet-stream",
237
+ "doc" => "application/msword",
238
+ "dvi" => "application/x-dvi",
239
+ "eps" => "application/postscript",
240
+ "etx" => "text/x-setext",
241
+ "exe" => "application/octet-stream",
242
+ "gif" => "image/gif",
243
+ "htm" => "text/html",
244
+ "html" => "text/html",
245
+ "jpe" => "image/jpeg",
246
+ "jpeg" => "image/jpeg",
247
+ "jpg" => "image/jpeg",
248
+ "js" => "text/javascript",
249
+ "lha" => "application/octet-stream",
250
+ "lzh" => "application/octet-stream",
251
+ "mov" => "video/quicktime",
252
+ "mpe" => "video/mpeg",
253
+ "mpeg" => "video/mpeg",
254
+ "mpg" => "video/mpeg",
255
+ "pbm" => "image/x-portable-bitmap",
256
+ "pdf" => "application/pdf",
257
+ "pgm" => "image/x-portable-graymap",
258
+ "png" => "image/png",
259
+ "pnm" => "image/x-portable-anymap",
260
+ "ppm" => "image/x-portable-pixmap",
261
+ "ppt" => "application/vnd.ms-powerpoint",
262
+ "ps" => "application/postscript",
263
+ "qt" => "video/quicktime",
264
+ "ras" => "image/x-cmu-raster",
265
+ "rb" => "text/plain",
266
+ "rd" => "text/plain",
267
+ "rtf" => "application/rtf",
268
+ "sgm" => "text/sgml",
269
+ "sgml" => "text/sgml",
270
+ "tif" => "image/tiff",
271
+ "tiff" => "image/tiff",
272
+ "txt" => "text/plain",
273
+ "xbm" => "image/x-xbitmap",
274
+ "xls" => "application/vnd.ms-excel",
275
+ "xml" => "text/xml",
276
+ "xpm" => "image/x-xpixmap",
277
+ "xwd" => "image/x-xwindowdump",
278
+ "zip" => "application/zip",
279
+ }
280
+ end
281
+
282
+ module CSRFFilter
283
+ def after_filter_return_value(response) # right after controller
284
+ p "CSRFFilter"
285
+ if session and session.sstr and response.is_a?(Hash)
286
+ response.merge(:csrf => session.sstr)
287
+ elsif session and session.sstr and response.is_a?(Sequel::Model)
288
+ response[:csrf] = session.sstr
289
+ response
290
+ else
291
+ response
292
+ end
293
+ end
294
+ end
295
+ class CSRFController < Controller
296
+ def after_filter_return_value(response) # right after controller
297
+ if session and session.sstr and response.is_a?(Hash)
298
+ response.merge(:csrf => session.sstr)
299
+ elsif session and session.sstr and response.is_a?(Sequel::Model)
300
+ response[:csrf] = session.sstr
301
+ response
302
+ else
303
+ response
304
+ end
305
+ end
306
+ end
307
+
308
+ class EgaliteError < RuntimeError
309
+ end
310
+ class EgaliteResponse
311
+ attr_accessor :command
312
+ attr_accessor :param
313
+
314
+ def initialize(com, param = nil)
315
+ @command = com
316
+ @param = param
317
+ end
318
+ end
319
+
320
+ class Environment
321
+ attr_reader :db, :opts
322
+
323
+ def initialize(db,opts)
324
+ @db = db
325
+ @opts = opts
326
+ end
327
+ end
328
+
329
+ class Request
330
+ attr_accessor :session, :cookies, :authorization
331
+ attr_accessor :language, :method
332
+ attr_accessor :route, :controller, :action, :params, :path_info, :path_params
333
+ attr_accessor :controller_class, :action_method
334
+ attr_reader :rack_request, :time, :handler
335
+
336
+ def initialize(values = {})
337
+ @cookies = []
338
+ @rack_request = values[:rack_request]
339
+ @handler = values[:handler]
340
+ @rack_env = values[:rack_env]
341
+ @time = Time.now
342
+ end
343
+ def accept_language
344
+ @rack_env['HTTP_ACCEPT_LANGUAGE']
345
+ end
346
+ def scheme
347
+ @rack_request.scheme
348
+ end
349
+ def port
350
+ @rack_request.port
351
+ end
352
+ def host
353
+ @rack_request.host
354
+ end
355
+ def ipaddr
356
+ @rack_request.ip
357
+ end
358
+ def path
359
+ @rack_request.path
360
+ end
361
+ def url
362
+ @rack_request.url
363
+ end
364
+ def referrer
365
+ @rack_request.referrer
366
+ end
367
+ end
368
+
369
+ class Handler
370
+ attr_accessor :routes
371
+
372
+ def initialize(opts = {})
373
+ @routes = opts[:routes] || Route.default_routes
374
+
375
+ db = opts[:db]
376
+ @db = db
377
+ @opts = opts
378
+ @env = Environment.new(db, opts)
379
+ opts[:static_root] ||= "static/"
380
+
381
+ @template_path = opts[:template_path] || 'pages/'
382
+ @template_path << '/' if @template_path[-1..-1] != '/'
383
+ @template_engine = opts[:template_engine] || HTMLTemplate
384
+
385
+ @profile_logger = opts[:profile_logger]
386
+ @notfound_template = opts[:notfound_template]
387
+ @error_template = opts[:error_template]
388
+ @admin_emails = opts[:admin_emails]
389
+ @exception_log_table = opts[:exception_log_table]
390
+ if @exception_log_table
391
+ Egalite::ErrorLogger.table = db[@exception_log_table]
392
+ Egalite::ErrorLogger.admin_emails = @admin_emails
393
+ end
394
+ end
395
+
396
+ private
397
+ def load_template(tmpl)
398
+ # to expand: template caching
399
+ if File.file?(tmpl) && File.readable?(tmpl)
400
+ open(tmpl) { |f| f.read }
401
+ else
402
+ nil
403
+ end
404
+ end
405
+
406
+ def escape_html(s)
407
+ Rack::Utils.escape_html(s)
408
+ end
409
+
410
+ def display_notfound
411
+ if @notfound_template
412
+ [404, {"Content-Type" => "text/html"}, [load_template(@notfound_template)]]
413
+ else
414
+ [404, {"Content-Type" => "text/plain"}, ['404 not found']]
415
+ end
416
+ end
417
+ def redirect(url)
418
+ [302,{'Location' => url}, [url]]
419
+ end
420
+ def get_controller(controllername,action, method)
421
+ action = method if action.blank?
422
+ action.downcase!
423
+ action.gsub!(/[^0-9a-z_]/,'')
424
+
425
+ return nil if action == ""
426
+
427
+ Controller.new.methods.each { |s| raise SecurityError if action == s }
428
+
429
+ controllername ||= ''
430
+ controllername = controllername.split('/').map { |c|
431
+ c.downcase!
432
+ c.gsub!(/[^0-9a-z]/,'')
433
+ c.capitalize
434
+ }.join
435
+ controllername = 'Default' if controllername.blank?
436
+
437
+ kontroller = nil
438
+ begin
439
+ kontroller = Object.const_get(controllername+'Controller')
440
+ rescue Exception => e
441
+ return nil
442
+ end
443
+
444
+ controller = kontroller.new
445
+ method = method.downcase
446
+
447
+ unless controller.respond_to?(action)
448
+ if controller.respond_to?("#{action}_#{method}")
449
+ action = "#{action}_#{method}"
450
+ else
451
+ return nil
452
+ end
453
+ end
454
+ [controller, action]
455
+ end
456
+
457
+ def forbidden
458
+ [403, {'Content-Type' => 'text/plain'}, ['Forbidden']]
459
+ end
460
+
461
+ def display_internal_server_error(e)
462
+ html = [
463
+ "<html><body>",
464
+ "<h1>Internal server error.</h1>"
465
+ ]
466
+ if ShowException
467
+ html += [
468
+ "<p>Exception: #{escape_html(e.to_s)}</p>",
469
+ "<h2>Back trace</h2>",
470
+ "<p>#{e.backtrace.map{|s|escape_html(s)}.join("<br/>\n")}</p>"
471
+ ]
472
+ end
473
+ html << "</body></html>"
474
+ [500, {'Content-Type' => 'text/html'}, [html.join("\n")]]
475
+ end
476
+
477
+ def set_cookies_to_response(response,req)
478
+ req.cookies.each { |k,v|
479
+ cookie_opts = @opts[:cookie_opts] || {}
480
+ unless v.is_a?(Hash)
481
+ req.cookies[k] = {
482
+ :value => v.to_s,
483
+ :expires => Time.now + (cookie_opts[:expire_after] || 3600),
484
+ :path => cookie_opts[:path] || '/',
485
+ :secure => cookie_opts[:secure] || false
486
+ }
487
+ end
488
+ }
489
+ a = req.cookies.map { |k,v|
490
+ s = "#{Rack::Utils.escape(k)}=#{Rack::Utils.escape(v[:value])}"
491
+ s += "; domain=#{v[:domain]}" if v[:domain]
492
+ s += "; path=#{v[:path]}" if v[:path]
493
+ s += "; expires=#{v[:expires].clone.gmtime.strftime("%a, %d-%b-%Y %H:%M:%S GMT")}" if v[:expires]
494
+ s += "; secure" if v[:secure]
495
+ s
496
+ }
497
+ s = a.join("\n")
498
+ response[1]['Set-Cookie'] = s
499
+ end
500
+
501
+ public
502
+ def inner_dispatch(req, values)
503
+ # recursive controller call to handle include tag or delegate.
504
+ stringified = StringifyHash.create(values)
505
+ (path, params) = req.route.get_path_and_params_from_params(stringified)
506
+ newreq = req.clone
507
+ newreq.params = params
508
+ method = 'GET'
509
+ method = values[:http_method] if values[:http_method]
510
+ dispatch(path, params, method, newreq)
511
+ end
512
+ def run_controller(controller, action, req)
513
+ # invoke controller
514
+ controller.env = @env
515
+ controller.req = req
516
+ controller.params = req.params
517
+
518
+ before_filter_result = controller.before_filter
519
+ if before_filter_result != true
520
+ return before_filter_result if before_filter_result.is_a?(Array)
521
+ return forbidden unless before_filter_result.respond_to?(:command)
522
+ response = case before_filter_result.command
523
+ when :delegate
524
+ inner_dispatch(req, before_filter_result.param)
525
+ when :redirect
526
+ redirect(before_filter_result.param)
527
+ when :notfound
528
+ display_notfound
529
+ else
530
+ forbidden
531
+ end
532
+ set_cookies_to_response(response,req)
533
+ return response
534
+ end
535
+
536
+ nargs = controller.method(action).arity
537
+ args = req.path_params[0,nargs.abs] || []
538
+ if nargs > 0
539
+ args.size.upto(nargs-1) { args << nil }
540
+ end
541
+ raise SecurityError unless controller.respond_to?(action, false)
542
+
543
+ s = Time.now
544
+ values = controller.send(action,*args)
545
+ t = Time.now - s
546
+ @profile_logger.puts "#{Time.now}: ctrl #{t}sec #{controller.class.name}.#{action} (#{req.path_info})" if @profile_logger
547
+
548
+ values = controller.after_filter_return_value(values)
549
+
550
+ # result handling
551
+ result = if values.respond_to?(:command)
552
+ case values.command
553
+ when :delegate
554
+ inner_dispatch(req, values.param)
555
+ when :redirect
556
+ redirect(values.param)
557
+ when :notfound
558
+ display_notfound
559
+ end
560
+ elsif values.is_a?(Array)
561
+ values
562
+ elsif values.is_a?(String)
563
+ [200,{'Content-Type' => "text/html"},[values]]
564
+ elsif values.is_a?(Rack::Response)
565
+ values.to_a
566
+ elsif values == nil
567
+ raise "egalite error: controller returned nil as a response."
568
+ else
569
+ htmlfile = controller.template_file
570
+ unless htmlfile
571
+ htmlfile = [req.controller,req.action].compact.join('_')
572
+ htmlfile = 'index' if htmlfile.blank?
573
+ htmlfile += '.html'
574
+ end
575
+ html = load_template(@template_path + htmlfile)
576
+ return [404, {"Content-Type" => "text/plain"}, ["Template not found: #{htmlfile}\n"]] unless html
577
+
578
+ # apply on_html_load filter
579
+ html = controller.filter_on_html_load(html, htmlfile)
580
+
581
+ # apply html template
582
+ template = @template_engine.new
583
+ template.controller = controller
584
+
585
+ s = Time.now
586
+ template.handleTemplate(html,values) { |values|
587
+ inner_dispatch(req,values)[2]
588
+ }
589
+ t = Time.now - s
590
+ @profile_logger.puts "#{Time.now}: view #{t}sec #{controller.class.name}.#{action} (#{req.path_info})" if @profile_logger
591
+
592
+ [200,{"Content-Type"=>"text/html"},[html]]
593
+ end
594
+ set_cookies_to_response(result,req)
595
+ return result
596
+ end
597
+
598
+ def dispatch(path, params, method, req, first_call = false)
599
+ # routing
600
+ (controller_name, action_name, path_params, prmhash) = nil
601
+ (controller, action) = nil
602
+
603
+ route = @routes.find { |route|
604
+ puts "Routing: matching: #{route.inspect}" if RouteDebug
605
+ route_result = route.match(path)
606
+ (controller_name, action_name, path_params, prmhash) = route_result
607
+ next if route_result == nil
608
+ puts "Routing: pre-matched: #{route_result.inspect}" if RouteDebug
609
+ (controller, action) = get_controller(controller_name, action_name, method)
610
+ true if controller
611
+ }
612
+ return display_notfound unless controller
613
+
614
+ puts "Routing: matched: #{controller.class} #{action}" if RouteDebug
615
+ params = prmhash.merge(params)
616
+
617
+ req.route = route
618
+ req.controller = controller_name
619
+ req.controller_class = controller
620
+ req.action = action_name
621
+ req.action_method = action
622
+ req.path_params = path_params
623
+ req.path_info = path_params.join('/')
624
+
625
+ # todo: language handling (by pathinfo?)
626
+ # todo: session handling (by pathinfo?)
627
+
628
+ res = run_controller(controller, action, req)
629
+
630
+ if first_call
631
+ controller.after_filter(res.to_a)
632
+
633
+ # access log
634
+ t = Time.now - req.time
635
+ log = [req.time.iso8601, req.ipaddr, t, req.url, req.referrer]
636
+ log += controller.log_values.to_a
637
+ line = log.map {|s| s.to_s.gsub(/\t/,'')}.join("\t").gsub(/\n/,'')
638
+ AccessLogger.write(line)
639
+ end
640
+ res
641
+ end
642
+
643
+ def call(rack_env)
644
+ # set up logging
645
+
646
+ res = nil
647
+
648
+ req = Rack::Request.new(rack_env)
649
+
650
+ begin
651
+ ereq = Request.new(
652
+ :rack_request => req,
653
+ :rack_env => rack_env,
654
+ :handler => self
655
+ )
656
+
657
+ # parameter handling
658
+ params = StringifyHash.new
659
+ req.params.each { |k,v|
660
+ # raise 'egalite: no multiple query parameter allowed in same keyword.' if v.is_a?(Array)
661
+ next unless k
662
+ frags = k.split(/[\]\[]{1,2}/)
663
+ last = frags.pop
664
+ list = params
665
+ frags.each { |frag|
666
+ list[frag] ||= StringifyHash.new
667
+ list = list[frag]
668
+ }
669
+ list[last] = v
670
+ }
671
+
672
+ puts "before-cookie: #{req.cookies.inspect}" if @opts[:cookie_debug]
673
+
674
+ ereq.params = params
675
+ ereq.cookies = req.cookies
676
+
677
+ authorization_keys = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']
678
+ key = authorization_keys.detect { |key| rack_env.has_key?(key) }
679
+ ereq.authorization = rack_env[key] if key
680
+
681
+ if @opts[:session_handler]
682
+ ereq.session = @opts[:session_handler].new(@env,ereq.cookies, @opts[:session_opts] || {})
683
+ ereq.session.load
684
+ end
685
+
686
+ res = dispatch(req.path_info, params, req.request_method, ereq, true)
687
+ res = res.to_a
688
+
689
+ puts "after-cookie: #{res[1]['Set-Cookie'].inspect}" if @opts[:cookie_debug]
690
+
691
+ if res[0] == 200
692
+ if res[1]['Content-Type'] !~ /charset/i and res[1]['Content-Type'] =~ /text\/html/i
693
+ res[1]["Content-Type"] = @opts[:charset] || 'text/html; charset=utf-8'
694
+ end
695
+ end
696
+
697
+ rescue Exception => e
698
+ raise e if $raise_exception
699
+
700
+ begin
701
+ # write error log
702
+ logid = nil
703
+ if @exception_log_table
704
+ logid = ErrorLogger.write_exception(e,{:ipaddress => req.ip, :url => req.url})
705
+ end
706
+
707
+ # show exception
708
+
709
+ if @error_template
710
+ values = {}
711
+ values[:logid] = logid if logid
712
+ values[:exception] = e.to_s
713
+ values[:backtrace] = e.backtrace
714
+ html = @template_engine.new.handleTemplate(@error_template.dup,values)
715
+ res = [500, {"Content-type"=>"text/html; charset=utf-8"}, [html]]
716
+ else
717
+ res = display_internal_server_error(e)
718
+ end
719
+ rescue Exception => e2
720
+ res = display_internal_server_error(e2)
721
+ end
722
+ end
723
+
724
+ res = res.to_a
725
+ p res if @opts[:response_debug]
726
+ res
727
+ end
728
+ end
729
+
730
+ end # module end
731
+
732
+ class StaticController < Egalite::Controller
733
+ def get
734
+ raise SecurityError unless env.opts[:static_root]
735
+
736
+ path = req.path_info
737
+ path.gsub!(/[^0-9a-zA-Z\(\)\. \/_\-]/,'')
738
+ if path.include?("..") or path =~ /^\//
739
+ return [403, {"Content-Type" => "text/plain"}, ["Forbidden\n"]]
740
+ end
741
+ path = File.join(env.opts[:static_root], path)
742
+ send_file(path)
743
+ end
744
+ end