Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
e7d6b0a2
Commit
e7d6b0a2
authored
Sep 19, 2000
by
Guido van Rossum
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
An honest attempt to make this work on Unix, Windows, and even
Macintosh (the latter untested). This closes Bug #110839.
parent
d9a8e965
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
173 additions
and
81 deletions
+173
-81
Lib/CGIHTTPServer.py
Lib/CGIHTTPServer.py
+173
-81
No files found.
Lib/CGIHTTPServer.py
View file @
e7d6b0a2
...
...
@@ -3,28 +3,31 @@
This module builds on SimpleHTTPServer by implementing GET and POST
requests to cgi-bin scripts.
If the os.fork() function is not present, this module will not work;
SystemError will be raised instead.
If the os.fork() function is not present (e.g. on Windows),
os.popen2() is used as a fallback, with slightly altered semantics; if
that function is not present either (e.g. on Macintosh), only Python
scripts are supported, and they are executed by the current process.
In all cases, the implementation is intentionally naive -- all
requests are executed sychronously.
SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
-- it may execute arbitrary Python code or external programs.
"""
__version__
=
"0.
3
"
__version__
=
"0.
4
"
import
os
import
sys
import
string
import
urllib
import
BaseHTTPServer
import
SimpleHTTPServer
try
:
os
.
fork
except
AttributeError
:
raise
SystemError
,
__name__
+
" requires os.fork()"
class
CGIHTTPRequestHandler
(
SimpleHTTPServer
.
SimpleHTTPRequestHandler
):
"""Complete HTTP server with GET, HEAD and POST commands.
...
...
@@ -35,6 +38,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""
# Determine platform specifics
have_fork
=
hasattr
(
os
,
'fork'
)
have_popen2
=
hasattr
(
os
,
'popen2'
)
# Make rfile unbuffered -- we need to read one line and then pass
# the rest to a subprocess, so we can't use buffered input.
rbufsize
=
0
...
...
@@ -59,9 +66,9 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
return
SimpleHTTPServer
.
SimpleHTTPRequestHandler
.
send_head
(
self
)
def
is_cgi
(
self
):
"""
test whether PATH
corresponds to a CGI script.
"""
Test whether self.path
corresponds to a CGI script.
Return a tuple (dir, rest) if
PATH
requires running a
Return a tuple (dir, rest) if
self.path
requires running a
CGI script, None if not. Note that rest begins with a
slash if it is not empty.
...
...
@@ -83,6 +90,15 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
cgi_directories
=
[
'/cgi-bin'
,
'/htbin'
]
def
is_executable
(
self
,
path
):
"""Test whether argument path is an executable file."""
return
executable
(
path
)
def
is_python
(
self
,
path
):
"""Test whether argument path is a Python script."""
head
,
tail
=
os
.
path
.
splitext
(
path
)
return
tail
.
lower
()
in
(
".py"
,
".pyw"
)
def
run_cgi
(
self
):
"""Execute a CGI script."""
dir
,
rest
=
self
.
cgi_info
...
...
@@ -105,79 +121,152 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
self
.
send_error
(
403
,
"CGI script is not a plain file (%s)"
%
`scriptname`
)
return
if
not
executable
(
scriptfile
):
self
.
send_error
(
403
,
"CGI script is not executable (%s)"
%
`scriptname`
)
return
nobody
=
nobody_uid
()
ispy
=
self
.
is_python
(
scriptname
)
if
not
ispy
:
if
not
(
self
.
have_fork
or
self
.
have_popen2
):
self
.
send_error
(
403
,
"CGI script is not a Python script (%s)"
%
`scriptname`
)
return
if
not
self
.
is_executable
(
scriptfile
):
self
.
send_error
(
403
,
"CGI script is not executable (%s)"
%
`scriptname`
)
return
# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
# XXX Much of the following could be prepared ahead of time!
env
=
{}
env
[
'SERVER_SOFTWARE'
]
=
self
.
version_string
()
env
[
'SERVER_NAME'
]
=
self
.
server
.
server_name
env
[
'GATEWAY_INTERFACE'
]
=
'CGI/1.1'
env
[
'SERVER_PROTOCOL'
]
=
self
.
protocol_version
env
[
'SERVER_PORT'
]
=
str
(
self
.
server
.
server_port
)
env
[
'REQUEST_METHOD'
]
=
self
.
command
uqrest
=
urllib
.
unquote
(
rest
)
env
[
'PATH_INFO'
]
=
uqrest
env
[
'PATH_TRANSLATED'
]
=
self
.
translate_path
(
uqrest
)
env
[
'SCRIPT_NAME'
]
=
scriptname
if
query
:
env
[
'QUERY_STRING'
]
=
query
host
=
self
.
address_string
()
if
host
!=
self
.
client_address
[
0
]:
env
[
'REMOTE_HOST'
]
=
host
env
[
'REMOTE_ADDR'
]
=
self
.
client_address
[
0
]
# XXX AUTH_TYPE
# XXX REMOTE_USER
# XXX REMOTE_IDENT
if
self
.
headers
.
typeheader
is
None
:
env
[
'CONTENT_TYPE'
]
=
self
.
headers
.
type
else
:
env
[
'CONTENT_TYPE'
]
=
self
.
headers
.
typeheader
length
=
self
.
headers
.
getheader
(
'content-length'
)
if
length
:
env
[
'CONTENT_LENGTH'
]
=
length
accept
=
[]
for
line
in
self
.
headers
.
getallmatchingheaders
(
'accept'
):
if
line
[:
1
]
in
string
.
whitespace
:
accept
.
append
(
string
.
strip
(
line
))
else
:
accept
=
accept
+
string
.
split
(
line
[
7
:],
','
)
env
[
'HTTP_ACCEPT'
]
=
string
.
joinfields
(
accept
,
','
)
ua
=
self
.
headers
.
getheader
(
'user-agent'
)
if
ua
:
env
[
'HTTP_USER_AGENT'
]
=
ua
co
=
filter
(
None
,
self
.
headers
.
getheaders
(
'cookie'
))
if
co
:
env
[
'HTTP_COOKIE'
]
=
string
.
join
(
co
,
', '
)
# XXX Other HTTP_* headers
if
not
self
.
have_fork
:
# Since we're setting the env in the parent, provide empty
# values to override previously set values
for
k
in
(
'QUERY_STRING'
,
'REMOTE_HOST'
,
'CONTENT_LENGTH'
,
'HTTP_USER_AGENT'
,
'HTTP_COOKIE'
):
env
.
setdefault
(
k
,
""
)
self
.
send_response
(
200
,
"Script output follows"
)
self
.
wfile
.
flush
()
# Always flush before forking
pid
=
os
.
fork
()
if
pid
!=
0
:
# Parent
pid
,
sts
=
os
.
waitpid
(
pid
,
0
)
decoded_query
=
string
.
replace
(
query
,
'+'
,
' '
)
if
self
.
have_fork
:
# Unix -- fork as we should
args
=
[
script
]
if
'='
not
in
decoded_query
:
args
.
append
(
decoded_query
)
nobody
=
nobody_uid
()
self
.
wfile
.
flush
()
# Always flush before forking
pid
=
os
.
fork
()
if
pid
!=
0
:
# Parent
pid
,
sts
=
os
.
waitpid
(
pid
,
0
)
if
sts
:
self
.
log_error
(
"CGI script exit status %#x"
,
sts
)
return
# Child
try
:
try
:
os
.
setuid
(
nobody
)
except
os
.
error
:
pass
os
.
dup2
(
self
.
rfile
.
fileno
(),
0
)
os
.
dup2
(
self
.
wfile
.
fileno
(),
1
)
os
.
execve
(
scriptfile
,
args
,
env
)
except
:
self
.
server
.
handle_error
(
self
.
request
,
self
.
client_address
)
os
.
_exit
(
127
)
elif
self
.
have_popen2
:
# Windows -- use popen2 to create a subprocess
import
shutil
os
.
environ
.
update
(
env
)
cmdline
=
scriptfile
if
self
.
is_python
(
scriptfile
):
interp
=
sys
.
executable
if
interp
.
lower
().
endswith
(
"w.exe"
):
# On Windows, use python.exe, not python.exe
interp
=
interp
[:
-
5
]
=
interp
[
-
4
:]
cmdline
=
"%s %s"
%
(
interp
,
cmdline
)
if
'='
not
in
query
and
'"'
not
in
query
:
cmdline
=
'%s "%s"'
%
(
cmdline
,
query
)
self
.
log_error
(
"command: %s"
,
cmdline
)
try
:
nbytes
=
int
(
length
)
except
:
nbytes
=
0
fi
,
fo
=
os
.
popen2
(
cmdline
)
if
self
.
command
.
lower
()
==
"post"
and
nbytes
>
0
:
data
=
self
.
rfile
.
read
(
nbytes
)
fi
.
write
(
data
)
fi
.
close
()
shutil
.
copyfileobj
(
fo
,
self
.
wfile
)
sts
=
fo
.
close
()
if
sts
:
self
.
log_error
(
"CGI script exit status x%x"
%
sts
)
return
# Child
try
:
# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
# XXX Much of the following could be prepared ahead of time!
env
=
{}
env
[
'SERVER_SOFTWARE'
]
=
self
.
version_string
()
env
[
'SERVER_NAME'
]
=
self
.
server
.
server_name
env
[
'GATEWAY_INTERFACE'
]
=
'CGI/1.1'
env
[
'SERVER_PROTOCOL'
]
=
self
.
protocol_version
env
[
'SERVER_PORT'
]
=
str
(
self
.
server
.
server_port
)
env
[
'REQUEST_METHOD'
]
=
self
.
command
uqrest
=
urllib
.
unquote
(
rest
)
env
[
'PATH_INFO'
]
=
uqrest
env
[
'PATH_TRANSLATED'
]
=
self
.
translate_path
(
uqrest
)
env
[
'SCRIPT_NAME'
]
=
scriptname
if
query
:
env
[
'QUERY_STRING'
]
=
query
host
=
self
.
address_string
()
if
host
!=
self
.
client_address
[
0
]:
env
[
'REMOTE_HOST'
]
=
host
env
[
'REMOTE_ADDR'
]
=
self
.
client_address
[
0
]
# AUTH_TYPE
# REMOTE_USER
# REMOTE_IDENT
if
self
.
headers
.
typeheader
is
None
:
env
[
'CONTENT_TYPE'
]
=
self
.
headers
.
type
self
.
log_error
(
"CGI script exit status %#x"
,
sts
)
else
:
env
[
'CONTENT_TYPE'
]
=
self
.
headers
.
typeheader
length
=
self
.
headers
.
getheader
(
'content-length'
)
if
length
:
env
[
'CONTENT_LENGTH'
]
=
length
accept
=
[]
for
line
in
self
.
headers
.
getallmatchingheaders
(
'accept'
):
if
line
[:
1
]
in
string
.
whitespace
:
accept
.
append
(
string
.
strip
(
line
))
else
:
accept
=
accept
+
string
.
split
(
line
[
7
:],
','
)
env
[
'HTTP_ACCEPT'
]
=
string
.
joinfields
(
accept
,
','
)
ua
=
self
.
headers
.
getheader
(
'user-agent'
)
if
ua
:
env
[
'HTTP_USER_AGENT'
]
=
ua
co
=
filter
(
None
,
self
.
headers
.
getheaders
(
'cookie'
))
if
co
:
env
[
'HTTP_COOKIE'
]
=
string
.
join
(
co
,
', '
)
# XXX Other HTTP_* headers
decoded_query
=
string
.
replace
(
query
,
'+'
,
' '
)
self
.
log_error
(
"CGI script exited OK"
)
else
:
# Other O.S. -- execute script in this process
os
.
environ
.
update
(
env
)
save_argv
=
sys
.
argv
save_stdin
=
sys
.
stdin
save_stdout
=
sys
.
stdout
save_stderr
=
sys
.
stderr
try
:
os
.
setuid
(
nobody
)
except
os
.
error
:
pass
os
.
dup2
(
self
.
rfile
.
fileno
(),
0
)
os
.
dup2
(
self
.
wfile
.
fileno
(),
1
)
print
scriptfile
,
script
,
decoded_query
os
.
execve
(
scriptfile
,
[
script
,
decoded_query
],
env
)
except
:
self
.
server
.
handle_error
(
self
.
request
,
self
.
client_address
)
os
.
_exit
(
127
)
try
:
sys
.
argv
=
[
scriptfile
]
if
'='
not
in
decoded_query
:
sys
.
argv
.
append
(
decoded_query
)
sys
.
stdout
=
self
.
wfile
sys
.
stdin
=
self
.
rfile
execfile
(
scriptfile
,
{
"__name__"
:
"__main__"
})
finally
:
sys
.
argv
=
save_argv
sys
.
stdin
=
save_stdin
sys
.
stdout
=
save_stdout
sys
.
stderr
=
save_stderr
except
SystemExit
,
sts
:
self
.
log_error
(
"CGI script exit status %s"
,
str
(
sts
))
else
:
self
.
log_error
(
"CGI script exited OK"
)
nobody
=
None
...
...
@@ -187,7 +276,10 @@ def nobody_uid():
global
nobody
if
nobody
:
return
nobody
import
pwd
try
:
import
pwd
except
ImportError
:
return
-
1
try
:
nobody
=
pwd
.
getpwnam
(
'nobody'
)[
2
]
except
KeyError
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment