sbsm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/COPYING +515 -0
  2. data/History.txt +5 -0
  3. data/Manifest.txt +49 -0
  4. data/README.txt +41 -0
  5. data/Rakefile +28 -0
  6. data/data/_flavored_uri.grammar +24 -0
  7. data/data/_uri.grammar +22 -0
  8. data/data/_zone_uri.grammar +24 -0
  9. data/data/flavored_uri.grammar +24 -0
  10. data/data/uri.grammar +22 -0
  11. data/data/zone_uri.grammar +24 -0
  12. data/install.rb +1098 -0
  13. data/lib/cgi/drbsession.rb +37 -0
  14. data/lib/sbsm/cgi.rb +79 -0
  15. data/lib/sbsm/drb.rb +19 -0
  16. data/lib/sbsm/drbserver.rb +162 -0
  17. data/lib/sbsm/exception.rb +28 -0
  18. data/lib/sbsm/flavored_uri_parser.rb +47 -0
  19. data/lib/sbsm/index.rb +66 -0
  20. data/lib/sbsm/lookandfeel.rb +176 -0
  21. data/lib/sbsm/lookandfeelfactory.rb +50 -0
  22. data/lib/sbsm/lookandfeelwrapper.rb +109 -0
  23. data/lib/sbsm/redefine_19_cookie.rb +4 -0
  24. data/lib/sbsm/redirector.rb +37 -0
  25. data/lib/sbsm/request.rb +162 -0
  26. data/lib/sbsm/session.rb +542 -0
  27. data/lib/sbsm/state.rb +301 -0
  28. data/lib/sbsm/time.rb +29 -0
  29. data/lib/sbsm/trans_handler.rb +119 -0
  30. data/lib/sbsm/turing.rb +25 -0
  31. data/lib/sbsm/uri_parser.rb +45 -0
  32. data/lib/sbsm/user.rb +47 -0
  33. data/lib/sbsm/validator.rb +256 -0
  34. data/lib/sbsm/viralstate.rb +47 -0
  35. data/lib/sbsm/zone_uri_parser.rb +48 -0
  36. data/test/data/dos_file.txt +2 -0
  37. data/test/data/lnf_file.txt +2 -0
  38. data/test/data/mac_file.txt +1 -0
  39. data/test/stub/cgi.rb +35 -0
  40. data/test/suite.rb +29 -0
  41. data/test/test_drbserver.rb +83 -0
  42. data/test/test_index.rb +90 -0
  43. data/test/test_lookandfeel.rb +230 -0
  44. data/test/test_session.rb +372 -0
  45. data/test/test_state.rb +176 -0
  46. data/test/test_trans_handler.rb +447 -0
  47. data/test/test_user.rb +44 -0
  48. data/test/test_validator.rb +126 -0
  49. data/usage-en.txt +112 -0
  50. metadata +142 -0
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # State Based Session Management
4
+ # Copyright (C) 2004 Hannes Wyss
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Z�rich, Switzerland
21
+ # hwyss@ywesee.com
22
+ #
23
+ # Lookandfeel -- sbsm -- hwyss@ywesee.com
24
+
25
+ require 'sbsm/time'
26
+ require 'cgi'
27
+
28
+ module SBSM
29
+ class Lookandfeel
30
+ attr_reader :language, :flavor, :session
31
+ DICTIONARIES = {}
32
+ DISABLED = []
33
+ ENABLED = []
34
+ HTML_ATTRIBUTES = {}
35
+ RESOURCES = {}
36
+ RESOURCE_BASE = "resources"
37
+ TXT_RESOURCES = "/resources"
38
+ class << self
39
+ def txt_file(filename)
40
+ Proc.new {
41
+ path = File.expand_path(filename, self::TXT_RESOURCES)
42
+ File.read(path).strip.gsub(/(\r\n)|(\n)|(\r)/, '<br>')
43
+ }
44
+ end
45
+ end
46
+ def initialize(session)
47
+ @session = session
48
+ @flavor = @session.flavor
49
+ @language = @session.language
50
+ set_dictionary(@language)
51
+ end
52
+ def attributes(key)
53
+ self::class::HTML_ATTRIBUTES.fetch(key.to_sym, {}).dup rescue {}
54
+ end
55
+ def base_url
56
+ [@session.http_protocol + ':/', @session.server_name, @language, @flavor].compact.join("/")
57
+ end
58
+ def direct_event
59
+ @session.direct_event
60
+ end
61
+ def disabled?(event)
62
+ self::class::DISABLED.include?(event)
63
+ end
64
+ def enabled?(event, default=true)
65
+ default || self::class::ENABLED.include?(event)
66
+ end
67
+ def event_url(event=direct_event, args={}, anchor=nil)
68
+ _event_url(event, args, anchor=nil) { |args|
69
+ unless(@session.is_crawler? || args.include?('state_id'))
70
+ args.unshift(:state_id, @session.state.object_id)
71
+ end
72
+ }
73
+ end
74
+ def _event_url(event=direct_event, args={}, anchor=nil, &block)
75
+ args = args.collect { |*pair| pair }.flatten
76
+ args = args.collect { |value| CGI.escape(value.to_s) }
77
+ if(block_given?)
78
+ yield(args)
79
+ end
80
+ url = [base_url(), event, args].compact.join('/')
81
+ if(anchor)
82
+ url << "#" << anchor.to_s
83
+ end
84
+ url
85
+ end
86
+ def languages
87
+ @languages ||= self::class::DICTIONARIES.keys.sort
88
+ end
89
+ def language_url(language)
90
+ [@session.http_protocol + ':/', @session.server_name, language, @flavor].compact.join("/")
91
+ end
92
+ def lookup(key, *args, &block)
93
+ _lookup(key, *args) || (block.call if block)
94
+ end
95
+ def _lookup(key, *args)
96
+ key = key.intern if key.is_a? String
97
+ if(args.size > 0)
98
+ result = ""
99
+ args.each_with_index { |text, index|
100
+ result << (lookup(key.to_s + index.to_s) || ' ')
101
+ result << text.to_s
102
+ }
103
+ tail = lookup(key.to_s + args.size.to_s)
104
+ result << tail if(tail)
105
+ else
106
+ result = @dictionary[key] if @dictionary
107
+ if(result.is_a? Proc)
108
+ result.call
109
+ elsif(result.nil?)
110
+ def_lan = @session.default_language
111
+ if(dict = self::class::DICTIONARIES[def_lan])
112
+ dict[key]
113
+ end
114
+ else
115
+ result
116
+ end
117
+ end
118
+ end
119
+ def format_date(date)
120
+ date.strftime(lookup(:date_format))
121
+ end
122
+ def format_price(price, currency=nil)
123
+ if(price.to_i > 0)
124
+ [currency, sprintf('%.2f', price.to_f/100.0)].compact.join(' ')
125
+ end
126
+ end
127
+ def format_time(time)
128
+ time.strftime(lookup(:time_format))
129
+ end
130
+ def navigation(filter=false)
131
+ @session.navigation
132
+ end
133
+ def resource(rname, rstr=nil)
134
+ collect_resource([ self::class::RESOURCE_BASE, @session.flavor ],
135
+ rname, rstr)
136
+ end
137
+ def resource_external(rname)
138
+ self::class::RESOURCES[rname]
139
+ end
140
+ def resource_global(rname, rstr=nil)
141
+ collect_resource(self::class::RESOURCE_BASE, rname, rstr)
142
+ end
143
+ def resource_localized(rname, rstr=nil, lang=@language)
144
+ result = resource([rname, lang].join('_').intern, rstr)
145
+ if(result.nil? && (lang != @session.default_language))
146
+ result = resource_localized(rname, rstr, @session.default_language)
147
+ end
148
+ result
149
+ end
150
+ def zone_navigation(filter=false)
151
+ @session.zone_navigation
152
+ end
153
+ def zones(filter=false)
154
+ @session.zones
155
+ end
156
+ private
157
+ def collect_resource(base, rname, rstr=nil)
158
+ varpart = self::class::RESOURCES[rname]
159
+ if(varpart.is_a?(Array))
160
+ varpart.collect { |part|
161
+ _collect_resource(base, part, rstr)
162
+ }
163
+ elsif(!varpart.nil?)
164
+ _collect_resource(base, varpart, rstr)
165
+ end
166
+ end
167
+ def _collect_resource(base, part, rstr)
168
+ [ @session.http_protocol + ':/',
169
+ @session.server_name,
170
+ base, part, rstr].flatten.compact.join('/')
171
+ end
172
+ def set_dictionary(language)
173
+ @dictionary = self::class::DICTIONARIES[language] || {}
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # State Based Session Management
4
+ # Copyright (C) 2004 Hannes Wyss
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Z�rich, Switzerland
21
+ # hwyss@ywesee.com
22
+ #
23
+ # LookandfeelFactory -- sbsm -- hwyss@ywesee.com
24
+
25
+ require 'sbsm/lookandfeel'
26
+
27
+ module SBSM
28
+ class LookandfeelFactory
29
+ WRAPPERS = {}
30
+ BASE = Lookandfeel
31
+ class << self
32
+ def create(session)
33
+ lnf = self::BASE.new(session)
34
+ if(wrappers = self::WRAPPERS[session.flavor])
35
+ lnf = wrappers.inject(lnf) { |lnf, klass|
36
+ klass.new(lnf)
37
+ }
38
+ end
39
+ lnf
40
+ rescue StandardError => e
41
+ puts e.class
42
+ puts e.message
43
+ puts e.backtrace
44
+ end
45
+ def include?(str)
46
+ self::WRAPPERS.include?(str)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # State Based Session Management
4
+ # Copyright (C) 2004 Hannes Wyss
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Z�rich, Switzerland
21
+ # hwyss@ywesee.com
22
+ #
23
+ # LookandfeelWrapper -- sbsm -- hwyss@ywesee.com
24
+
25
+ require "sbsm/lookandfeel"
26
+
27
+ module SBSM
28
+ class LookandfeelWrapper < Lookandfeel
29
+ def initialize(component)
30
+ @component = component
31
+ super(@component.session)
32
+ end
33
+ def method_missing(symbol, *args, &block)
34
+ @component.send(symbol, *args, &block)
35
+ end
36
+ def attributes(key)
37
+ self::class::HTML_ATTRIBUTES.fetch(key.to_sym) {
38
+ @component.attributes(key)
39
+ }
40
+ end
41
+ def disabled?(event)
42
+ self::class::DISABLED.include?(event) \
43
+ || @component.disabled?(event)
44
+ end
45
+ def enabled?(event, default=false)
46
+ self::class::ENABLED.include?(event) \
47
+ || @component.enabled?(event, default)
48
+ end
49
+ def languages
50
+ unless(@languages)
51
+ super
52
+ if(@languages.empty?)
53
+ @languages = @component.languages
54
+ end
55
+ end
56
+ @languages
57
+ end
58
+ def lookup(key, *args, &block)
59
+ _lookup(key, *args) || @component.lookup(key, *args, &block)
60
+ end
61
+ def navigation(filter=true)
62
+ nav = @component.navigation(false)
63
+ if(filter)
64
+ nav.select { |item|
65
+ key = (item.is_a? Symbol) ? item : item.direct_event
66
+ enabled?(key)
67
+ }
68
+ else
69
+ nav
70
+ end
71
+ end
72
+ def resource(rname, rstr=nil)
73
+ if(self::class::RESOURCES.include?(rname))
74
+ super
75
+ else
76
+ @component.resource(rname, rstr)
77
+ end
78
+ end
79
+ def resource_global(rname, rstr=nil)
80
+ if(self::class::RESOURCES.include?(rname))
81
+ super
82
+ else
83
+ @component.resource_global(rname, rstr)
84
+ end
85
+ end
86
+ def zone_navigation(filter=true)
87
+ nav = @component.zone_navigation(false)
88
+ if(filter)
89
+ nav.select { |item|
90
+ key = (item.is_a? Symbol) ? item : item.direct_event
91
+ enabled?(key)
92
+ }
93
+ else
94
+ nav
95
+ end
96
+ end
97
+ def zones(filter=true)
98
+ nav = @component.zones(false)
99
+ if(filter)
100
+ nav.select { |item|
101
+ key = (item.is_a? Symbol) ? item : item.direct_event
102
+ enabled?(key)
103
+ }
104
+ else
105
+ nav
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,4 @@
1
+ #class CGI
2
+ # remove_const 'Cookie'
3
+ #end
4
+ #load '/usr/lib/ruby19/1.9.1/cgi/cookie.rb'
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ # Redirector -- sbsm -- 02.11.2006 -- hwyss@ywesee.com
3
+
4
+ module SBSM
5
+ module Redirector
6
+ def http_headers
7
+ if(redirect?)
8
+ @redirected = @state.redirected = true
9
+ event, *args = @state.direct_event
10
+ if(args.first.is_a? Hash)
11
+ args = args.first
12
+ end
13
+ {
14
+ "Location" => lookandfeel._event_url(event, args || {}),
15
+ }
16
+ else
17
+ @redirected = @state.redirected = false
18
+ super
19
+ end
20
+ end
21
+ def redirect?
22
+ direct = @state.direct_event
23
+ if(direct.is_a?(Array))
24
+ direct = direct.first
25
+ end
26
+ direct && (@request_method != 'GET' \
27
+ || ![direct, :sort].include?(event))
28
+ end
29
+ def to_html
30
+ if(redirect?)
31
+ ''
32
+ else
33
+ super
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # State Based Session Management
4
+ # Copyright (C) 2004 Hannes Wyss
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Z�rich, Switzerland
21
+ # hwyss@ywesee.com
22
+ #
23
+ # Request -- sbsm -- hwyss@ywesee.com
24
+
25
+ require 'sbsm/cgi'
26
+ require 'sbsm/drb'
27
+ require 'sbsm/redefine_19_cookie'
28
+ require 'cgi/session'
29
+ require 'cgi/drbsession'
30
+ require 'delegate'
31
+
32
+ module SBSM
33
+ class Request < SimpleDelegator
34
+ include DRbUndumped
35
+ CRAWLER_PATTERN = /archiver|slurp|bot|crawler|jeeves|spider|\.{6}/i
36
+ attr_reader :cgi
37
+ def initialize(drb_uri, html_version = "html4", cgiclass = CGI)
38
+ @cgi = cgiclass.new(html_version)
39
+ @drb_uri = drb_uri
40
+ @thread = nil
41
+ @request = Apache.request
42
+ super(@cgi)
43
+ end
44
+ def cookies
45
+ @cgi.cookies
46
+ end
47
+ def is_crawler?
48
+ !!CRAWLER_PATTERN.match(@cgi.user_agent)
49
+ end
50
+ def passthru(path, disposition='attachment')
51
+ @passthru = path
52
+ @disposition = disposition
53
+ ''
54
+ end
55
+ def process
56
+ begin
57
+ @cgi.params.store('default_flavor', ENV['DEFAULT_FLAVOR'])
58
+ @request.notes.each { |key, val|
59
+ @cgi.params.store(key, val)
60
+ }
61
+ drb_process()
62
+ #drb_request()
63
+ #drb_response()
64
+ rescue StandardError => e
65
+ handle_exception(e)
66
+ ensure
67
+ @session.close if @session.respond_to?(:close)
68
+ end
69
+ end
70
+ def remote_host(lookup_type=Apache::REMOTE_NOLOOKUP)
71
+ @request.remote_host(lookup_type)
72
+ end
73
+ def unparsed_uri
74
+ @request.unparsed_uri
75
+ end
76
+ private
77
+ def drb_process
78
+ args = {
79
+ 'database_manager' => CGI::Session::DRbSession,
80
+ 'drbsession_uri' => @drb_uri,
81
+ 'session_path' => '/',
82
+ }
83
+ if(is_crawler?)
84
+ sleep 0.5
85
+ sid = [ENV['DEFAULT_FLAVOR'], @cgi.params['language'], @cgi.user_agent].join('-')
86
+ args.store('session_id', sid)
87
+ end
88
+ @session = CGI::Session.new(@cgi, args)
89
+ @proxy = @session[:proxy]
90
+ res = @proxy.drb_process(self)
91
+ cookie_input = @proxy.cookie_input
92
+ # view.to_html can call passthru instead of sending data
93
+ if(@passthru)
94
+ unless(cookie_input.empty?)
95
+ cookie = generate_cookie(cookie_input)
96
+ @request.headers_out.add('Set-Cookie', cookie.to_s)
97
+ end
98
+ # the variable @passthru is set by a trusted source
99
+ basename = File.basename(@passthru)
100
+ fullpath = File.expand_path(@passthru,
101
+ @request.server.document_root)
102
+ fullpath.untaint
103
+ subreq = @request.lookup_file(fullpath)
104
+ @request.content_type = subreq.content_type
105
+ @request.headers_out.add('Content-Disposition',
106
+ "#@disposition; filename=#{basename}")
107
+ @request.headers_out.add('Content-Length',
108
+ File.size(fullpath).to_s)
109
+ begin
110
+ File.open(fullpath) { |fd| @request.send_fd(fd) }
111
+ rescue Errno::ENOENT, IOError => err
112
+ @request.log_reason(err.message, @passthru)
113
+ return Apache::NOT_FOUND
114
+ end
115
+ else
116
+ begin
117
+ headers = @proxy.http_headers
118
+ unless(cookie_input.empty?)
119
+ cookie = generate_cookie(cookie_input)
120
+ headers.store('Set-Cookie', [cookie])
121
+ end
122
+ @cgi.out(headers) {
123
+ (@cgi.params.has_key?("pretty")) ? CGI.pretty( res ) : res
124
+ }
125
+ rescue StandardError => e
126
+ handle_exception(e)
127
+ end
128
+ end
129
+ end
130
+ def generate_cookie(cookie_input)
131
+ cookie_pairs = cookie_input.collect { |pair|
132
+ pair.join('=')
133
+ }.join(';')
134
+ cookie_hash = {
135
+ "name" => @proxy.cookie_name || 'sbsm-persistent-cookie',
136
+ "value" => cookie_pairs,
137
+ "path" => "/",
138
+ "expires" => (Time.now + (60 * 60 * 24 * 365 * 10)),
139
+ }
140
+ CGI::Cookie.new(cookie_hash).to_s
141
+ end
142
+ def handle_exception(e)
143
+ if defined?(Apache)
144
+ msg = [
145
+ [Time.now, self.object_id].join(' - '),
146
+ e.class,
147
+ e.message,
148
+ ].join(" - ")
149
+ uri = unparsed_uri
150
+ @request.log_reason(msg, uri)
151
+ e.backtrace.each { |line|
152
+ @request.log_reason(line, uri)
153
+ }
154
+ end
155
+ hdrs = {
156
+ 'Status' => '302 Moved',
157
+ 'Location' => '/resources/errors/appdown.html',
158
+ }
159
+ @cgi.header(hdrs)
160
+ end
161
+ end
162
+ end