def main(): class MyRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler): def _is_cgi(self): path = self.path x = '/cgi-bin/htmlhelp.cgi' i = len(x) if path[:i] == x and (not path[i:] or path[i] == '/'): self.cgi_info = '', path[1:i] return 1 return 0 CGIHTTPServer.test(MyRequestHandler)
def test_url_collapse_path_split(self): test_vectors = { "": ("/", ""), "..": IndexError, "/.//..": IndexError, "/": ("/", ""), "//": ("/", ""), "/\\": ("/", "\\"), "/.//": ("/", ""), "cgi-bin/file1.py": ("/cgi-bin", "file1.py"), "/cgi-bin/file1.py": ("/cgi-bin", "file1.py"), "a": ("/", "a"), "/a": ("/", "a"), "//a": ("/", "a"), "./a": ("/", "a"), "./C:/": ("/C:", ""), "/a/b": ("/a", "b"), "/a/b/": ("/a/b", ""), "/a/b/c/..": ("/a/b", ""), "/a/b/c/../d": ("/a/b", "d"), "/a/b/c/../d/e/../f": ("/a/b/d", "f"), "/a/b/c/../d/e/../../f": ("/a/b", "f"), "/a/b/c/../d/e/.././././..//f": ("/a/b", "f"), "../a/b/c/../d/e/.././././..//f": IndexError, "/a/b/c/../d/e/../../../f": ("/a", "f"), "/a/b/c/../d/e/../../../../f": ("/", "f"), "/a/b/c/../d/e/../../../../../f": IndexError, "/a/b/c/../d/e/../../../../f/..": ("/", ""), } for path, expected in test_vectors.iteritems(): if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, CGIHTTPServer._url_collapse_path_split, path) else: actual = CGIHTTPServer._url_collapse_path_split(path) self.assertEqual(expected, actual, msg="path = %r\nGot: %r\nWanted: %r" % (path, actual, expected))
def is_cgi(self): collapsed_path = CGIHTTPServer._url_collapse_path(self.path) dir_sep = collapsed_path.find('/', 1) head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:] if head in self.cgi_directories: self.cgi_info = head, tail return True return False
def do_POST(self): collapsed_path = CGIHTTPServer._url_collapse_path(urllib.unquote(self.path)) if collapsed_path.endswith("/") and collapsed_path != "/": collapsed_path = collapsed_path[:-1] if collapsed_path == "/sink/a": return self.do_sink_a() else: self.send_error(404, "No such endpoint (%s)" % collapsed_path) return
def is_cgi(self): path = self.path i = path.rfind("?") if i >= 0: path, query = path[:i], path[i:] else: query = "" root, ext = os.path.splitext(path) if self.is_cgi_extension(ext): self.cgi_info = CGIHTTPServer._url_collapse_path_split(self.path) return True return False
def is_cgi(self): path = self.path i = path.rfind('?') if i >= 0: path, query = path[:i], path[i:] else: query = '' root, ext = os.path.splitext(path) if self.is_cgi_extension(ext): self.cgi_info = CGIHTTPServer._url_collapse_path_split(self.path) return True return False
def is_cgi(self): splitpath = CGIHTTPServer._url_collapse_path_split(self.path) script_query = splitpath[1].split("?", 1) if script_query[0].endswith(".py"): if splitpath[0].startswith("/"): # Workaround for some weirdness with how CGIHTTPServer # computes the SCRIPT_NAME environment variable. splitpath = list(splitpath) splitpath[0] = '' splitpath = tuple(splitpath) self.cgi_info = splitpath return True return False
def test_url_collapse_path(self): # verify tail is the last portion and head is the rest on proper urls test_vectors = { '': '//', '..': IndexError, '/.//..': IndexError, '/': '//', '//': '//', '/\\': '//\\', '/.//': '//', 'cgi-bin/file1.py': '/cgi-bin/file1.py', '/cgi-bin/file1.py': '/cgi-bin/file1.py', 'a': '//a', '/a': '//a', '//a': '//a', './a': '//a', './C:/': '/C:/', '/a/b': '/a/b', '/a/b/': '/a/b/', '/a/b/.': '/a/b/', '/a/b/c/..': '/a/b/', '/a/b/c/../d': '/a/b/d', '/a/b/c/../d/e/../f': '/a/b/d/f', '/a/b/c/../d/e/../../f': '/a/b/f', '/a/b/c/../d/e/.././././..//f': '/a/b/f', '../a/b/c/../d/e/.././././..//f': IndexError, '/a/b/c/../d/e/../../../f': '/a/f', '/a/b/c/../d/e/../../../../f': '//f', '/a/b/c/../d/e/../../../../../f': IndexError, '/a/b/c/../d/e/../../../../f/..': '//', '/a/b/c/../d/e/../../../../f/../.': '//', } for path, expected in test_vectors.iteritems(): if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, CGIHTTPServer._url_collapse_path, path) else: actual = CGIHTTPServer._url_collapse_path(path) self.assertEqual(expected, actual, msg='path = %r\nGot: %r\nWanted: %r' % (path, actual, expected))
def is_cgi(self): # v added `CGIHTTPServer.` collapsed_path = CGIHTTPServer._url_collapse_path(self.path) dir_sep = collapsed_path.find('/', 1) head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep + 1:] if ".class" in tail: self.cgi_info = head, tail return True if head == "/" and tail == "": print('head' + head + 'tail' + tail) return False if head in self.cgi_directories: if not tail.endswith('.html'): # <-- new line #if tail.endswith('.py'): # <-- new line self.cgi_info = head, tail return True return False
def test_url_collapse_path_split(self): test_vectors = { '': ('/', ''), '..': IndexError, '/.//..': IndexError, '/': ('/', ''), '//': ('/', ''), '/\\': ('/', '\\'), '/.//': ('/', ''), 'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'), 'a': ('/', 'a'), '/a': ('/', 'a'), '//a': ('/', 'a'), './a': ('/', 'a'), './C:/': ('/C:', ''), '/a/b': ('/a', 'b'), '/a/b/': ('/a/b', ''), '/a/b/c/..': ('/a/b', ''), '/a/b/c/../d': ('/a/b', 'd'), '/a/b/c/../d/e/../f': ('/a/b/d', 'f'), '/a/b/c/../d/e/../../f': ('/a/b', 'f'), '/a/b/c/../d/e/.././././..//f': ('/a/b', 'f'), '../a/b/c/../d/e/.././././..//f': IndexError, '/a/b/c/../d/e/../../../f': ('/a', 'f'), '/a/b/c/../d/e/../../../../f': ('/', 'f'), '/a/b/c/../d/e/../../../../../f': IndexError, '/a/b/c/../d/e/../../../../f/..': ('/', ''), } for path, expected in test_vectors.iteritems(): if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, CGIHTTPServer._url_collapse_path_split, path) else: actual = CGIHTTPServer._url_collapse_path_split(path) self.assertEqual(expected, actual, msg='path = %r\nGot: %r\nWanted: %r' % (path, actual, expected))
break head, tail = head[:i], head[i:] + tail temp = self.translate_path(head) if os.path.isdir(temp): for index in self.indices: if os.path.exists(os.path.join(temp, index)): head = posixpath.join(head, index) break ctype = self.guess_type(head) if ctype in self.actions: os.environ['REDIRECT_STATUS'] = '200' head = self.actions[ctype] + head self.path = head + tail + query def translate_path(self, path): path = posixpath.normpath(urllib.unquote(path)) n = len(self.aliases) for i in range(n): url, dir = self.aliases[n - i - 1] length = len(url) if path[:length] == url: return dir + path[length:] return '' if __name__ == '__main__': CGIHTTPServer.test(PHPHTTPRequestHandler)
def run_cgi(self): """Execute a CGI script.""" path = self.path dir, rest = self.cgi_info i = path.find('/', len(dir) + 1) while i >= 0: nextdir = path[:i] nextrest = path[i + 1:] scriptdir = self.translate_path(nextdir) if os.path.isdir(scriptdir): dir, rest = nextdir, nextrest i = path.find('/', len(dir) + 1) else: break # find an explicit query string, if present. i = rest.rfind('?') if i >= 0: rest, query = rest[:i], rest[i + 1:] else: query = '' # dissect the part after the directory name into a script name & # a possible additional path, to be stored in PATH_INFO. i = rest.find('/') if i >= 0: script, rest = rest[:i], rest[i:] else: script, rest = rest, '' scriptname = dir + '/' + script scriptfile = self.translate_path(scriptname) if not os.path.exists(scriptfile): self.send_error(404, "No such CGI script (%r)" % scriptname) return if not os.path.isfile(scriptfile): self.send_error(403, "CGI script is not a plain file (%r)" % scriptname) return ispy = self.is_python(scriptname) if not ispy: if not (self.have_fork or self.have_popen2 or self.have_popen3): self.send_error( 403, "CGI script is not a Python script (%r)" % scriptname) return if not self.is_executable(scriptfile): self.send_error( 403, "CGI script is not executable (%r)" % 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] authorization = self.headers.getheader("authorization") if authorization: authorization = authorization.split() if len(authorization) == 2: import base64, binascii env['AUTH_TYPE'] = authorization[0] if authorization[0].lower() == "basic": try: authorization = base64.decodestring(authorization[1]) except binascii.Error: pass else: authorization = authorization.split(':') if len(authorization) == 2: env['REMOTE_USER'] = authorization[0] # 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 referer = self.headers.getheader('referer') if referer: env['HTTP_REFERER'] = referer accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in "\t\n\r ": accept.append(line.strip()) else: accept = accept + line[7:].split(',') env['HTTP_ACCEPT'] = ','.join(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'] = ', '.join(co) # XXX Other HTTP_* headers # 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', 'HTTP_REFERER'): env.setdefault(k, "") os.environ.update(env) self.send_response(200, "Script output follows") decoded_query = query.replace('+', ' ') if self.have_fork: # Unix -- fork as we should args = [script] if '=' not in decoded_query: args.append(decoded_query) nobody = CGIHTTPServer.nobody_uid() self.wfile.flush() # Always flush before forking pid = os.fork() if pid != 0: # Parent pid, sts = os.waitpid(pid, 0) # throw away additional data [see bug #427345] while select.select([self.rfile], [], [], 0)[0]: if not self.rfile.read(1): break 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) #hack to import python scripts due to permission restrictions #regarding launching another interpreter instance root, ext = os.path.splitext(scriptfile) if ext == '.py': root, script = os.path.split(root) sys.path.append(root) __import__(script) os._exit(0) else: os.execve(scriptfile, args, os.environ) except: self.server.handle_error(self.request, self.client_address) os._exit(127)
def run_cgi(self): """Execute a CGI script.""" dir, rest = self.cgi_info o = urlparse.urlparse(rest) # find an explicit query string, if present. query = str(o.query) # dissect the part after the directory name into a script name & # a possible additional path, to be stored in PATH_INFO. path = str(o.path) i = path.find('/') if i >= 0: script, rest = path[:i], path[i:] else: script, rest = path, '' scriptname = dir + '/' + script scriptfile = self.translate_path(scriptname) if not os.path.exists(scriptfile): self.send_error(404, "No such CGI script (%r)" % scriptname) return if not os.path.isfile(scriptfile): self.send_error(403, "CGI script is not a plain file (%r)" % scriptname) return ispy = self.is_python(scriptname) if not ispy: if not (self.have_fork or self.have_popen2 or self.have_popen3): self.send_error(403, "CGI script is not a Python script (%r)" % scriptname) return if not self.is_executable(scriptfile): self.send_error(403, "CGI script is not executable (%r)" % scriptname) return # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html # XXX Much of the following could be prepared ahead of time! env = copy.deepcopy(os.environ) 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 if query != '': if rest != '/captcha': rest = script + rest else: query = query.split('?')[0] rest = rest.replace('blog.py/', '') 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] authorization = self.headers.getheader("authorization") if authorization: authorization = authorization.split() if len(authorization) == 2: import base64, binascii env['AUTH_TYPE'] = authorization[0] if authorization[0].lower() == "basic": try: authorization = base64.decodestring(authorization[1]) except binascii.Error: pass else: authorization = authorization.split(':') if len(authorization) == 2: env['REMOTE_USER'] = authorization[0] # 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 referer = self.headers.getheader('referer') if referer: env['HTTP_REFERER'] = referer accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in "\t\n\r ": accept.append(line.strip()) else: accept = accept + line[7:].split(',') env['HTTP_ACCEPT'] = ','.join(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'] = ', '.join(co) # XXX Other HTTP_* headers # 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', 'HTTP_REFERER'): env.setdefault(k, "") if self.command.lower() == 'post': self.send_response(303, 'redirection') else: self.send_response(200, "Script output follows") decoded_query = query.replace('+', ' ') if self.have_fork: # Unix -- fork as we should args = [script] if '=' not in decoded_query: args.append(decoded_query) if sys.platform != 'darwin': nobody = CGIHTTPServer.nobody_uid() self.wfile.flush() # Always flush before forking pid = os.fork() if pid != 0: # Parent pid, sts = os.waitpid(pid, 0) # throw away additional data [see bug #427345] while select.select([self.rfile], [], [], 0)[0]: if not self.rfile.read(1): break if sts: self.log_error("CGI script exit status %#x", sts) return # Child try: if sys.platform != 'darwin': 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) else: # Non Unix - use subprocess import subprocess cmdline = [scriptfile] if self.is_python(scriptfile): interp = sys.executable if interp.lower().endswith("w.exe"): # On Windows, use python.exe, not pythonw.exe interp = interp[:-5] + interp[-4:] cmdline = [interp, '-u'] + cmdline if '=' not in query: cmdline.append(query) self.log_message("command: %s", subprocess.list2cmdline(cmdline)) try: nbytes = int(length) except (TypeError, ValueError): nbytes = 0 p = subprocess.Popen(cmdline, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, env = env ) if self.command.lower() == "post" and nbytes > 0: data = self.rfile.read(nbytes) else: data = None # throw away additional data [see bug #427345] while select.select([self.rfile._sock], [], [], 0)[0]: if not self.rfile._sock.recv(1): break stdout, stderr = p.communicate(data) if 'location' == stdout[:len('location')].lower(): seeother = stdout[len('location')+1:].strip() stdout = ''' <html><head><meta http-equiv="refresh" content="0;url=%s"></head></html>''' % seeother self.wfile.write(stdout) if stderr: self.log_error('%s', stderr) p.stderr.close() p.stdout.close() status = p.returncode if status: self.log_error("CGI script exit status %#x", status) else: self.log_message("CGI script exited OK")
#!/usr/bin/env python # coding:utf-8 '''CGI--通用网关接口''' import CGIHTTPServer CGIHTTPServer.test() '''默认8000,改端口 python cgihttpd.py 8080'''
def run_cgi(self): """Execute a CGI script.""" path = self.path dir, rest = self.cgi_info i = path.find("/", len(dir) + 1) while i >= 0: nextdir = path[:i] nextrest = path[i + 1 :] scriptdir = self.translate_path(nextdir) if os.path.isdir(scriptdir): dir, rest = nextdir, nextrest i = path.find("/", len(dir) + 1) else: break # find an explicit query string, if present. i = rest.rfind("?") if i >= 0: rest, query = rest[:i], rest[i + 1 :] else: query = "" # dissect the part after the directory name into a script name & # a possible additional path, to be stored in PATH_INFO. i = rest.find("/") if i >= 0: script, rest = rest[:i], rest[i:] else: script, rest = rest, "" scriptname = dir + "/" + script scriptfile = self.translate_path(scriptname) if not os.path.exists(scriptfile): self.send_error(404, "No such CGI script (%r)" % scriptname) return if not os.path.isfile(scriptfile): self.send_error(403, "CGI script is not a plain file (%r)" % scriptname) return ispy = self.is_python(scriptname) isphp = self.is_php(scriptname) if not (ispy or isphp): if not (self.have_fork or self.have_popen2 or self.have_popen3): self.send_error(403, "CGI script is not a Python script (%r)" % scriptname) return if not self.is_executable(scriptfile): self.send_error(403, "CGI script is not executable (%r)" % scriptname) return # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html # XXX Much of the following could be prepared ahead of time! env = copy.deepcopy(os.environ) 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] authorization = self.headers.getheader("authorization") if authorization: authorization = authorization.split() if len(authorization) == 2: import base64, binascii env["AUTH_TYPE"] = authorization[0] if authorization[0].lower() == "basic": try: authorization = base64.decodestring(authorization[1]) except binascii.Error: pass else: authorization = authorization.split(":") if len(authorization) == 2: env["REMOTE_USER"] = authorization[0] # 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 referer = self.headers.getheader("referer") if referer: env["HTTP_REFERER"] = referer accept = [] for line in self.headers.getallmatchingheaders("accept"): if line[:1] in "\t\n\r ": accept.append(line.strip()) else: accept = accept + line[7:].split(",") env["HTTP_ACCEPT"] = ",".join(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"] = ", ".join(co) # XXX Other HTTP_* headers # 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", "HTTP_REFERER"): env.setdefault(k, "") self.send_response(200, "Script output follows") decoded_query = query.replace("+", " ") if self.is_php(scriptfile): env["SCRIPT_FILENAME"] = os.path.abspath(scriptfile) self.init_bin() # if self.have_fork and not self.is_php(scriptfile): if self.have_fork: # Unix -- fork as we should args = [script] if self.is_php(scriptfile): args = [scriptfile] scriptfile = self.php_bin # args = [scriptfile] # scriptfile = '/usr/bin/php' if "=" not in decoded_query: args.append(decoded_query) nobody = CGIHTTPServer.nobody_uid() self.wfile.flush() # Always flush before forking pid = os.fork() if pid != 0: # Parent pid, sts = os.waitpid(pid, 0) # throw away additional data [see bug #427345] while select.select([self.rfile], [], [], 0)[0]: if not self.rfile.read(1): break 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) else: # Non Unix - use subprocess import subprocess cmdline = [scriptfile] if self.is_python(scriptfile): interp = sys.executable if interp.lower().endswith("w.exe"): # On Windows, use python.exe, not pythonw.exe interp = interp[:-5] + interp[-4:] cmdline = [interp, "-u"] + cmdline if self.is_php(scriptfile): cmdline = [self.php_bin] + cmdline if "=" not in query: cmdline.append(query) self.log_message("command: %s", subprocess.list2cmdline(cmdline)) try: nbytes = int(length) except (TypeError, ValueError): nbytes = 0 p = subprocess.Popen( cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env ) if self.command.lower() == "post" and nbytes > 0: data = self.rfile.read(nbytes) else: data = None # throw away additional data [see bug #427345] while select.select([self.rfile._sock], [], [], 0)[0]: if not self.rfile._sock.recv(1): break stdout, stderr = p.communicate(data) self.wfile.write(stdout) if stderr: self.log_error("%s", stderr) p.stderr.close() p.stdout.close() status = p.returncode if status: self.log_error("CGI script exit status %#x", status) else: self.log_message("CGI script exited OK")
def run_cgi(self): """Execute a CGI script.""" path = self.path dir, rest = self.cgi_info i = path.find('/', len(dir) + 1) while i >= 0: nextdir = path[:i] nextrest = path[i+1:] scriptdir = self.translate_path(nextdir) if os.path.isdir(scriptdir): dir, rest = nextdir, nextrest i = path.find('/', len(dir) + 1) else: break # find an explicit query string, if present. i = rest.rfind('?') if i >= 0: rest, query = rest[:i], rest[i+1:] else: query = '' # dissect the part after the directory name into a script name & # a possible additional path, to be stored in PATH_INFO. i = rest.find('/') if i >= 0: script, rest = rest[:i], rest[i:] else: script, rest = rest, '' scriptname = dir + '/' + script scriptfile = self.translate_path(scriptname) if not os.path.exists(scriptfile): self.send_error(404, "No such CGI script (%r)" % scriptname) return if not os.path.isfile(scriptfile): self.send_error(403, "CGI script is not a plain file (%r)" % scriptname) return ispy = self.is_python(scriptname) if not ispy: if not (self.have_fork or self.have_popen2 or self.have_popen3): self.send_error(403, "CGI script is not a Python script (%r)" % scriptname) return if not self.is_executable(scriptfile): self.send_error(403, "CGI script is not executable (%r)" % 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] authorization = self.headers.getheader("authorization") if authorization: authorization = authorization.split() if len(authorization) == 2: import base64, binascii env['AUTH_TYPE'] = authorization[0] if authorization[0].lower() == "basic": try: authorization = base64.decodestring(authorization[1]) except binascii.Error: pass else: authorization = authorization.split(':') if len(authorization) == 2: env['REMOTE_USER'] = authorization[0] # 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 referer = self.headers.getheader('referer') if referer: env['HTTP_REFERER'] = referer accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in "\t\n\r ": accept.append(line.strip()) else: accept = accept + line[7:].split(',') env['HTTP_ACCEPT'] = ','.join(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'] = ', '.join(co) # XXX Other HTTP_* headers # 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', 'HTTP_REFERER'): env.setdefault(k, "") os.environ.update(env) self.send_response(200, "Script output follows") decoded_query = query.replace('+', ' ') if self.have_fork: # Unix -- fork as we should args = [script] if '=' not in decoded_query: args.append(decoded_query) nobody = CGIHTTPServer.nobody_uid() self.wfile.flush() # Always flush before forking pid = os.fork() if pid != 0: # Parent pid, sts = os.waitpid(pid, 0) # throw away additional data [see bug #427345] while select.select([self.rfile], [], [], 0)[0]: if not self.rfile.read(1): break 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) #hack to import python scripts due to permission restrictions #regarding launching another interpreter instance root, ext = os.path.splitext(scriptfile) if ext == '.py': root, script = os.path.split(root) sys.path.append(root) __import__(script) os._exit(0) else: os.execve(scriptfile, args, os.environ) except: self.server.handle_error(self.request, self.client_address) os._exit(127)
break head, tail = head[:i], head[i:] + tail temp = self.translate_path(head) if os.path.isdir(temp): for index in self.indices: if os.path.exists(os.path.join(temp, index)): head = posixpath.join(head, index) break ctype = self.guess_type(head) if ctype in self.actions: os.environ['REDIRECT_STATUS'] = '200' head = self.actions[ctype] + head self.path = head + tail + query def translate_path(self, path): path = posixpath.normpath(urllib.unquote(path)) n = len(self.aliases) for i in range(n): url, dir = self.aliases[n-i-1] length = len(url) if path[:length] == url: return dir + path[length:] return '' if __name__ == '__main__': CGIHTTPServer.test(PHPHTTPRequestHandler)
def test(HandlerClass = SymfonyHTTPRequestHandler, ServerClass = HTTPServer): CGIHTTPServer.test(HandlerClass, ServerClass)
def test(HandlerClass = PTestCGIHandler, ServerClass = BaseHTTPServer.HTTPServer): CGIHTTPServer.test(HandlerClass, ServerClass)
def server(): CGIHTTPServer.test()
# -*- coding: utf-8 -*- import CGIHTTPServer if __name__ == '__main__': print('あああ') CGIHTTPServer.test();
import SimpleHTTPServer import SocketServer import CGIHTTPServer PORT = 8000 Handler = CGIHTTPServer.CGIHTTPRequestHandler httpd = CGIHTTPServer.TCPServer(("", PORT), Handler) print "serving at port", PORT httpd.serve_forever()
def run_cgi(self): """Execute a CGI script.""" path = self.path dir, rest = self.cgi_info i = path.find('/', len(dir) + 1) while i >= 0: nextdir = path[:i] nextrest = path[i+1:] scriptdir = self.translate_path(nextdir) if os.path.isdir(scriptdir): dir, rest = nextdir, nextrest i = path.find('/', len(dir) + 1) else: break # find an explicit query string, if present. i = rest.rfind('?') if i >= 0: rest, query = rest[:i], rest[i+1:] else: query = '' # dissect the part after the directory name into a script name & # a possible additional path, to be stored in PATH_INFO. i = rest.find('/') if i >= 0: script, rest = rest[:i], rest[i:] else: script, rest = rest, '' scriptname = dir + '/' + script scriptfile = self.translate_path(scriptname) if not os.path.exists(scriptfile): self.send_error(404, "No such CGI script (%r)" % scriptname) return if not os.path.isfile(scriptfile): self.send_error(403, "CGI script is not a plain file (%r)" % scriptname) return ispy = self.is_python(scriptname) isphp = self.is_php(scriptname) if not (ispy or isphp): if not (self.have_fork or self.have_popen2 or self.have_popen3): self.send_error(403, "CGI script is not a Python script (%r)" % scriptname) return if not self.is_executable(scriptfile): self.send_error(403, "CGI script is not executable (%r)" % scriptname) return # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html # XXX Much of the following could be prepared ahead of time! env = copy.deepcopy(os.environ) 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] authorization = self.headers.getheader("authorization") if authorization: authorization = authorization.split() if len(authorization) == 2: import base64, binascii env['AUTH_TYPE'] = authorization[0] if authorization[0].lower() == "basic": try: authorization = base64.decodestring(authorization[1]) except binascii.Error: pass else: authorization = authorization.split(':') if len(authorization) == 2: env['REMOTE_USER'] = authorization[0] # 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 referer = self.headers.getheader('referer') if referer: env['HTTP_REFERER'] = referer accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in "\t\n\r ": accept.append(line.strip()) else: accept = accept + line[7:].split(',') env['HTTP_ACCEPT'] = ','.join(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'] = ', '.join(co) # XXX Other HTTP_* headers # 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', 'HTTP_REFERER'): env.setdefault(k, "") self.send_response(200, "Script output follows") decoded_query = query.replace('+', ' ') if self.is_php(scriptfile): env['SCRIPT_FILENAME'] = os.path.abspath(scriptfile) self.init_bin() # if self.have_fork and not self.is_php(scriptfile): if self.have_fork: # Unix -- fork as we should args = [script] if self.is_php(scriptfile): args = [scriptfile] scriptfile = self.php_bin # args = [scriptfile] # scriptfile = '/usr/bin/php' if '=' not in decoded_query: args.append(decoded_query) nobody = CGIHTTPServer.nobody_uid() self.wfile.flush() # Always flush before forking pid = os.fork() if pid != 0: # Parent pid, sts = os.waitpid(pid, 0) # throw away additional data [see bug #427345] while select.select([self.rfile], [], [], 0)[0]: if not self.rfile.read(1): break 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) else: # Non Unix - use subprocess import subprocess cmdline = [scriptfile] if self.is_python(scriptfile): interp = sys.executable if interp.lower().endswith("w.exe"): # On Windows, use python.exe, not pythonw.exe interp = interp[:-5] + interp[-4:] cmdline = [interp, '-u'] + cmdline if self.is_php(scriptfile): cmdline = [self.php_bin] + cmdline if '=' not in query: cmdline.append(query) self.log_message("command: %s", subprocess.list2cmdline(cmdline)) try: nbytes = int(length) except (TypeError, ValueError): nbytes = 0 p = subprocess.Popen(cmdline, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, env = env ) if self.command.lower() == "post" and nbytes > 0: data = self.rfile.read(nbytes) else: data = None # throw away additional data [see bug #427345] while select.select([self.rfile._sock], [], [], 0)[0]: if not self.rfile._sock.recv(1): break stdout, stderr = p.communicate(data) self.wfile.write(stdout) if stderr: self.log_error('%s', stderr) p.stderr.close() p.stdout.close() status = p.returncode if status: self.log_error("CGI script exit status %#x", status) else: self.log_message("CGI script exited OK")
#!/usr/bin/env python # _* config: utf-8 _*_ import CGIHTTPServer CGIHTTPServer.test()
#!/usr/bin/env python import os import CGIHTTPServer class PyCGIHandler(CGIHTTPServer.CGIHTTPRequestHandler): def is_cgi(self): splitpath = CGIHTTPServer._url_collapse_path_split(self.path) script_query = splitpath[1].split("?", 1) if script_query[0].endswith(".py"): if splitpath[0].startswith("/"): # Workaround for some weirdness with how CGIHTTPServer # computes the SCRIPT_NAME environment variable. splitpath = list(splitpath) splitpath[0] = '' splitpath = tuple(splitpath) self.cgi_info = splitpath return True return False os.chdir("www") CGIHTTPServer.test(HandlerClass=PyCGIHandler)