This repository has been archived by the owner on Oct 12, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
/
RunAsCGI
186 lines (141 loc) · 5.6 KB
/
RunAsCGI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
== CherryPy as a CGI application ==
CherryPy works much better when it runs for a long time unlike CGI scripts
which have a very short life time.
However sometimes there are occasions where CGI is the only way to deploy and
once you've used CherryPy you want to stick with it. Why go back to "import cgi"
when there is CherryPy?
Here is a hack to enable VERY SIMPLE cherry py scripts to be ran as a CGI
script. It is not going to work for any complex scripts that leverage CherryPy
features!
The example HelloWorld from http://www.cherrypy.org/wiki/CherryPyTutorial
{{{
#!python
from cherrypy import cpg
class HelloWorld:
def index(self):
return "Hello world!"
index.exposed = True
cpg.root = HelloWorld()
cpg.server.start()
}}}
Becomes:
{{{
#!python
from cherrypy_cgi import cherrypy_from_cgi
class HelloWorld:
def index(self):
return "Hello world!"
index.exposed = True
cherrypy_from_cgi(cherry_root=HelloWorld)
}}}
Assuming the script is called "helloworld" and dropped into the cgi-bin
directory for the web server this is accessible either via:
http://machine/cgi-bin/helloworld
Or
http://machine/cgi-bin/helloworld/
The first one will redirect to the 2nd one. For this type of CGI this is not
ideal but for scripts that take GET parameters this is required to ensure the
parameters get passed correctly. It is possible to allow the first URL form
(with the trailing slash omitted) to call the CGI directly without the
redirect, if you need this (and don't care about GET parameters) then
update cherrypy_cgi.py to change the line that reads:
{{{
cgi_function_name="_missing_slash" # default function to workaround missing '/'
}}}
And replace it with:
{{{
cgi_function_name="" # or '/'
}}}
Problems/limitations:
* the redirect is a bit of a hack :-(
* errors (python errors) are simply not reported well/at all and I'm not sure why. cgitb doesn't appear to be doing the trick in all circumstances :-(
* Not future proof; I fully expect CherryPy 2.1 to break this hack
I'm using this on sourceforge.net where I have CGI access but no control over
the web server (I don't even get to see the error logs from CGI). I really like
sourceforge and you can't complain about the price ;-)
Code/suggestions/feedback welcome. Hopefully it is useful to someone else
(probably a very small subset of CherryPy users).
Most of the credit/blame belongs to Jared (ninebelow) from the following post:
http://groups-beta.google.com/group/cherrypy-users/msg/072a8b36361a0774?dmode=source
Requirements:
http://www.CherryPy.org
{{{
import cherrypy
cherrypy.__version__ == '2.0.0'
assert(cherrypy.__version__ == '2.0.0')
}}}
http://www.pythonweb.org/projects/webmodules
{{{
import web.wsgi
assert(web.version == '0.5.3')
}}}
* cherrypy_cgi.py -- mini library
* demo_cgi.py -- mini helloworld test
* demo_cgi.sh -- debug script so you can run it from command line with out a web server.
The "CGI" library
{{{
#!python
# modeled on code from
# http://groups-beta.google.com/group/cherrypy-users/browse_thread/thread/46fde58f8c2708d/072a8b36361a0774?q=cgi&rnum=4#072a8b36361a0774
# this will enable some better error tracing
import cgitb; cgitb.enable()
# at some hosts need to add path info manually
import sys
# examples
##sys.path.append("/usr/local/psa/home/vhosts/ninebelow.com/cgi-bin")
##sys.path.append("/usr/local/psa/home/vhosts/ninebelow.com/cgi-bin/MySQLdb")
import os
# Cherry Py wsgiapp expects the environment variable PATH_INFO to be
# set to a string containing the name of the function to call. This should be
# set by hand; "" is index.html/default
# otherwise the name. e.g. "myfunc"
'''
We can derive script/function name from one of:
SCRIPT_NAME
SCRIPT_FILENAME
SCRIPT_URI
SCRIPT_URL
cgi_function_name=os.path.basename(os.environ['SCRIPT_NAME'])
'''
cgi_function_name=""
if "PATH_INFO" not in os.environ:
os.environ["PATH_INFO"] = cgi_function_name
# Import CherryPy global namespaces
# tested with cherrypy.__version__ == '2.0.0'
from cherrypy import wsgiapp
from cherrypy import cpg
# Import wrapper function to enable WSGI applications to run in a CGI environment.
# http://www.pythonweb.org/projects/webmodules
# Tested with PythonWeb.org-0.5.3; web.version == '0.5.3'
import web.wsgi
class CherryPyWsgiApp:
# CherryPy always starts with cpg.root when trying to map request URIs
# to objects, so we need to mount a request handler object here. A request
# to '/' will be mapped to cpg.root.index().
def __init__(self, cherry_root=None):
cpg.root = cherry_root
#wsgiapp.init() # default - not useful for cgi as cherry py goes to stdout
#wsgiapp.init(configMap = {'server.logToScreen':0})
wsgiapp.init(configMap = {'logToScreen':0})
def __call__(self, environ, start_response):
return wsgiapp.wsgiApp(environ, start_response)
def cherrypy_from_cgi(cherry_root=None):
#Wrapper function to enable WSGI applications to run in a CGI environment.
web.wsgi.runCGI(CherryPyWsgiApp(cherry_root=cherry_root))
}}}
{{{
#
# demo shell script to run hacked cgi for cherrypy from
# command line for debugging purposes
#
REQUEST_METHOD=GET
HTTP_REFERER=""
SERVER_NAME='hostname'
SERVER_PORT=80
SERVER_PROTOCOL=http
HTTP_HOST=$SERVER_NAME
SCRIPT_NAME=""
PATH_INFO=""
export REQUEST_METHOD HTTP_REFERER PATH_INFO SERVER_NAME SERVER_PORT SCRIPT_NAME SERVER_PROTOCOL HTTP_HOST
python demo_cgi.py
}}}