Mercurial > cpython-lru_cache-weakref
comparison Lib/dos_8x3/cgihttps.py @ 3784:b41019557b6e legacy-trunk
Fuck. For PC support, this must be in the distribution.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Mon, 22 Jul 1996 15:23:25 +0000 |
| parents | |
| children | 1bddba2f100e |
comparison
equal
deleted
inserted
replaced
| 3783:a6203d17158b | 3784:b41019557b6e |
|---|---|
| 1 """CGI-savvy HTTP Server. | |
| 2 | |
| 3 This module builds on SimpleHTTPServer by implementing GET and POST | |
| 4 requests to cgi-bin scripts. | |
| 5 | |
| 6 """ | |
| 7 | |
| 8 | |
| 9 __version__ = "0.3" | |
| 10 | |
| 11 | |
| 12 import os | |
| 13 import sys | |
| 14 import time | |
| 15 import socket | |
| 16 import string | |
| 17 import urllib | |
| 18 import BaseHTTPServer | |
| 19 import SimpleHTTPServer | |
| 20 | |
| 21 | |
| 22 class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | |
| 23 | |
| 24 """Complete HTTP server with GET, HEAD and POST commands. | |
| 25 | |
| 26 GET and HEAD also support running CGI scripts. | |
| 27 | |
| 28 The POST command is *only* implemented for CGI scripts. | |
| 29 | |
| 30 """ | |
| 31 | |
| 32 def do_POST(self): | |
| 33 """Serve a POST request. | |
| 34 | |
| 35 This is only implemented for CGI scripts. | |
| 36 | |
| 37 """ | |
| 38 | |
| 39 if self.is_cgi(): | |
| 40 self.run_cgi() | |
| 41 else: | |
| 42 self.send_error(501, "Can only POST to CGI scripts") | |
| 43 | |
| 44 def send_head(self): | |
| 45 """Version of send_head that support CGI scripts""" | |
| 46 if self.is_cgi(): | |
| 47 return self.run_cgi() | |
| 48 else: | |
| 49 return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self) | |
| 50 | |
| 51 def is_cgi(self): | |
| 52 """test whether PATH corresponds to a CGI script. | |
| 53 | |
| 54 Return a tuple (dir, rest) if PATH requires running a | |
| 55 CGI script, None if not. Note that rest begins with a | |
| 56 slash if it is not empty. | |
| 57 | |
| 58 The default implementation tests whether the path | |
| 59 begins with one of the strings in the list | |
| 60 self.cgi_directories (and the next character is a '/' | |
| 61 or the end of the string). | |
| 62 | |
| 63 """ | |
| 64 | |
| 65 path = self.path | |
| 66 | |
| 67 for x in self.cgi_directories: | |
| 68 i = len(x) | |
| 69 if path[:i] == x and (not path[i:] or path[i] == '/'): | |
| 70 self.cgi_info = path[:i], path[i+1:] | |
| 71 return 1 | |
| 72 return 0 | |
| 73 | |
| 74 cgi_directories = ['/cgi-bin', '/htbin'] | |
| 75 | |
| 76 def run_cgi(self): | |
| 77 """Execute a CGI script.""" | |
| 78 dir, rest = self.cgi_info | |
| 79 i = string.rfind(rest, '?') | |
| 80 if i >= 0: | |
| 81 rest, query = rest[:i], rest[i+1:] | |
| 82 else: | |
| 83 query = '' | |
| 84 i = string.find(rest, '/') | |
| 85 if i >= 0: | |
| 86 script, rest = rest[:i], rest[i:] | |
| 87 else: | |
| 88 script, rest = rest, '' | |
| 89 scriptname = dir + '/' + script | |
| 90 scriptfile = self.translate_path(scriptname) | |
| 91 if not os.path.exists(scriptfile): | |
| 92 self.send_error(404, "No such CGI script (%s)" % `scriptname`) | |
| 93 return | |
| 94 if not os.path.isfile(scriptfile): | |
| 95 self.send_error(403, "CGI script is not a plain file (%s)" % | |
| 96 `scriptname`) | |
| 97 return | |
| 98 if not executable(scriptfile): | |
| 99 self.send_error(403, "CGI script is not executable (%s)" % | |
| 100 `scriptname`) | |
| 101 return | |
| 102 nobody = nobody_uid() | |
| 103 self.send_response(200, "Script output follows") | |
| 104 self.wfile.flush() # Always flush before forking | |
| 105 pid = os.fork() | |
| 106 if pid != 0: | |
| 107 # Parent | |
| 108 pid, sts = os.waitpid(pid, 0) | |
| 109 if sts: | |
| 110 self.log_error("CGI script exit status x%x" % sts) | |
| 111 return | |
| 112 # Child | |
| 113 try: | |
| 114 # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html | |
| 115 # XXX Much of the following could be prepared ahead of time! | |
| 116 env = {} | |
| 117 env['SERVER_SOFTWARE'] = self.version_string() | |
| 118 env['SERVER_NAME'] = self.server.server_name | |
| 119 env['GATEWAY_INTERFACE'] = 'CGI/1.1' | |
| 120 env['SERVER_PROTOCOL'] = self.protocol_version | |
| 121 env['SERVER_PORT'] = str(self.server.server_port) | |
| 122 env['REQUEST_METHOD'] = self.command | |
| 123 uqrest = urllib.unquote(rest) | |
| 124 env['PATH_INFO'] = uqrest | |
| 125 env['PATH_TRANSLATED'] = self.translate_path(uqrest) | |
| 126 env['SCRIPT_NAME'] = scriptname | |
| 127 if query: | |
| 128 env['QUERY_STRING'] = query | |
| 129 host = self.address_string() | |
| 130 if host != self.client_address[0]: | |
| 131 env['REMOTE_HOST'] = host | |
| 132 env['REMOTE_ADDR'] = self.client_address[0] | |
| 133 # AUTH_TYPE | |
| 134 # REMOTE_USER | |
| 135 # REMOTE_IDENT | |
| 136 env['CONTENT_TYPE'] = self.headers.type | |
| 137 length = self.headers.getheader('content-length') | |
| 138 if length: | |
| 139 env['CONTENT_LENGTH'] = length | |
| 140 accept = [] | |
| 141 for line in self.headers.getallmatchingheaders('accept'): | |
| 142 if line[:1] in string.whitespace: | |
| 143 accept.append(string.strip(line)) | |
| 144 else: | |
| 145 accept = accept + string.split(line[7:]) | |
| 146 env['HTTP_ACCEPT'] = string.joinfields(accept, ',') | |
| 147 ua = self.headers.getheader('user-agent') | |
| 148 if ua: | |
| 149 env['HTTP_USER_AGENT'] = ua | |
| 150 # XXX Other HTTP_* headers | |
| 151 import regsub | |
| 152 decoded_query = regsub.gsub('+', ' ', query) | |
| 153 try: | |
| 154 os.setuid(nobody) | |
| 155 except os.error: | |
| 156 pass | |
| 157 os.dup2(self.rfile.fileno(), 0) | |
| 158 os.dup2(self.wfile.fileno(), 1) | |
| 159 print scriptfile, script, decoded_query | |
| 160 os.execve(scriptfile, | |
| 161 [script, decoded_query], | |
| 162 env) | |
| 163 except: | |
| 164 self.server.handle_error(self.request, self.client_address) | |
| 165 os._exit(127) | |
| 166 | |
| 167 | |
| 168 nobody = None | |
| 169 | |
| 170 def nobody_uid(): | |
| 171 """Internal routine to get nobody's uid""" | |
| 172 global nobody | |
| 173 if nobody: | |
| 174 return nobody | |
| 175 import pwd | |
| 176 try: | |
| 177 nobody = pwd.getpwnam('nobody')[2] | |
| 178 except pwd.error: | |
| 179 nobody = 1 + max(map(lambda x: x[2], pwd.getpwall())) | |
| 180 return nobody | |
| 181 | |
| 182 | |
| 183 def executable(path): | |
| 184 """Test for executable file.""" | |
| 185 try: | |
| 186 st = os.stat(path) | |
| 187 except os.error: | |
| 188 return 0 | |
| 189 return st[0] & 0111 != 0 | |
| 190 | |
| 191 | |
| 192 def test(HandlerClass = CGIHTTPRequestHandler, | |
| 193 ServerClass = BaseHTTPServer.HTTPServer): | |
| 194 import sys | |
| 195 if sys.argv[1:2] == ['-r']: | |
| 196 db = MyArchive() | |
| 197 db.regenindices() | |
| 198 return | |
| 199 SimpleHTTPServer.test(HandlerClass, ServerClass) | |
| 200 | |
| 201 | |
| 202 if __name__ == '__main__': | |
| 203 test() |
