Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d635b1d

Browse files
committed
The Usual
1 parent 0872e05 commit d635b1d

20 files changed

Lines changed: 642 additions & 421 deletions

Lib/dos-8x3/cgihttps.py

Lines changed: 173 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,31 @@
33
This module builds on SimpleHTTPServer by implementing GET and POST
44
requests to cgi-bin scripts.
55
6-
If the os.fork() function is not present, this module will not work;
7-
SystemError will be raised instead.
6+
If the os.fork() function is not present (e.g. on Windows),
7+
os.popen2() is used as a fallback, with slightly altered semantics; if
8+
that function is not present either (e.g. on Macintosh), only Python
9+
scripts are supported, and they are executed by the current process.
10+
11+
In all cases, the implementation is intentionally naive -- all
12+
requests are executed sychronously.
13+
14+
SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
15+
-- it may execute arbitrary Python code or external programs.
816
917
"""
1018

1119

12-
__version__ = "0.3"
20+
__version__ = "0.4"
1321

1422

1523
import os
24+
import sys
1625
import string
1726
import urllib
1827
import BaseHTTPServer
1928
import SimpleHTTPServer
2029

2130

22-
try:
23-
os.fork
24-
except AttributeError:
25-
raise SystemError, __name__ + " requires os.fork()"
26-
27-
2831
class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
2932

3033
"""Complete HTTP server with GET, HEAD and POST commands.
@@ -35,6 +38,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
3538
3639
"""
3740

41+
# Determine platform specifics
42+
have_fork = hasattr(os, 'fork')
43+
have_popen2 = hasattr(os, 'popen2')
44+
3845
# Make rfile unbuffered -- we need to read one line and then pass
3946
# the rest to a subprocess, so we can't use buffered input.
4047
rbufsize = 0
@@ -59,9 +66,9 @@ def send_head(self):
5966
return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
6067

6168
def is_cgi(self):
62-
"""test whether PATH corresponds to a CGI script.
69+
"""Test whether self.path corresponds to a CGI script.
6370
64-
Return a tuple (dir, rest) if PATH requires running a
71+
Return a tuple (dir, rest) if self.path requires running a
6572
CGI script, None if not. Note that rest begins with a
6673
slash if it is not empty.
6774
@@ -83,6 +90,15 @@ def is_cgi(self):
8390

8491
cgi_directories = ['/cgi-bin', '/htbin']
8592

93+
def is_executable(self, path):
94+
"""Test whether argument path is an executable file."""
95+
return executable(path)
96+
97+
def is_python(self, path):
98+
"""Test whether argument path is a Python script."""
99+
head, tail = os.path.splitext(path)
100+
return tail.lower() in (".py", ".pyw")
101+
86102
def run_cgi(self):
87103
"""Execute a CGI script."""
88104
dir, rest = self.cgi_info
@@ -105,79 +121,152 @@ def run_cgi(self):
105121
self.send_error(403, "CGI script is not a plain file (%s)" %
106122
`scriptname`)
107123
return
108-
if not executable(scriptfile):
109-
self.send_error(403, "CGI script is not executable (%s)" %
110-
`scriptname`)
111-
return
112-
nobody = nobody_uid()
124+
ispy = self.is_python(scriptname)
125+
if not ispy:
126+
if not (self.have_fork or self.have_popen2):
127+
self.send_error(403, "CGI script is not a Python script (%s)" %
128+
`scriptname`)
129+
return
130+
if not self.is_executable(scriptfile):
131+
self.send_error(403, "CGI script is not executable (%s)" %
132+
`scriptname`)
133+
return
134+
135+
# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
136+
# XXX Much of the following could be prepared ahead of time!
137+
env = {}
138+
env['SERVER_SOFTWARE'] = self.version_string()
139+
env['SERVER_NAME'] = self.server.server_name
140+
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
141+
env['SERVER_PROTOCOL'] = self.protocol_version
142+
env['SERVER_PORT'] = str(self.server.server_port)
143+
env['REQUEST_METHOD'] = self.command
144+
uqrest = urllib.unquote(rest)
145+
env['PATH_INFO'] = uqrest
146+
env['PATH_TRANSLATED'] = self.translate_path(uqrest)
147+
env['SCRIPT_NAME'] = scriptname
148+
if query:
149+
env['QUERY_STRING'] = query
150+
host = self.address_string()
151+
if host != self.client_address[0]:
152+
env['REMOTE_HOST'] = host
153+
env['REMOTE_ADDR'] = self.client_address[0]
154+
# XXX AUTH_TYPE
155+
# XXX REMOTE_USER
156+
# XXX REMOTE_IDENT
157+
if self.headers.typeheader is None:
158+
env['CONTENT_TYPE'] = self.headers.type
159+
else:
160+
env['CONTENT_TYPE'] = self.headers.typeheader
161+
length = self.headers.getheader('content-length')
162+
if length:
163+
env['CONTENT_LENGTH'] = length
164+
accept = []
165+
for line in self.headers.getallmatchingheaders('accept'):
166+
if line[:1] in string.whitespace:
167+
accept.append(string.strip(line))
168+
else:
169+
accept = accept + string.split(line[7:], ',')
170+
env['HTTP_ACCEPT'] = string.joinfields(accept, ',')
171+
ua = self.headers.getheader('user-agent')
172+
if ua:
173+
env['HTTP_USER_AGENT'] = ua
174+
co = filter(None, self.headers.getheaders('cookie'))
175+
if co:
176+
env['HTTP_COOKIE'] = string.join(co, ', ')
177+
# XXX Other HTTP_* headers
178+
if not self.have_fork:
179+
# Since we're setting the env in the parent, provide empty
180+
# values to override previously set values
181+
for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
182+
'HTTP_USER_AGENT', 'HTTP_COOKIE'):
183+
env.setdefault(k, "")
184+
113185
self.send_response(200, "Script output follows")
114-
self.wfile.flush() # Always flush before forking
115-
pid = os.fork()
116-
if pid != 0:
117-
# Parent
118-
pid, sts = os.waitpid(pid, 0)
186+
187+
decoded_query = string.replace(query, '+', ' ')
188+
189+
if self.have_fork:
190+
# Unix -- fork as we should
191+
args = [script]
192+
if '=' not in decoded_query:
193+
args.append(decoded_query)
194+
nobody = nobody_uid()
195+
self.wfile.flush() # Always flush before forking
196+
pid = os.fork()
197+
if pid != 0:
198+
# Parent
199+
pid, sts = os.waitpid(pid, 0)
200+
if sts:
201+
self.log_error("CGI script exit status %#x", sts)
202+
return
203+
# Child
204+
try:
205+
try:
206+
os.setuid(nobody)
207+
except os.error:
208+
pass
209+
os.dup2(self.rfile.fileno(), 0)
210+
os.dup2(self.wfile.fileno(), 1)
211+
os.execve(scriptfile, args, env)
212+
except:
213+
self.server.handle_error(self.request, self.client_address)
214+
os._exit(127)
215+
216+
elif self.have_popen2:
217+
# Windows -- use popen2 to create a subprocess
218+
import shutil
219+
os.environ.update(env)
220+
cmdline = scriptfile
221+
if self.is_python(scriptfile):
222+
interp = sys.executable
223+
if interp.lower().endswith("w.exe"):
224+
# On Windows, use python.exe, not python.exe
225+
interp = interp[:-5] = interp[-4:]
226+
cmdline = "%s %s" % (interp, cmdline)
227+
if '=' not in query and '"' not in query:
228+
cmdline = '%s "%s"' % (cmdline, query)
229+
self.log_error("command: %s", cmdline)
230+
try:
231+
nbytes = int(length)
232+
except:
233+
nbytes = 0
234+
fi, fo = os.popen2(cmdline)
235+
if self.command.lower() == "post" and nbytes > 0:
236+
data = self.rfile.read(nbytes)
237+
fi.write(data)
238+
fi.close()
239+
shutil.copyfileobj(fo, self.wfile)
240+
sts = fo.close()
119241
if sts:
120-
self.log_error("CGI script exit status x%x" % sts)
121-
return
122-
# Child
123-
try:
124-
# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
125-
# XXX Much of the following could be prepared ahead of time!
126-
env = {}
127-
env['SERVER_SOFTWARE'] = self.version_string()
128-
env['SERVER_NAME'] = self.server.server_name
129-
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
130-
env['SERVER_PROTOCOL'] = self.protocol_version
131-
env['SERVER_PORT'] = str(self.server.server_port)
132-
env['REQUEST_METHOD'] = self.command
133-
uqrest = urllib.unquote(rest)
134-
env['PATH_INFO'] = uqrest
135-
env['PATH_TRANSLATED'] = self.translate_path(uqrest)
136-
env['SCRIPT_NAME'] = scriptname
137-
if query:
138-
env['QUERY_STRING'] = query
139-
host = self.address_string()
140-
if host != self.client_address[0]:
141-
env['REMOTE_HOST'] = host
142-
env['REMOTE_ADDR'] = self.client_address[0]
143-
# AUTH_TYPE
144-
# REMOTE_USER
145-
# REMOTE_IDENT
146-
if self.headers.typeheader is None:
147-
env['CONTENT_TYPE'] = self.headers.type
242+
self.log_error("CGI script exit status %#x", sts)
148243
else:
149-
env['CONTENT_TYPE'] = self.headers.typeheader
150-
length = self.headers.getheader('content-length')
151-
if length:
152-
env['CONTENT_LENGTH'] = length
153-
accept = []
154-
for line in self.headers.getallmatchingheaders('accept'):
155-
if line[:1] in string.whitespace:
156-
accept.append(string.strip(line))
157-
else:
158-
accept = accept + string.split(line[7:], ',')
159-
env['HTTP_ACCEPT'] = string.joinfields(accept, ',')
160-
ua = self.headers.getheader('user-agent')
161-
if ua:
162-
env['HTTP_USER_AGENT'] = ua
163-
co = filter(None, self.headers.getheaders('cookie'))
164-
if co:
165-
env['HTTP_COOKIE'] = string.join(co, ', ')
166-
# XXX Other HTTP_* headers
167-
decoded_query = string.replace(query, '+', ' ')
244+
self.log_error("CGI script exited OK")
245+
246+
else:
247+
# Other O.S. -- execute script in this process
248+
os.environ.update(env)
249+
save_argv = sys.argv
250+
save_stdin = sys.stdin
251+
save_stdout = sys.stdout
252+
save_stderr = sys.stderr
168253
try:
169-
os.setuid(nobody)
170-
except os.error:
171-
pass
172-
os.dup2(self.rfile.fileno(), 0)
173-
os.dup2(self.wfile.fileno(), 1)
174-
print scriptfile, script, decoded_query
175-
os.execve(scriptfile,
176-
[script, decoded_query],
177-
env)
178-
except:
179-
self.server.handle_error(self.request, self.client_address)
180-
os._exit(127)
254+
try:
255+
sys.argv = [scriptfile]
256+
if '=' not in decoded_query:
257+
sys.argv.append(decoded_query)
258+
sys.stdout = self.wfile
259+
sys.stdin = self.rfile
260+
execfile(scriptfile, {"__name__": "__main__"})
261+
finally:
262+
sys.argv = save_argv
263+
sys.stdin = save_stdin
264+
sys.stdout = save_stdout
265+
sys.stderr = save_stderr
266+
except SystemExit, sts:
267+
self.log_error("CGI script exit status %s", str(sts))
268+
else:
269+
self.log_error("CGI script exited OK")
181270

182271

183272
nobody = None
@@ -187,7 +276,10 @@ def nobody_uid():
187276
global nobody
188277
if nobody:
189278
return nobody
190-
import pwd
279+
try:
280+
import pwd
281+
except ImportError:
282+
return -1
191283
try:
192284
nobody = pwd.getpwnam('nobody')[2]
193285
except KeyError:

Lib/dos-8x3/configpa.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def __read(self, fp, fpname):
440440
# allow empty values
441441
if optval == '""':
442442
optval = ''
443-
cursect[optname] = optval
443+
cursect[self.optionxform(optname)] = optval
444444
else:
445445
# a non-fatal parsing error occurred. set up the
446446
# exception but keep going. the exception will be

Lib/dos-8x3/posixfil.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,6 @@ def __repr__(self):
6767
(self.states[file.closed], file.name, file.mode, \
6868
hex(id(self))[2:])
6969

70-
def __del__(self):
71-
self._file_.close()
72-
7370
#
7471
# Initialization routines
7572
#

Lib/dos-8x3/py_compi.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ def compile(file, cfile=None, dfile=None):
4848
except AttributeError:
4949
timestamp = long(os.stat(file)[8])
5050
codestring = f.read()
51+
# If parsing from a string, line breaks are \n (see parsetok.c:tok_nextc)
52+
# Replace will return original string if pattern is not found, so
53+
# we don't need to check whether it is found first.
54+
codestring = codestring.replace("\r\n","\n")
55+
codestring = codestring.replace("\r","\n")
5156
f.close()
5257
if codestring and codestring[-1] != '\n':
5358
codestring = codestring + '\n'

Lib/dos-8x3/sre_pars.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ def parse_template(source, pattern):
634634
while 1:
635635
group = _group(this, pattern.groups+1)
636636
if group:
637-
if (not s.next or
637+
if (s.next not in DIGITS or
638638
not _group(this + s.next, pattern.groups+1)):
639639
code = MARK, int(group)
640640
break

Lib/dos-8x3/stringio.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,15 @@ def readline(self, length=None):
9191
r = self.buf[self.pos:newpos]
9292
self.pos = newpos
9393
return r
94-
def readlines(self):
94+
def readlines(self, sizehint = 0):
95+
total = 0
9596
lines = []
9697
line = self.readline()
9798
while line:
9899
lines.append(line)
100+
total += len(line)
101+
if 0 < sizehint <= total:
102+
break
99103
line = self.readline()
100104
return lines
101105
def write(self, s):

0 commit comments

Comments
 (0)