rack-cgi 0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []