cgi-exception 0.1.0 → 0.2.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/CHANGES.txt +19 -0
- data/README.txt +17 -8
- data/lib/cgi_exception.rb +92 -12
- data/test/test_cgi_exception.rb +163 -0
- metadata +42 -33
data/CHANGES.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= CHANGES
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
== Release 0.2.0 (2008-02-21)
|
6
|
+
|
7
|
+
=== Enhancements
|
8
|
+
|
9
|
+
* mod_ruby support
|
10
|
+
|
11
|
+
* detect whether HTTP header printed or not
|
12
|
+
|
13
|
+
* omit lines when Exception backtrace is too long
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
== Release 0.1.0
|
18
|
+
|
19
|
+
* first public release
|
data/README.txt
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
= README.txt
|
2
2
|
|
3
|
-
Release: 0.
|
3
|
+
Release: 0.2.0
|
4
4
|
|
5
|
-
copyright(c) 2007 kuwata-lab.com all rights reserved.
|
5
|
+
copyright(c) 2007-2008 kuwata-lab.com all rights reserved.
|
6
|
+
|
7
|
+
http://rubyforge.org/projects/cgi-exception/
|
6
8
|
|
7
9
|
|
8
10
|
== About
|
9
11
|
|
10
|
-
'cgi_exception.rb' is a
|
12
|
+
'cgi_exception.rb' is a small script to show exception raised in your
|
11
13
|
CGI script into browser, like PHP. You don't need to look for error
|
12
14
|
messages in Web server's log file.
|
13
15
|
|
16
|
+
NOTICE: cig_exception.rb works only with CGI or mod_ruby. It doesn't
|
17
|
+
support FastCGI.
|
18
|
+
|
14
19
|
|
15
20
|
== Install
|
16
21
|
|
@@ -19,7 +24,11 @@ with administrator priviledge.
|
|
19
24
|
|
20
25
|
Or, just type 'ruby setup.rb' with administrator priviledge.
|
21
26
|
|
22
|
-
Or, copy 'lib/cgi_exception.rb' to proper directory
|
27
|
+
Or, copy 'lib/cgi_exception.rb' to proper directory such as
|
28
|
+
'/usr/local/lib/ruby/site_ruby/1.8'.
|
29
|
+
|
30
|
+
NOTICE: It is NOT recommended to install by RubyGems, because
|
31
|
+
'require "rubygems"' is too heavy for CGI program.
|
23
32
|
|
24
33
|
|
25
34
|
== Usage
|
@@ -37,11 +46,11 @@ local variable 'user' is not initialized.
|
|
37
46
|
#!/usr/bin/env ruby
|
38
47
|
require 'cgi'
|
39
48
|
require 'cgi_exception'
|
40
|
-
html = "<
|
41
|
-
print
|
49
|
+
html = "<p>Hello #{user}!</p>\n"
|
50
|
+
print CGI.new.header
|
42
51
|
print html
|
43
52
|
|
44
|
-
You'll see the following message in your browser if you access the
|
53
|
+
You'll see the following message in your browser if you access the above
|
45
54
|
CGI script.
|
46
55
|
|
47
56
|
/var/www/cgi-bin/foo.cgi:4: undefined local variable or method `user'
|
@@ -55,4 +64,4 @@ public domain
|
|
55
64
|
|
56
65
|
== Author
|
57
66
|
|
58
|
-
makoto kuwata <kwa
|
67
|
+
makoto kuwata <kwa.at.kuwata-lab.com>
|
data/lib/cgi_exception.rb
CHANGED
@@ -1,25 +1,105 @@
|
|
1
1
|
##
|
2
|
-
## $Rev:
|
3
|
-
## $Release: 0.
|
4
|
-
## copyright(c) 2007 kuwata-lab.com all rights reserved.
|
2
|
+
## $Rev: 7 $
|
3
|
+
## $Release: 0.2.0 $
|
4
|
+
## copyright(c) 2007-2008 kuwata-lab.com all rights reserved.
|
5
5
|
## License: public domain
|
6
6
|
##
|
7
7
|
|
8
|
+
## escape HTML characters
|
8
9
|
def _esc_html(s)
|
9
10
|
s.to_s.gsub(/&/,'&').gsub(/</,'<').gsub(/>/,'>').gsub(/"/,'"')
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
out << header << "\r\n" if header
|
13
|
+
## print exception in HTML format
|
14
|
+
def _print_exception(ex)
|
15
15
|
arr = ex.backtrace
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
print "<pre style=\"color:#CC0000\">"
|
17
|
+
print "<b>#{_esc_html arr[0]}: #{_esc_html ex.message} (#{ex.class.name})</b>\n"
|
18
|
+
block = proc {|s| print " from #{_esc_html s}\n" }
|
19
|
+
max = 20
|
20
|
+
if arr.length <= max
|
21
|
+
arr[1..-1].each(&block)
|
22
|
+
else
|
23
|
+
n = 5
|
24
|
+
arr[1..(max-n)].each(&block)
|
25
|
+
print " ...\n"
|
26
|
+
arr[-n..-1].each(&block)
|
27
|
+
end
|
28
|
+
print "</pre>"
|
20
29
|
end
|
21
30
|
|
22
|
-
|
23
|
-
|
31
|
+
## print HTTP header (for CGI program)
|
32
|
+
def _print_http_header_for_cgi()
|
33
|
+
print "Status: 500 Internal Error\r\n"
|
34
|
+
print "Content-Type: text/html\r\n"
|
35
|
+
print "X-CGI-Exception: 0.2.0\r\n"
|
36
|
+
print "\r\n"
|
24
37
|
end
|
25
38
|
|
39
|
+
## print HTTP header (for mod_ruby)
|
40
|
+
def _print_http_header_for_modruby()
|
41
|
+
request = Apache::request
|
42
|
+
request.status = 500
|
43
|
+
request.status_line = '500 Internal Error'
|
44
|
+
request.content_type = 'text/html'
|
45
|
+
request.headers_out['X-CGI-Exception'] = '0.2.0'
|
46
|
+
request.send_http_header
|
47
|
+
end
|
48
|
+
|
49
|
+
if defined?(MOD_RUBY)
|
50
|
+
|
51
|
+
def _print_http_header() # don't use alias
|
52
|
+
_print_http_header_for_modruby()
|
53
|
+
end
|
54
|
+
|
55
|
+
class ::Apache::RubyRun # :nodoc:
|
56
|
+
## if 'alias _handler_orig handler' statement is evaluated
|
57
|
+
## more than twice, handler() will cause stack over flow.
|
58
|
+
unless self.method_defined?(:_handler_orig)
|
59
|
+
alias _handler_orig handler
|
60
|
+
end
|
61
|
+
## override handler() to catch and exception it to browser
|
62
|
+
def handler(r)
|
63
|
+
return _handler_orig(r)
|
64
|
+
rescue Exception => ex
|
65
|
+
_print_http_header()
|
66
|
+
_print_exception(ex)
|
67
|
+
#raise ex
|
68
|
+
$stderr.write "#{ex.backtrace[0]}: #{ex.message} (#{ex.class.name})\n"
|
69
|
+
return ::Apache::OK
|
70
|
+
end
|
71
|
+
## original
|
72
|
+
#def handler(r)
|
73
|
+
# status = check_request(r)
|
74
|
+
# return status if status != OK
|
75
|
+
# filename = setup(r)
|
76
|
+
# load(filename, true)
|
77
|
+
# return OK
|
78
|
+
#end
|
79
|
+
end
|
80
|
+
|
81
|
+
else
|
82
|
+
|
83
|
+
def _print_http_header() # don't use alias
|
84
|
+
_print_http_header_for_cgi()
|
85
|
+
end
|
86
|
+
|
87
|
+
## override $stdout.write() to detect whether HTTP header printed or not
|
88
|
+
class << $stdout
|
89
|
+
def write(*args)
|
90
|
+
$_header_printed = true
|
91
|
+
super(*args)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
$_header_printed = false
|
96
|
+
|
97
|
+
## when process exit, print exception if exception raised
|
98
|
+
at_exit do
|
99
|
+
if $!
|
100
|
+
_print_http_header() unless $_header_printed
|
101
|
+
_print_exception($!)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
###
|
2
|
+
### $Rev: 7 $
|
3
|
+
### $Release: 0.2.0 $
|
4
|
+
### copyright(c) 2007-2008 kuwata-lab.com all rights reserved.
|
5
|
+
###
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
LIBDIR = File.dirname(__FILE__) + '/../lib'
|
9
|
+
|
10
|
+
|
11
|
+
class CGIExceptionTest < Test::Unit::TestCase
|
12
|
+
|
13
|
+
|
14
|
+
def _test
|
15
|
+
@name = (name() =~ /^test_(.*)\(.*\)$/) && $1
|
16
|
+
filename = (@filename ||= "#{@name}.rb")
|
17
|
+
begin
|
18
|
+
#preamble = "$: << #{LIBDIR.inspect}\n"
|
19
|
+
#File.open(filename, 'w') {|f| f << preamble << @script }
|
20
|
+
#output = `ruby #{filename} 2>/dev/null`
|
21
|
+
File.open(filename, 'w') {|f| f << @script }
|
22
|
+
command = "ruby -I #{LIBDIR} #{filename} 2>/dev/null"
|
23
|
+
output = `#{command}`
|
24
|
+
expected = @expected
|
25
|
+
expected = @expected2 if @expected2 && @expected2 == output
|
26
|
+
assert_equal(expected, output)
|
27
|
+
ensure
|
28
|
+
File.unlink(filename) if File.exist?(filename) unless $DEBUG
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def test_when_no_header_printed
|
34
|
+
@script = <<'END'
|
35
|
+
require 'cgi_exception'
|
36
|
+
def build_html
|
37
|
+
return "<p>Hello #{name}</p>"
|
38
|
+
end
|
39
|
+
html = build_html
|
40
|
+
print "Content-Type: text/html\r\n"
|
41
|
+
print html
|
42
|
+
END
|
43
|
+
@expected = <<END
|
44
|
+
Status: 500 Internal Error\r
|
45
|
+
Content-Type: text/html\r
|
46
|
+
X-CGI-Exception: 0.2.0\r
|
47
|
+
\r
|
48
|
+
<pre style="color:#CC0000"><b>when_no_header_printed.rb:3:in `build_html': undefined local variable or method `name' for main:Object (NameError)</b>
|
49
|
+
from when_no_header_printed.rb:5
|
50
|
+
</pre>
|
51
|
+
END
|
52
|
+
@expected.chomp!
|
53
|
+
_test
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def test_when_header_already_printed
|
58
|
+
@script = <<'END'
|
59
|
+
require 'cgi_exception'
|
60
|
+
def build_html
|
61
|
+
return "<p>Hello #{name}</p>"
|
62
|
+
end
|
63
|
+
print "Content-Type: text/html\r\n"
|
64
|
+
print "\r\n"
|
65
|
+
print "<html>\n"
|
66
|
+
print build_html
|
67
|
+
print "</html>\n"
|
68
|
+
END
|
69
|
+
@expected = <<END
|
70
|
+
Content-Type: text/html\r
|
71
|
+
\r
|
72
|
+
<html>
|
73
|
+
<pre style="color:#CC0000"><b>when_header_already_printed.rb:3:in `build_html': undefined local variable or method `name' for main:Object (NameError)</b>
|
74
|
+
from when_header_already_printed.rb:8
|
75
|
+
</pre>
|
76
|
+
END
|
77
|
+
@expected.chomp!
|
78
|
+
_test
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def test_when_error_backtrace_is_too_long
|
83
|
+
@script = <<'END'
|
84
|
+
require 'cgi_exception'
|
85
|
+
def build_html
|
86
|
+
return f(100).to_s
|
87
|
+
end
|
88
|
+
def f(n)
|
89
|
+
return n + g(n-1)
|
90
|
+
end
|
91
|
+
def g(n)
|
92
|
+
return n + f(n-1)
|
93
|
+
end
|
94
|
+
html = build_html()
|
95
|
+
print "Content-Type: text/html\r\n"
|
96
|
+
print "\r\n"
|
97
|
+
print html
|
98
|
+
END
|
99
|
+
@expected = <<END
|
100
|
+
Status: 500 Internal Error\r
|
101
|
+
Content-Type: text/html\r
|
102
|
+
X-CGI-Exception: 0.2.0\r
|
103
|
+
\r
|
104
|
+
<pre style="color:#CC0000"><b>when_error_backtrace_is_too_long.rb:6:in `f': stack level too deep (SystemStackError)</b>
|
105
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
106
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
107
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
108
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
109
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
110
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
111
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
112
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
113
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
114
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
115
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
116
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
117
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
118
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
119
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
120
|
+
...
|
121
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
122
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
123
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
124
|
+
from when_error_backtrace_is_too_long.rb:3:in `build_html'
|
125
|
+
from when_error_backtrace_is_too_long.rb:11
|
126
|
+
</pre>
|
127
|
+
END
|
128
|
+
@expected.chomp!
|
129
|
+
@expected2 = <<END
|
130
|
+
Status: 500 Internal Error\r
|
131
|
+
Content-Type: text/html\r
|
132
|
+
X-CGI-Exception: 0.2.0\r
|
133
|
+
\r
|
134
|
+
<pre style="color:#CC0000"><b>when_error_backtrace_is_too_long.rb:9:in `g': stack level too deep (SystemStackError)</b>
|
135
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
136
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
137
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
138
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
139
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
140
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
141
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
142
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
143
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
144
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
145
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
146
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
147
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
148
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
149
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
150
|
+
...
|
151
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
152
|
+
from when_error_backtrace_is_too_long.rb:9:in `g'
|
153
|
+
from when_error_backtrace_is_too_long.rb:6:in `f'
|
154
|
+
from when_error_backtrace_is_too_long.rb:3:in `build_html'
|
155
|
+
from when_error_backtrace_is_too_long.rb:11
|
156
|
+
</pre>
|
157
|
+
END
|
158
|
+
@expected2.chomp!
|
159
|
+
_test
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
end
|
metadata
CHANGED
@@ -1,48 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.2
|
3
|
-
specification_version: 1
|
4
2
|
name: cgi-exception
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-12-24 00:00:00 +09:00
|
8
|
-
summary: Utility to display what and where exception raised in CGI script
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email:
|
12
|
-
homepage: http://cgi-exception.rubyforge.org/
|
13
|
-
rubyforge_project:
|
14
|
-
description: cgi-exception.rb is a tiny utility to display what and where exception raised in CGI script just like PHP. You don't need to look for error message in web server's log file.
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: false
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 0.2.0
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- makoto kuwata
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
- setup.rb
|
35
|
-
test_files: []
|
36
|
-
|
37
|
-
rdoc_options: []
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
38
11
|
|
39
|
-
|
12
|
+
date: 2008-02-22 00:00:00 +09:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
40
15
|
|
16
|
+
description: cgi-exception.rb is a tiny utility to display what and at where exception raised in CGI script just like PHP. You don't need to look for error message in web server's log file.
|
17
|
+
email: kwa@kuwata-lab.com
|
41
18
|
executables: []
|
42
19
|
|
43
20
|
extensions: []
|
44
21
|
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/cgi_exception.rb
|
26
|
+
- test/test_cgi_exception.rb
|
27
|
+
- README.txt
|
28
|
+
- CHANGES.txt
|
29
|
+
- setup.rb
|
30
|
+
has_rdoc: false
|
31
|
+
homepage: http://cgi-exception.rubyforge.org/
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
45
49
|
requirements: []
|
46
50
|
|
47
|
-
|
51
|
+
rubyforge_project: cgi-exception
|
52
|
+
rubygems_version: 1.0.1
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: Utility to display what and at where exception raised in CGI script
|
56
|
+
test_files: []
|
48
57
|
|