bijou 0.1.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.txt +4 -0
- data/LICENSE.txt +58 -0
- data/README.txt +48 -0
- data/Rakefile +105 -0
- data/doc/INSTALL.rdoc +260 -0
- data/doc/README.rdoc +314 -0
- data/doc/releases/bijou-0.1.0.rdoc +60 -0
- data/examples/birthday/birthday.rb +34 -0
- data/examples/holiday/holiday.rb +61 -0
- data/examples/holiday/letterhead.txt +4 -0
- data/examples/holiday/signature.txt +9 -0
- data/examples/phishing/letter.txt +29 -0
- data/examples/phishing/letterhead.txt +4 -0
- data/examples/phishing/phishing.rb +21 -0
- data/examples/phishing/signature.txt +9 -0
- data/examples/profile/profile.rb +46 -0
- data/lib/bijou.rb +15 -0
- data/lib/bijou/backend.rb +542 -0
- data/lib/bijou/cgi/adapter.rb +201 -0
- data/lib/bijou/cgi/handler.rb +5 -0
- data/lib/bijou/cgi/request.rb +37 -0
- data/lib/bijou/common.rb +12 -0
- data/lib/bijou/component.rb +108 -0
- data/lib/bijou/config.rb +60 -0
- data/lib/bijou/console/adapter.rb +167 -0
- data/lib/bijou/console/handler.rb +4 -0
- data/lib/bijou/console/request.rb +26 -0
- data/lib/bijou/context.rb +431 -0
- data/lib/bijou/diagnostics.rb +87 -0
- data/lib/bijou/errorformatter.rb +322 -0
- data/lib/bijou/exception.rb +39 -0
- data/lib/bijou/filters.rb +107 -0
- data/lib/bijou/httprequest.rb +108 -0
- data/lib/bijou/httpresponse.rb +268 -0
- data/lib/bijou/lexer.rb +513 -0
- data/lib/bijou/minicgi.rb +159 -0
- data/lib/bijou/parser.rb +1026 -0
- data/lib/bijou/processor.rb +404 -0
- data/lib/bijou/prstringio.rb +400 -0
- data/lib/bijou/webrick/adapter.rb +174 -0
- data/lib/bijou/webrick/handler.rb +32 -0
- data/lib/bijou/webrick/request.rb +45 -0
- data/script/cgi.rb +25 -0
- data/script/console.rb +7 -0
- data/script/server.rb +7 -0
- data/test/t1.cfg +5 -0
- data/test/tc_config.rb +26 -0
- data/test/tc_filter.rb +25 -0
- data/test/tc_lexer.rb +120 -0
- data/test/tc_response.rb +103 -0
- data/test/tc_ruby.rb +62 -0
- data/test/tc_stack.rb +50 -0
- metadata +121 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
|
2
|
+
require 'cgi'
|
3
|
+
require 'bijou/processor'
|
4
|
+
require 'bijou/httpresponse'
|
5
|
+
require 'bijou/webrick/request'
|
6
|
+
|
7
|
+
module Bijou
|
8
|
+
#
|
9
|
+
# This module allows Bijou to run under the WEBrick server.
|
10
|
+
#
|
11
|
+
module WEBrick
|
12
|
+
#
|
13
|
+
# This adapter encapsulates the differences between the WEBrick server and
|
14
|
+
# the interfaces expected within the Bijou environment.
|
15
|
+
#
|
16
|
+
class Bijou::WEBrick::Adapter
|
17
|
+
def self.handle(req, res)
|
18
|
+
bijou_types =
|
19
|
+
[
|
20
|
+
[ 'rbb', 'text/html' ],
|
21
|
+
[ 'htm', 'text/html' ],
|
22
|
+
[ 'html', 'text/html' ],
|
23
|
+
]
|
24
|
+
|
25
|
+
path_info = req.path
|
26
|
+
document_root = ENV['DOCUMENT_ROOT']
|
27
|
+
bijou_cache = ENV['BIJOU_CACHE']
|
28
|
+
bijou_config = ENV['BIJOU_CONFIG']
|
29
|
+
|
30
|
+
if bijou_config
|
31
|
+
begin
|
32
|
+
config = Bijou::Config.load_file(bijou_config)
|
33
|
+
rescue SyntaxError
|
34
|
+
error = $!.to_s
|
35
|
+
error << "\nStack: " + $@.join("\n")
|
36
|
+
|
37
|
+
return self::diagnostic(res, "Error",
|
38
|
+
"Error loading configuration.", error)
|
39
|
+
end
|
40
|
+
|
41
|
+
if (!config)
|
42
|
+
return self.error(res, 200, "Error",
|
43
|
+
"The configuration file path is invalid." +
|
44
|
+
" Please check the WEbrick configuration.")
|
45
|
+
end
|
46
|
+
else
|
47
|
+
config = Bijou::Config.new
|
48
|
+
end
|
49
|
+
|
50
|
+
# The config file overrides the environment settings.
|
51
|
+
if !config.document_root || config.document_root.empty?
|
52
|
+
if document_root
|
53
|
+
config.document_root = document_root
|
54
|
+
else
|
55
|
+
config.document_root = Dir.getwd
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if !config.cache_root && bijou_cache
|
60
|
+
config.cache_root = bijou_cache
|
61
|
+
end
|
62
|
+
|
63
|
+
config.includes.each do |inc|
|
64
|
+
$:.push inc
|
65
|
+
end
|
66
|
+
|
67
|
+
# Remove any leading slashes so expand_path doesn't see it as absolute.
|
68
|
+
if path_info[0,1] == '/'
|
69
|
+
path_info = path_info[1..-1]
|
70
|
+
end
|
71
|
+
|
72
|
+
found = false
|
73
|
+
bijou_types.each {|type|
|
74
|
+
ext = type[0]
|
75
|
+
if path_info =~ /\.#{ext}$/
|
76
|
+
found = true
|
77
|
+
end
|
78
|
+
}
|
79
|
+
|
80
|
+
if !found
|
81
|
+
response = Bijou::Processor.handle_other(config, path_info)
|
82
|
+
|
83
|
+
res.status = response['status']
|
84
|
+
res['Content-Type'] = response['type']
|
85
|
+
res.body = response['body']
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
processor = Bijou::Processor.new
|
90
|
+
|
91
|
+
# Build the page from the request.
|
92
|
+
begin
|
93
|
+
context = processor.load(path_info, config)
|
94
|
+
rescue Exception
|
95
|
+
msg = Bijou::ErrorFormatter.format_error :html, 4
|
96
|
+
return self.formatted_error(res, "Error loading page", msg)
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Prepare the request data.
|
101
|
+
#
|
102
|
+
|
103
|
+
context.request = Bijou::WEBrick::Request.new(req)
|
104
|
+
context.response = HttpResponse.new
|
105
|
+
|
106
|
+
args = {}
|
107
|
+
args.replace(context.request.params);
|
108
|
+
|
109
|
+
begin
|
110
|
+
context.render(args)
|
111
|
+
rescue Exception
|
112
|
+
msg = Bijou::ErrorFormatter.format_error :html, 4, context
|
113
|
+
return self.formatted_error(res, "Error rendering page", msg)
|
114
|
+
end
|
115
|
+
|
116
|
+
res.status = 200
|
117
|
+
res['Content-Type'] = "text/html"
|
118
|
+
res.body = context.output;
|
119
|
+
|
120
|
+
# print_environment cgi
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def self.error(res, num, title, message)
|
126
|
+
res.status = num
|
127
|
+
res['Content-Type'] = "text/html"
|
128
|
+
res.body = "<html>" +
|
129
|
+
"<h1>#{num} #{title}</h1>" +
|
130
|
+
"<p>#{message}</p>" +
|
131
|
+
"</html>"
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.diagnostic(res, title, message, diagnostic)
|
135
|
+
# 'charset' => 'iso-8859-1',
|
136
|
+
res.status = 200
|
137
|
+
res['Content-Type'] = "text/html"
|
138
|
+
res.body = "<html>" +
|
139
|
+
"<h1>#{title}</h1>" +
|
140
|
+
"<p>#{message}</p>" +
|
141
|
+
"<pre>#{::CGI::escapeHTML(diagnostic)}</pre>" +
|
142
|
+
"</html>"
|
143
|
+
return nil
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.formatted_error(res, title, message)
|
147
|
+
res.status = 200
|
148
|
+
res['Content-Type'] = "text/html"
|
149
|
+
res.body = "<html>" +
|
150
|
+
'<head><title>Bijou Error</title></head>' +
|
151
|
+
"<h1>#{title}</h1>" +
|
152
|
+
message +
|
153
|
+
'</html>'
|
154
|
+
return nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.print_environment
|
158
|
+
# print "Content-type: text/html; charset=iso-8859-1\n\n"
|
159
|
+
# print "Hello, world!"
|
160
|
+
# puts $:
|
161
|
+
|
162
|
+
print "<pre>" +
|
163
|
+
::CGI::escapeHTML(
|
164
|
+
"params: " + cgi.params.inspect + "\n" +
|
165
|
+
"cookies: " + cgi.cookies.inspect + "\n" +
|
166
|
+
ENV.collect() do |key, value|
|
167
|
+
key + " --> " + value + "\n"
|
168
|
+
end.join("")
|
169
|
+
) +
|
170
|
+
"<pre>"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
require 'webrick'
|
3
|
+
require 'bijou/webrick/adapter'
|
4
|
+
|
5
|
+
include WEBrick
|
6
|
+
|
7
|
+
s = HTTPServer.new( :Port => 2000 )
|
8
|
+
|
9
|
+
#
|
10
|
+
# A basic WEBrick servlet to get started with Bijou. This servlet can be
|
11
|
+
# started by running 'ruby script/server.rb' on the local machine.
|
12
|
+
#
|
13
|
+
# Note that it does not support the POST method, so any forms must specifiy
|
14
|
+
# the attribute method="GET" or leave it unspecified (as the default is GET).
|
15
|
+
#
|
16
|
+
class Bijou::WEBrick::Servlet < HTTPServlet::AbstractServlet
|
17
|
+
# The GET handler dispatches incoming requests to the Bijou::WEBrick::Adapter
|
18
|
+
# class.
|
19
|
+
def do_GET(request, response)
|
20
|
+
servlet = Bijou::WEBrick::Adapter.handle(request, response)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# When a request beginning with '/' is received, the HTTPServer creates an
|
26
|
+
# instance of BijouServlet and calls do_[method]
|
27
|
+
#
|
28
|
+
s.mount("/", Bijou::WEBrick::Servlet)
|
29
|
+
|
30
|
+
trap("INT"){ s.shutdown }
|
31
|
+
|
32
|
+
s.start
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
require 'bijou/minicgi'
|
3
|
+
require 'bijou/httprequest'
|
4
|
+
|
5
|
+
module Bijou
|
6
|
+
module WEBrick
|
7
|
+
class Request < Bijou::HttpRequest
|
8
|
+
#
|
9
|
+
# Accepts a WEBrick::HTTPRequest object and adapts it to the HttpRequest
|
10
|
+
# object expected by the Bijou component.
|
11
|
+
#
|
12
|
+
def initialize(req)
|
13
|
+
super()
|
14
|
+
|
15
|
+
@req = req
|
16
|
+
|
17
|
+
if @req.query_string
|
18
|
+
query_string = ::CGI::parse(@req.query_string) || {}
|
19
|
+
@query_string = Bijou::MiniCGI.singularize(query_string)
|
20
|
+
else
|
21
|
+
@query_string = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
@form = @query_string.clone
|
25
|
+
@params = @query_string.clone
|
26
|
+
|
27
|
+
#cookies = ::CGI::Cookie::parse(@req.cookies)
|
28
|
+
@cookies = @req.cookies
|
29
|
+
|
30
|
+
@http_method = @req.request_method
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :req
|
34
|
+
|
35
|
+
#--
|
36
|
+
# TODO: Standardize accessor name.
|
37
|
+
#++
|
38
|
+
def virtual_path
|
39
|
+
# @server_variables['REQUEST_URI']
|
40
|
+
# @server_variables['PATH_INFO']
|
41
|
+
@req.request_uri
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/script/cgi.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
#
|
3
|
+
# The following comment was taken and adapted from the Apache config file:
|
4
|
+
#
|
5
|
+
# Apache parses all CGI scripts for the shebang line by default.
|
6
|
+
# This comment line, the first line of the script, consists of the symbols
|
7
|
+
# pound (#) and exclamation (!) followed by the path of the program that
|
8
|
+
# can execute this specific script. For a Ruby script, with ruby.exe in
|
9
|
+
# the C:\Program Files\Ruby directory, the shebang line should be:
|
10
|
+
#
|
11
|
+
#!c:/program files/ruby/bin/ruby
|
12
|
+
#
|
13
|
+
# Note you _must_not_ indent the actual shebang line, and it must be the
|
14
|
+
# first line of the file. Of course, CGI processing must be enabled by
|
15
|
+
# the appropriate ScriptAlias or Options ExecCGI directives for the files
|
16
|
+
# or directory in question.
|
17
|
+
#
|
18
|
+
# See doc/INSTALL.rdoc for more information regarding Apache configuration.
|
19
|
+
#
|
20
|
+
$:.push '../lib'
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'bijou'
|
24
|
+
|
25
|
+
load 'bijou/cgi/handler.rb'
|
data/script/console.rb
ADDED
data/script/server.rb
ADDED
data/test/t1.cfg
ADDED
data/test/tc_config.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
$:.push '../lib'
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'bijou/config'
|
6
|
+
|
7
|
+
class ConfigTestCase < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_basic
|
15
|
+
file = File.expand_path('t1.cfg', File.dirname(__FILE__))
|
16
|
+
|
17
|
+
cfg = Bijou::Config.load_file(file)
|
18
|
+
|
19
|
+
assert cfg
|
20
|
+
assert cfg.document_root == '../web'
|
21
|
+
assert cfg.cache_root == '../web_cache'
|
22
|
+
assert cfg.debug == true
|
23
|
+
assert cfg.trace_level == Bijou::Log::Info
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/test/tc_filter.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
$:.push '../lib'
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'bijou/filters'
|
6
|
+
|
7
|
+
class FilterTestCase < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
end
|
13
|
+
|
14
|
+
# Ensure attibute values are escaped as expected.
|
15
|
+
def test_attribute_value
|
16
|
+
assert_equal Bijou::EncodeAttributeValue.apply("'"), '''
|
17
|
+
assert_equal Bijou::EncodeAttributeValue.apply('"'), '"'
|
18
|
+
assert_equal Bijou::EncodeAttributeValue.apply('<'), '<'
|
19
|
+
assert_equal Bijou::EncodeAttributeValue.apply('&'), '&'
|
20
|
+
assert_equal Bijou::EncodeAttributeValue.apply('<&\'"'),
|
21
|
+
'<&'"'
|
22
|
+
assert_equal Bijou::EncodeAttributeValue.apply('a<bc& \'" '),
|
23
|
+
'a<bc& '" '
|
24
|
+
end
|
25
|
+
end
|
data/test/tc_lexer.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
|
2
|
+
$:.push '../lib'
|
3
|
+
#$:.push File.expand_path(File.dirname(__FILE__) + '/..')
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'bijou/lexer'
|
7
|
+
|
8
|
+
#--
|
9
|
+
# Use stringio, if available. Otherwise, use the alternative.
|
10
|
+
#++
|
11
|
+
begin
|
12
|
+
require 'stringio'
|
13
|
+
rescue LoadError
|
14
|
+
require 'bijou/prstringio'
|
15
|
+
|
16
|
+
class StringIO < PureRubyStringIO
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module LexerHelp
|
21
|
+
#
|
22
|
+
# Utility methods
|
23
|
+
#
|
24
|
+
|
25
|
+
def open_input(str)
|
26
|
+
file = StringIO.new(str)
|
27
|
+
diagnostics = Bijou::Parse::Diagnostics.new
|
28
|
+
input = Bijou::Parse::LexerInput.new(file, diagnostics)
|
29
|
+
return input
|
30
|
+
end
|
31
|
+
|
32
|
+
def scan_top(str)
|
33
|
+
input = open_input(str)
|
34
|
+
return Bijou::Parse::TextLexer.new(input)
|
35
|
+
end
|
36
|
+
|
37
|
+
def scan_tags(str)
|
38
|
+
input = open_input(str)
|
39
|
+
return Bijou::Parse::TagLexer.new(input)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class TopTestCase < Test::Unit::TestCase
|
45
|
+
include LexerHelp
|
46
|
+
include Bijou::Parse
|
47
|
+
|
48
|
+
def setup
|
49
|
+
end
|
50
|
+
|
51
|
+
def teardown
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Utility methods
|
56
|
+
#
|
57
|
+
|
58
|
+
#
|
59
|
+
# Test methods
|
60
|
+
#
|
61
|
+
|
62
|
+
def test_empty
|
63
|
+
lexer = scan_top("")
|
64
|
+
assert_equal(nil, lexer.next_token)
|
65
|
+
lexer.input.close
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_opentokens
|
69
|
+
lexer = scan_top("<")
|
70
|
+
assert lexer.next_token == Token::Char && lexer.text == '<'
|
71
|
+
assert lexer.next_token == nil
|
72
|
+
lexer.input.close
|
73
|
+
|
74
|
+
lexer = scan_top("=")
|
75
|
+
assert lexer.next_token == Token::Char && lexer.text == '='
|
76
|
+
assert lexer.next_token == nil
|
77
|
+
lexer.input.close
|
78
|
+
|
79
|
+
lexer = scan_top("=")
|
80
|
+
lexer.tokenize_arguments = true
|
81
|
+
assert lexer.next_token == Token::Char && lexer.text == '='
|
82
|
+
assert lexer.next_token == nil
|
83
|
+
lexer.input.close
|
84
|
+
|
85
|
+
lexer = scan_top("'")
|
86
|
+
assert lexer.next_token == Token::Char && lexer.text == "'"
|
87
|
+
assert lexer.next_token == nil
|
88
|
+
lexer.input.close
|
89
|
+
end
|
90
|
+
|
91
|
+
def scan_unterminated_string(str)
|
92
|
+
lexer = scan_top(str)
|
93
|
+
lexer.tokenize_arguments = true
|
94
|
+
assert_equal nil, lexer.next_token
|
95
|
+
assert lexer.warnings.length == 1 &&
|
96
|
+
lexer.warnings[0].text =~ /unterminated string literal/,
|
97
|
+
'unterminated string literal'
|
98
|
+
lexer.input.close
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_unterminated_string
|
102
|
+
scan_unterminated_string('"')
|
103
|
+
scan_unterminated_string('" ')
|
104
|
+
scan_unterminated_string("' ")
|
105
|
+
scan_unterminated_string("'\n")
|
106
|
+
scan_unterminated_string("' \n")
|
107
|
+
scan_unterminated_string("'\n ")
|
108
|
+
scan_unterminated_string("' \n ")
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_basic
|
112
|
+
lexer = scan_top("<")
|
113
|
+
|
114
|
+
while tok = lexer.next_token
|
115
|
+
puts "tok: #{tok} #{lexer.text}"
|
116
|
+
end
|
117
|
+
|
118
|
+
lexer.input.close
|
119
|
+
end
|
120
|
+
end
|