rack-cgi 0.1

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/lib/rack/cgi.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rack-cgi'
data/lib/rack-cgi.rb ADDED
@@ -0,0 +1,166 @@
1
+ require 'childprocess'
2
+ require 'byebug'
3
+
4
+ module Rack
5
+ class CGI
6
+ class Executable
7
+ def self.=~ rhs
8
+ ::File.executable? rhs
9
+ end
10
+ end
11
+
12
+ def initialize app, args = {}
13
+ @app = app
14
+ @opts = args.select {|k, _| k.is_a? Symbol}
15
+ @rules = args.select {|k, _| !k.is_a? Symbol}
16
+
17
+ @root = @opts[:cgi_path]
18
+ if @root !~ /^\//
19
+ @root = ::File.join(Dir.pwd, @root)
20
+ end
21
+
22
+ @index = @opts[:index] || []
23
+ @index = [@index] if not @index.is_a? Hash
24
+ end
25
+
26
+ def solve_path path
27
+ path = ::File.join(@root, path)
28
+ if ::File.directory? path
29
+ @index.each do |f|
30
+ path2 = ::File.join(path, f)
31
+ return path2 if ::File.file? path2
32
+ end
33
+ else
34
+ return path if ::File.file? path
35
+ end
36
+ nil
37
+ end
38
+
39
+ def cgi_env env, path
40
+ env = env.select {|k, _| k =~ /^[A-Z]/}
41
+ env['SCRIPT_FILENAME'] = path
42
+ env['DOCUMENT_ROOT'] = @root
43
+ env['REDIRECT_STATUS'] = "200"
44
+ env
45
+ end
46
+
47
+ def match_cgi_rule path
48
+ @rules.each do |m, r|
49
+ if m =~ path
50
+ return r
51
+ end
52
+ end
53
+ return nil
54
+ end
55
+
56
+ def run_cgi rule, path, env
57
+ if rule.empty?
58
+ args = [path]
59
+ else
60
+ args = [rule, path]
61
+ end
62
+
63
+ process = ChildProcess.build(*args)
64
+ process.io.stdout = Tempfile.new('rack-cgi-stdout')
65
+ process.io.stderr = Tempfile.new('rack-cgi-stderr')
66
+ env.each do |k, v|
67
+ process.environment[k] = v
68
+ end
69
+ process.cwd = Dir.pwd
70
+ process.start
71
+ process.wait
72
+
73
+ cont_out = ::File.read(process.io.stdout.path)
74
+ cont_err = ::File.read(process.io.stderr.path)
75
+ process.io.stdout.unlink
76
+ process.io.stderr.unlink
77
+
78
+ [process.exit_code, cont_out, cont_err]
79
+ end
80
+
81
+ def split_header_content output
82
+ lines = output.lines.to_a
83
+ header = []
84
+
85
+ until lines.empty?
86
+ l = lines.shift
87
+ if l == "\n" or l == "\r\n"
88
+ # find break line between header and content
89
+ return header.join, lines.join
90
+ elsif l =~ /:/
91
+ header << l
92
+ else
93
+ # content break header ruler, so deal as no header
94
+ return "", output
95
+ end
96
+ end
97
+
98
+ # deal all content as header
99
+ return output, ""
100
+ end
101
+
102
+ def parse_output output
103
+ header, content = split_header_content output
104
+
105
+ h = {}
106
+ header.each_line do |l|
107
+ k, v = l.split ':', 2
108
+ k.strip!
109
+ v.strip!
110
+ h[k.downcase] = [k, v]
111
+ end
112
+
113
+ if h['status']
114
+ status = h['status'][1].to_i
115
+ h.delete 'status'
116
+ else
117
+ status = 200
118
+ end
119
+
120
+ header_hash = Hash[h.values]
121
+
122
+ [status, header_hash, [content]]
123
+ end
124
+
125
+ def report_error code, out, err, cgi_env
126
+ h = {'Content-Type' => 'text/plain'}
127
+ status = 500
128
+ reports = []
129
+
130
+ reports << "CGI Error!\n\n"
131
+ reports << "stdout output:\n"
132
+ reports << out
133
+ reports << "\n"
134
+ reports << "stderr output:\n"
135
+ reports << err
136
+ reports << "\n"
137
+ reports << "environments:\n"
138
+ cgi_env.each do |k, v|
139
+ reports << "#{k} => #{v}\n"
140
+ end
141
+
142
+ [status, h, reports]
143
+ end
144
+
145
+ def call(env)
146
+ path = solve_path env["PATH_INFO"]
147
+ if not path
148
+ return @app.call(env)
149
+ end
150
+
151
+ rule = match_cgi_rule path
152
+ if not rule
153
+ return @app.call(env)
154
+ end
155
+
156
+ cgi_env = cgi_env(env, path)
157
+ code, out, err = run_cgi rule, path, cgi_env
158
+ if code == 0
159
+ parse_output out
160
+ else
161
+ report_error code, out, err, cgi_env
162
+ end
163
+ end
164
+ end
165
+ end
166
+
data/rack-cgi.gemspec ADDED
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rack-cgi'
3
+ s.version = '0.1'
4
+ s.date = '2015-05-17'
5
+ s.summary = 'A rack middleware that can call CGI in rack'
6
+ s.description = 'A rack middleware that can call CGI in rack'
7
+ s.authors = ['Chizhong Jin']
8
+ s.email = 'jinchizhong@kingsoft.com'
9
+ s.files = Dir['{lib/*,lib/**/*,test/*,test/**/*}'] +
10
+ %w(rack-cgi.gemspec)
11
+ s.homepage = 'http://rubygems.org/gems/rack-cgi'
12
+ s.license = 'BSD'
13
+ end
data/test/cgi/error ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ echo Content-Type: text/plain
4
+ echo Status: 500
5
+ echo
6
+ echo 500 Server Internal Error
data/test/cgi/export ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+
3
+ echo 'Content-Type: text/plain'
4
+ echo 'encoding: utf-8'
5
+ echo
6
+
7
+ export
data/test/cgi/file ADDED
@@ -0,0 +1 @@
1
+ This is a test file for test
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ echo 'Content-Type: text/plain'
4
+ echo ''
5
+
6
+ echo 'Hello world'
data/test/cgi/redirect ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ echo Status: 302
4
+ echo Location: http://www.google.com
5
+ echo
6
+
data/test/cgi/test.php ADDED
@@ -0,0 +1,3 @@
1
+ <?php
2
+ phpinfo();
3
+ ?>
@@ -0,0 +1,2 @@
1
+ echo "Hello world"
2
+
data/test/config.ru ADDED
@@ -0,0 +1,5 @@
1
+ require '../lib/rack-cgi'
2
+
3
+ use Rack::CGI, cgi_path: 'cgi', index: 'index.cgi', Rack::CGI::Executable => '', /\.php$/ => '/usr/bin/php5-cgi'
4
+ use Rack::Static, urls: ['/'], root: 'cgi'
5
+ run proc{ [404, {"CONTENT-TYPE" => "text/plain"}, ['404 Not Found']] }
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-cgi
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chizhong Jin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-05-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A rack middleware that can call CGI in rack
15
+ email: jinchizhong@kingsoft.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/rack-cgi.rb
21
+ - lib/rack/cgi.rb
22
+ - test/config.ru
23
+ - test/cgi/redirect
24
+ - test/cgi/error
25
+ - test/cgi/export
26
+ - test/cgi/test.php
27
+ - test/cgi/without_header
28
+ - test/cgi/index.cgi
29
+ - test/cgi/file
30
+ - rack-cgi.gemspec
31
+ homepage: http://rubygems.org/gems/rack-cgi
32
+ licenses:
33
+ - BSD
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 1.8.23
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: A rack middleware that can call CGI in rack
56
+ test_files: []