xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/http/server.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""HTTP server classes.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerNote: BaseHTTPRequestHandler doesn't implement any HTTP request; see
4*cda5da8dSAndroid Build Coastguard WorkerSimpleHTTPRequestHandler for simple implementations of GET, HEAD and POST,
5*cda5da8dSAndroid Build Coastguard Workerand CGIHTTPRequestHandler for CGI scripts.
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard WorkerIt does, however, optionally implement HTTP/1.1 persistent connections,
8*cda5da8dSAndroid Build Coastguard Workeras of version 0.3.
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard WorkerNotes on CGIHTTPRequestHandler
11*cda5da8dSAndroid Build Coastguard Worker------------------------------
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard WorkerThis class implements GET and POST requests to cgi-bin scripts.
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard WorkerIf the os.fork() function is not present (e.g. on Windows),
16*cda5da8dSAndroid Build Coastguard Workersubprocess.Popen() is used as a fallback, with slightly altered semantics.
17*cda5da8dSAndroid Build Coastguard Worker
18*cda5da8dSAndroid Build Coastguard WorkerIn all cases, the implementation is intentionally naive -- all
19*cda5da8dSAndroid Build Coastguard Workerrequests are executed synchronously.
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard WorkerSECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
22*cda5da8dSAndroid Build Coastguard Worker-- it may execute arbitrary Python code or external programs.
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard WorkerNote that status code 200 is sent prior to execution of a CGI script, so
25*cda5da8dSAndroid Build Coastguard Workerscripts cannot send other status codes such as 302 (redirect).
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard WorkerXXX To do:
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker- log requests even later (to capture byte count)
30*cda5da8dSAndroid Build Coastguard Worker- log user-agent header and other interesting goodies
31*cda5da8dSAndroid Build Coastguard Worker- send error log to separate file
32*cda5da8dSAndroid Build Coastguard Worker"""
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker# See also:
36*cda5da8dSAndroid Build Coastguard Worker#
37*cda5da8dSAndroid Build Coastguard Worker# HTTP Working Group                                        T. Berners-Lee
38*cda5da8dSAndroid Build Coastguard Worker# INTERNET-DRAFT                                            R. T. Fielding
39*cda5da8dSAndroid Build Coastguard Worker# <draft-ietf-http-v10-spec-00.txt>                     H. Frystyk Nielsen
40*cda5da8dSAndroid Build Coastguard Worker# Expires September 8, 1995                                  March 8, 1995
41*cda5da8dSAndroid Build Coastguard Worker#
42*cda5da8dSAndroid Build Coastguard Worker# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
43*cda5da8dSAndroid Build Coastguard Worker#
44*cda5da8dSAndroid Build Coastguard Worker# and
45*cda5da8dSAndroid Build Coastguard Worker#
46*cda5da8dSAndroid Build Coastguard Worker# Network Working Group                                      R. Fielding
47*cda5da8dSAndroid Build Coastguard Worker# Request for Comments: 2616                                       et al
48*cda5da8dSAndroid Build Coastguard Worker# Obsoletes: 2068                                              June 1999
49*cda5da8dSAndroid Build Coastguard Worker# Category: Standards Track
50*cda5da8dSAndroid Build Coastguard Worker#
51*cda5da8dSAndroid Build Coastguard Worker# URL: http://www.faqs.org/rfcs/rfc2616.html
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard Worker# Log files
54*cda5da8dSAndroid Build Coastguard Worker# ---------
55*cda5da8dSAndroid Build Coastguard Worker#
56*cda5da8dSAndroid Build Coastguard Worker# Here's a quote from the NCSA httpd docs about log file format.
57*cda5da8dSAndroid Build Coastguard Worker#
58*cda5da8dSAndroid Build Coastguard Worker# | The logfile format is as follows. Each line consists of:
59*cda5da8dSAndroid Build Coastguard Worker# |
60*cda5da8dSAndroid Build Coastguard Worker# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
61*cda5da8dSAndroid Build Coastguard Worker# |
62*cda5da8dSAndroid Build Coastguard Worker# |        host: Either the DNS name or the IP number of the remote client
63*cda5da8dSAndroid Build Coastguard Worker# |        rfc931: Any information returned by identd for this person,
64*cda5da8dSAndroid Build Coastguard Worker# |                - otherwise.
65*cda5da8dSAndroid Build Coastguard Worker# |        authuser: If user sent a userid for authentication, the user name,
66*cda5da8dSAndroid Build Coastguard Worker# |                  - otherwise.
67*cda5da8dSAndroid Build Coastguard Worker# |        DD: Day
68*cda5da8dSAndroid Build Coastguard Worker# |        Mon: Month (calendar name)
69*cda5da8dSAndroid Build Coastguard Worker# |        YYYY: Year
70*cda5da8dSAndroid Build Coastguard Worker# |        hh: hour (24-hour format, the machine's timezone)
71*cda5da8dSAndroid Build Coastguard Worker# |        mm: minutes
72*cda5da8dSAndroid Build Coastguard Worker# |        ss: seconds
73*cda5da8dSAndroid Build Coastguard Worker# |        request: The first line of the HTTP request as sent by the client.
74*cda5da8dSAndroid Build Coastguard Worker# |        ddd: the status code returned by the server, - if not available.
75*cda5da8dSAndroid Build Coastguard Worker# |        bbbb: the total number of bytes sent,
76*cda5da8dSAndroid Build Coastguard Worker# |              *not including the HTTP/1.0 header*, - if not available
77*cda5da8dSAndroid Build Coastguard Worker# |
78*cda5da8dSAndroid Build Coastguard Worker# | You can determine the name of the file accessed through request.
79*cda5da8dSAndroid Build Coastguard Worker#
80*cda5da8dSAndroid Build Coastguard Worker# (Actually, the latter is only true if you know the server configuration
81*cda5da8dSAndroid Build Coastguard Worker# at the time the request was made!)
82*cda5da8dSAndroid Build Coastguard Worker
83*cda5da8dSAndroid Build Coastguard Worker__version__ = "0.6"
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Worker__all__ = [
86*cda5da8dSAndroid Build Coastguard Worker    "HTTPServer", "ThreadingHTTPServer", "BaseHTTPRequestHandler",
87*cda5da8dSAndroid Build Coastguard Worker    "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler",
88*cda5da8dSAndroid Build Coastguard Worker]
89*cda5da8dSAndroid Build Coastguard Worker
90*cda5da8dSAndroid Build Coastguard Workerimport copy
91*cda5da8dSAndroid Build Coastguard Workerimport datetime
92*cda5da8dSAndroid Build Coastguard Workerimport email.utils
93*cda5da8dSAndroid Build Coastguard Workerimport html
94*cda5da8dSAndroid Build Coastguard Workerimport http.client
95*cda5da8dSAndroid Build Coastguard Workerimport io
96*cda5da8dSAndroid Build Coastguard Workerimport itertools
97*cda5da8dSAndroid Build Coastguard Workerimport mimetypes
98*cda5da8dSAndroid Build Coastguard Workerimport os
99*cda5da8dSAndroid Build Coastguard Workerimport posixpath
100*cda5da8dSAndroid Build Coastguard Workerimport select
101*cda5da8dSAndroid Build Coastguard Workerimport shutil
102*cda5da8dSAndroid Build Coastguard Workerimport socket # For gethostbyaddr()
103*cda5da8dSAndroid Build Coastguard Workerimport socketserver
104*cda5da8dSAndroid Build Coastguard Workerimport sys
105*cda5da8dSAndroid Build Coastguard Workerimport time
106*cda5da8dSAndroid Build Coastguard Workerimport urllib.parse
107*cda5da8dSAndroid Build Coastguard Worker
108*cda5da8dSAndroid Build Coastguard Workerfrom http import HTTPStatus
109*cda5da8dSAndroid Build Coastguard Worker
110*cda5da8dSAndroid Build Coastguard Worker
111*cda5da8dSAndroid Build Coastguard Worker# Default error message template
112*cda5da8dSAndroid Build Coastguard WorkerDEFAULT_ERROR_MESSAGE = """\
113*cda5da8dSAndroid Build Coastguard Worker<!DOCTYPE HTML>
114*cda5da8dSAndroid Build Coastguard Worker<html lang="en">
115*cda5da8dSAndroid Build Coastguard Worker    <head>
116*cda5da8dSAndroid Build Coastguard Worker        <meta charset="utf-8">
117*cda5da8dSAndroid Build Coastguard Worker        <title>Error response</title>
118*cda5da8dSAndroid Build Coastguard Worker    </head>
119*cda5da8dSAndroid Build Coastguard Worker    <body>
120*cda5da8dSAndroid Build Coastguard Worker        <h1>Error response</h1>
121*cda5da8dSAndroid Build Coastguard Worker        <p>Error code: %(code)d</p>
122*cda5da8dSAndroid Build Coastguard Worker        <p>Message: %(message)s.</p>
123*cda5da8dSAndroid Build Coastguard Worker        <p>Error code explanation: %(code)s - %(explain)s.</p>
124*cda5da8dSAndroid Build Coastguard Worker    </body>
125*cda5da8dSAndroid Build Coastguard Worker</html>
126*cda5da8dSAndroid Build Coastguard Worker"""
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard WorkerDEFAULT_ERROR_CONTENT_TYPE = "text/html;charset=utf-8"
129*cda5da8dSAndroid Build Coastguard Worker
130*cda5da8dSAndroid Build Coastguard Workerclass HTTPServer(socketserver.TCPServer):
131*cda5da8dSAndroid Build Coastguard Worker
132*cda5da8dSAndroid Build Coastguard Worker    allow_reuse_address = 1    # Seems to make sense in testing environment
133*cda5da8dSAndroid Build Coastguard Worker
134*cda5da8dSAndroid Build Coastguard Worker    def server_bind(self):
135*cda5da8dSAndroid Build Coastguard Worker        """Override server_bind to store the server name."""
136*cda5da8dSAndroid Build Coastguard Worker        socketserver.TCPServer.server_bind(self)
137*cda5da8dSAndroid Build Coastguard Worker        host, port = self.server_address[:2]
138*cda5da8dSAndroid Build Coastguard Worker        self.server_name = socket.getfqdn(host)
139*cda5da8dSAndroid Build Coastguard Worker        self.server_port = port
140*cda5da8dSAndroid Build Coastguard Worker
141*cda5da8dSAndroid Build Coastguard Worker
142*cda5da8dSAndroid Build Coastguard Workerclass ThreadingHTTPServer(socketserver.ThreadingMixIn, HTTPServer):
143*cda5da8dSAndroid Build Coastguard Worker    daemon_threads = True
144*cda5da8dSAndroid Build Coastguard Worker
145*cda5da8dSAndroid Build Coastguard Worker
146*cda5da8dSAndroid Build Coastguard Workerclass BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
147*cda5da8dSAndroid Build Coastguard Worker
148*cda5da8dSAndroid Build Coastguard Worker    """HTTP request handler base class.
149*cda5da8dSAndroid Build Coastguard Worker
150*cda5da8dSAndroid Build Coastguard Worker    The following explanation of HTTP serves to guide you through the
151*cda5da8dSAndroid Build Coastguard Worker    code as well as to expose any misunderstandings I may have about
152*cda5da8dSAndroid Build Coastguard Worker    HTTP (so you don't need to read the code to figure out I'm wrong
153*cda5da8dSAndroid Build Coastguard Worker    :-).
154*cda5da8dSAndroid Build Coastguard Worker
155*cda5da8dSAndroid Build Coastguard Worker    HTTP (HyperText Transfer Protocol) is an extensible protocol on
156*cda5da8dSAndroid Build Coastguard Worker    top of a reliable stream transport (e.g. TCP/IP).  The protocol
157*cda5da8dSAndroid Build Coastguard Worker    recognizes three parts to a request:
158*cda5da8dSAndroid Build Coastguard Worker
159*cda5da8dSAndroid Build Coastguard Worker    1. One line identifying the request type and path
160*cda5da8dSAndroid Build Coastguard Worker    2. An optional set of RFC-822-style headers
161*cda5da8dSAndroid Build Coastguard Worker    3. An optional data part
162*cda5da8dSAndroid Build Coastguard Worker
163*cda5da8dSAndroid Build Coastguard Worker    The headers and data are separated by a blank line.
164*cda5da8dSAndroid Build Coastguard Worker
165*cda5da8dSAndroid Build Coastguard Worker    The first line of the request has the form
166*cda5da8dSAndroid Build Coastguard Worker
167*cda5da8dSAndroid Build Coastguard Worker    <command> <path> <version>
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker    where <command> is a (case-sensitive) keyword such as GET or POST,
170*cda5da8dSAndroid Build Coastguard Worker    <path> is a string containing path information for the request,
171*cda5da8dSAndroid Build Coastguard Worker    and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
172*cda5da8dSAndroid Build Coastguard Worker    <path> is encoded using the URL encoding scheme (using %xx to signify
173*cda5da8dSAndroid Build Coastguard Worker    the ASCII character with hex code xx).
174*cda5da8dSAndroid Build Coastguard Worker
175*cda5da8dSAndroid Build Coastguard Worker    The specification specifies that lines are separated by CRLF but
176*cda5da8dSAndroid Build Coastguard Worker    for compatibility with the widest range of clients recommends
177*cda5da8dSAndroid Build Coastguard Worker    servers also handle LF.  Similarly, whitespace in the request line
178*cda5da8dSAndroid Build Coastguard Worker    is treated sensibly (allowing multiple spaces between components
179*cda5da8dSAndroid Build Coastguard Worker    and allowing trailing whitespace).
180*cda5da8dSAndroid Build Coastguard Worker
181*cda5da8dSAndroid Build Coastguard Worker    Similarly, for output, lines ought to be separated by CRLF pairs
182*cda5da8dSAndroid Build Coastguard Worker    but most clients grok LF characters just fine.
183*cda5da8dSAndroid Build Coastguard Worker
184*cda5da8dSAndroid Build Coastguard Worker    If the first line of the request has the form
185*cda5da8dSAndroid Build Coastguard Worker
186*cda5da8dSAndroid Build Coastguard Worker    <command> <path>
187*cda5da8dSAndroid Build Coastguard Worker
188*cda5da8dSAndroid Build Coastguard Worker    (i.e. <version> is left out) then this is assumed to be an HTTP
189*cda5da8dSAndroid Build Coastguard Worker    0.9 request; this form has no optional headers and data part and
190*cda5da8dSAndroid Build Coastguard Worker    the reply consists of just the data.
191*cda5da8dSAndroid Build Coastguard Worker
192*cda5da8dSAndroid Build Coastguard Worker    The reply form of the HTTP 1.x protocol again has three parts:
193*cda5da8dSAndroid Build Coastguard Worker
194*cda5da8dSAndroid Build Coastguard Worker    1. One line giving the response code
195*cda5da8dSAndroid Build Coastguard Worker    2. An optional set of RFC-822-style headers
196*cda5da8dSAndroid Build Coastguard Worker    3. The data
197*cda5da8dSAndroid Build Coastguard Worker
198*cda5da8dSAndroid Build Coastguard Worker    Again, the headers and data are separated by a blank line.
199*cda5da8dSAndroid Build Coastguard Worker
200*cda5da8dSAndroid Build Coastguard Worker    The response code line has the form
201*cda5da8dSAndroid Build Coastguard Worker
202*cda5da8dSAndroid Build Coastguard Worker    <version> <responsecode> <responsestring>
203*cda5da8dSAndroid Build Coastguard Worker
204*cda5da8dSAndroid Build Coastguard Worker    where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
205*cda5da8dSAndroid Build Coastguard Worker    <responsecode> is a 3-digit response code indicating success or
206*cda5da8dSAndroid Build Coastguard Worker    failure of the request, and <responsestring> is an optional
207*cda5da8dSAndroid Build Coastguard Worker    human-readable string explaining what the response code means.
208*cda5da8dSAndroid Build Coastguard Worker
209*cda5da8dSAndroid Build Coastguard Worker    This server parses the request and the headers, and then calls a
210*cda5da8dSAndroid Build Coastguard Worker    function specific to the request type (<command>).  Specifically,
211*cda5da8dSAndroid Build Coastguard Worker    a request SPAM will be handled by a method do_SPAM().  If no
212*cda5da8dSAndroid Build Coastguard Worker    such method exists the server sends an error response to the
213*cda5da8dSAndroid Build Coastguard Worker    client.  If it exists, it is called with no arguments:
214*cda5da8dSAndroid Build Coastguard Worker
215*cda5da8dSAndroid Build Coastguard Worker    do_SPAM()
216*cda5da8dSAndroid Build Coastguard Worker
217*cda5da8dSAndroid Build Coastguard Worker    Note that the request name is case sensitive (i.e. SPAM and spam
218*cda5da8dSAndroid Build Coastguard Worker    are different requests).
219*cda5da8dSAndroid Build Coastguard Worker
220*cda5da8dSAndroid Build Coastguard Worker    The various request details are stored in instance variables:
221*cda5da8dSAndroid Build Coastguard Worker
222*cda5da8dSAndroid Build Coastguard Worker    - client_address is the client IP address in the form (host,
223*cda5da8dSAndroid Build Coastguard Worker    port);
224*cda5da8dSAndroid Build Coastguard Worker
225*cda5da8dSAndroid Build Coastguard Worker    - command, path and version are the broken-down request line;
226*cda5da8dSAndroid Build Coastguard Worker
227*cda5da8dSAndroid Build Coastguard Worker    - headers is an instance of email.message.Message (or a derived
228*cda5da8dSAndroid Build Coastguard Worker    class) containing the header information;
229*cda5da8dSAndroid Build Coastguard Worker
230*cda5da8dSAndroid Build Coastguard Worker    - rfile is a file object open for reading positioned at the
231*cda5da8dSAndroid Build Coastguard Worker    start of the optional input data part;
232*cda5da8dSAndroid Build Coastguard Worker
233*cda5da8dSAndroid Build Coastguard Worker    - wfile is a file object open for writing.
234*cda5da8dSAndroid Build Coastguard Worker
235*cda5da8dSAndroid Build Coastguard Worker    IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
236*cda5da8dSAndroid Build Coastguard Worker
237*cda5da8dSAndroid Build Coastguard Worker    The first thing to be written must be the response line.  Then
238*cda5da8dSAndroid Build Coastguard Worker    follow 0 or more header lines, then a blank line, and then the
239*cda5da8dSAndroid Build Coastguard Worker    actual data (if any).  The meaning of the header lines depends on
240*cda5da8dSAndroid Build Coastguard Worker    the command executed by the server; in most cases, when data is
241*cda5da8dSAndroid Build Coastguard Worker    returned, there should be at least one header line of the form
242*cda5da8dSAndroid Build Coastguard Worker
243*cda5da8dSAndroid Build Coastguard Worker    Content-type: <type>/<subtype>
244*cda5da8dSAndroid Build Coastguard Worker
245*cda5da8dSAndroid Build Coastguard Worker    where <type> and <subtype> should be registered MIME types,
246*cda5da8dSAndroid Build Coastguard Worker    e.g. "text/html" or "text/plain".
247*cda5da8dSAndroid Build Coastguard Worker
248*cda5da8dSAndroid Build Coastguard Worker    """
249*cda5da8dSAndroid Build Coastguard Worker
250*cda5da8dSAndroid Build Coastguard Worker    # The Python system version, truncated to its first component.
251*cda5da8dSAndroid Build Coastguard Worker    sys_version = "Python/" + sys.version.split()[0]
252*cda5da8dSAndroid Build Coastguard Worker
253*cda5da8dSAndroid Build Coastguard Worker    # The server software version.  You may want to override this.
254*cda5da8dSAndroid Build Coastguard Worker    # The format is multiple whitespace-separated strings,
255*cda5da8dSAndroid Build Coastguard Worker    # where each string is of the form name[/version].
256*cda5da8dSAndroid Build Coastguard Worker    server_version = "BaseHTTP/" + __version__
257*cda5da8dSAndroid Build Coastguard Worker
258*cda5da8dSAndroid Build Coastguard Worker    error_message_format = DEFAULT_ERROR_MESSAGE
259*cda5da8dSAndroid Build Coastguard Worker    error_content_type = DEFAULT_ERROR_CONTENT_TYPE
260*cda5da8dSAndroid Build Coastguard Worker
261*cda5da8dSAndroid Build Coastguard Worker    # The default request version.  This only affects responses up until
262*cda5da8dSAndroid Build Coastguard Worker    # the point where the request line is parsed, so it mainly decides what
263*cda5da8dSAndroid Build Coastguard Worker    # the client gets back when sending a malformed request line.
264*cda5da8dSAndroid Build Coastguard Worker    # Most web servers default to HTTP 0.9, i.e. don't send a status line.
265*cda5da8dSAndroid Build Coastguard Worker    default_request_version = "HTTP/0.9"
266*cda5da8dSAndroid Build Coastguard Worker
267*cda5da8dSAndroid Build Coastguard Worker    def parse_request(self):
268*cda5da8dSAndroid Build Coastguard Worker        """Parse a request (internal).
269*cda5da8dSAndroid Build Coastguard Worker
270*cda5da8dSAndroid Build Coastguard Worker        The request should be stored in self.raw_requestline; the results
271*cda5da8dSAndroid Build Coastguard Worker        are in self.command, self.path, self.request_version and
272*cda5da8dSAndroid Build Coastguard Worker        self.headers.
273*cda5da8dSAndroid Build Coastguard Worker
274*cda5da8dSAndroid Build Coastguard Worker        Return True for success, False for failure; on failure, any relevant
275*cda5da8dSAndroid Build Coastguard Worker        error response has already been sent back.
276*cda5da8dSAndroid Build Coastguard Worker
277*cda5da8dSAndroid Build Coastguard Worker        """
278*cda5da8dSAndroid Build Coastguard Worker        self.command = None  # set in case of error on the first line
279*cda5da8dSAndroid Build Coastguard Worker        self.request_version = version = self.default_request_version
280*cda5da8dSAndroid Build Coastguard Worker        self.close_connection = True
281*cda5da8dSAndroid Build Coastguard Worker        requestline = str(self.raw_requestline, 'iso-8859-1')
282*cda5da8dSAndroid Build Coastguard Worker        requestline = requestline.rstrip('\r\n')
283*cda5da8dSAndroid Build Coastguard Worker        self.requestline = requestline
284*cda5da8dSAndroid Build Coastguard Worker        words = requestline.split()
285*cda5da8dSAndroid Build Coastguard Worker        if len(words) == 0:
286*cda5da8dSAndroid Build Coastguard Worker            return False
287*cda5da8dSAndroid Build Coastguard Worker
288*cda5da8dSAndroid Build Coastguard Worker        if len(words) >= 3:  # Enough to determine protocol version
289*cda5da8dSAndroid Build Coastguard Worker            version = words[-1]
290*cda5da8dSAndroid Build Coastguard Worker            try:
291*cda5da8dSAndroid Build Coastguard Worker                if not version.startswith('HTTP/'):
292*cda5da8dSAndroid Build Coastguard Worker                    raise ValueError
293*cda5da8dSAndroid Build Coastguard Worker                base_version_number = version.split('/', 1)[1]
294*cda5da8dSAndroid Build Coastguard Worker                version_number = base_version_number.split(".")
295*cda5da8dSAndroid Build Coastguard Worker                # RFC 2145 section 3.1 says there can be only one "." and
296*cda5da8dSAndroid Build Coastguard Worker                #   - major and minor numbers MUST be treated as
297*cda5da8dSAndroid Build Coastguard Worker                #      separate integers;
298*cda5da8dSAndroid Build Coastguard Worker                #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
299*cda5da8dSAndroid Build Coastguard Worker                #      turn is lower than HTTP/12.3;
300*cda5da8dSAndroid Build Coastguard Worker                #   - Leading zeros MUST be ignored by recipients.
301*cda5da8dSAndroid Build Coastguard Worker                if len(version_number) != 2:
302*cda5da8dSAndroid Build Coastguard Worker                    raise ValueError
303*cda5da8dSAndroid Build Coastguard Worker                if any(not component.isdigit() for component in version_number):
304*cda5da8dSAndroid Build Coastguard Worker                    raise ValueError("non digit in http version")
305*cda5da8dSAndroid Build Coastguard Worker                if any(len(component) > 10 for component in version_number):
306*cda5da8dSAndroid Build Coastguard Worker                    raise ValueError("unreasonable length http version")
307*cda5da8dSAndroid Build Coastguard Worker                version_number = int(version_number[0]), int(version_number[1])
308*cda5da8dSAndroid Build Coastguard Worker            except (ValueError, IndexError):
309*cda5da8dSAndroid Build Coastguard Worker                self.send_error(
310*cda5da8dSAndroid Build Coastguard Worker                    HTTPStatus.BAD_REQUEST,
311*cda5da8dSAndroid Build Coastguard Worker                    "Bad request version (%r)" % version)
312*cda5da8dSAndroid Build Coastguard Worker                return False
313*cda5da8dSAndroid Build Coastguard Worker            if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
314*cda5da8dSAndroid Build Coastguard Worker                self.close_connection = False
315*cda5da8dSAndroid Build Coastguard Worker            if version_number >= (2, 0):
316*cda5da8dSAndroid Build Coastguard Worker                self.send_error(
317*cda5da8dSAndroid Build Coastguard Worker                    HTTPStatus.HTTP_VERSION_NOT_SUPPORTED,
318*cda5da8dSAndroid Build Coastguard Worker                    "Invalid HTTP version (%s)" % base_version_number)
319*cda5da8dSAndroid Build Coastguard Worker                return False
320*cda5da8dSAndroid Build Coastguard Worker            self.request_version = version
321*cda5da8dSAndroid Build Coastguard Worker
322*cda5da8dSAndroid Build Coastguard Worker        if not 2 <= len(words) <= 3:
323*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
324*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.BAD_REQUEST,
325*cda5da8dSAndroid Build Coastguard Worker                "Bad request syntax (%r)" % requestline)
326*cda5da8dSAndroid Build Coastguard Worker            return False
327*cda5da8dSAndroid Build Coastguard Worker        command, path = words[:2]
328*cda5da8dSAndroid Build Coastguard Worker        if len(words) == 2:
329*cda5da8dSAndroid Build Coastguard Worker            self.close_connection = True
330*cda5da8dSAndroid Build Coastguard Worker            if command != 'GET':
331*cda5da8dSAndroid Build Coastguard Worker                self.send_error(
332*cda5da8dSAndroid Build Coastguard Worker                    HTTPStatus.BAD_REQUEST,
333*cda5da8dSAndroid Build Coastguard Worker                    "Bad HTTP/0.9 request type (%r)" % command)
334*cda5da8dSAndroid Build Coastguard Worker                return False
335*cda5da8dSAndroid Build Coastguard Worker        self.command, self.path = command, path
336*cda5da8dSAndroid Build Coastguard Worker
337*cda5da8dSAndroid Build Coastguard Worker        # gh-87389: The purpose of replacing '//' with '/' is to protect
338*cda5da8dSAndroid Build Coastguard Worker        # against open redirect attacks possibly triggered if the path starts
339*cda5da8dSAndroid Build Coastguard Worker        # with '//' because http clients treat //path as an absolute URI
340*cda5da8dSAndroid Build Coastguard Worker        # without scheme (similar to http://path) rather than a path.
341*cda5da8dSAndroid Build Coastguard Worker        if self.path.startswith('//'):
342*cda5da8dSAndroid Build Coastguard Worker            self.path = '/' + self.path.lstrip('/')  # Reduce to a single /
343*cda5da8dSAndroid Build Coastguard Worker
344*cda5da8dSAndroid Build Coastguard Worker        # Examine the headers and look for a Connection directive.
345*cda5da8dSAndroid Build Coastguard Worker        try:
346*cda5da8dSAndroid Build Coastguard Worker            self.headers = http.client.parse_headers(self.rfile,
347*cda5da8dSAndroid Build Coastguard Worker                                                     _class=self.MessageClass)
348*cda5da8dSAndroid Build Coastguard Worker        except http.client.LineTooLong as err:
349*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
350*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE,
351*cda5da8dSAndroid Build Coastguard Worker                "Line too long",
352*cda5da8dSAndroid Build Coastguard Worker                str(err))
353*cda5da8dSAndroid Build Coastguard Worker            return False
354*cda5da8dSAndroid Build Coastguard Worker        except http.client.HTTPException as err:
355*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
356*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE,
357*cda5da8dSAndroid Build Coastguard Worker                "Too many headers",
358*cda5da8dSAndroid Build Coastguard Worker                str(err)
359*cda5da8dSAndroid Build Coastguard Worker            )
360*cda5da8dSAndroid Build Coastguard Worker            return False
361*cda5da8dSAndroid Build Coastguard Worker
362*cda5da8dSAndroid Build Coastguard Worker        conntype = self.headers.get('Connection', "")
363*cda5da8dSAndroid Build Coastguard Worker        if conntype.lower() == 'close':
364*cda5da8dSAndroid Build Coastguard Worker            self.close_connection = True
365*cda5da8dSAndroid Build Coastguard Worker        elif (conntype.lower() == 'keep-alive' and
366*cda5da8dSAndroid Build Coastguard Worker              self.protocol_version >= "HTTP/1.1"):
367*cda5da8dSAndroid Build Coastguard Worker            self.close_connection = False
368*cda5da8dSAndroid Build Coastguard Worker        # Examine the headers and look for an Expect directive
369*cda5da8dSAndroid Build Coastguard Worker        expect = self.headers.get('Expect', "")
370*cda5da8dSAndroid Build Coastguard Worker        if (expect.lower() == "100-continue" and
371*cda5da8dSAndroid Build Coastguard Worker                self.protocol_version >= "HTTP/1.1" and
372*cda5da8dSAndroid Build Coastguard Worker                self.request_version >= "HTTP/1.1"):
373*cda5da8dSAndroid Build Coastguard Worker            if not self.handle_expect_100():
374*cda5da8dSAndroid Build Coastguard Worker                return False
375*cda5da8dSAndroid Build Coastguard Worker        return True
376*cda5da8dSAndroid Build Coastguard Worker
377*cda5da8dSAndroid Build Coastguard Worker    def handle_expect_100(self):
378*cda5da8dSAndroid Build Coastguard Worker        """Decide what to do with an "Expect: 100-continue" header.
379*cda5da8dSAndroid Build Coastguard Worker
380*cda5da8dSAndroid Build Coastguard Worker        If the client is expecting a 100 Continue response, we must
381*cda5da8dSAndroid Build Coastguard Worker        respond with either a 100 Continue or a final response before
382*cda5da8dSAndroid Build Coastguard Worker        waiting for the request body. The default is to always respond
383*cda5da8dSAndroid Build Coastguard Worker        with a 100 Continue. You can behave differently (for example,
384*cda5da8dSAndroid Build Coastguard Worker        reject unauthorized requests) by overriding this method.
385*cda5da8dSAndroid Build Coastguard Worker
386*cda5da8dSAndroid Build Coastguard Worker        This method should either return True (possibly after sending
387*cda5da8dSAndroid Build Coastguard Worker        a 100 Continue response) or send an error response and return
388*cda5da8dSAndroid Build Coastguard Worker        False.
389*cda5da8dSAndroid Build Coastguard Worker
390*cda5da8dSAndroid Build Coastguard Worker        """
391*cda5da8dSAndroid Build Coastguard Worker        self.send_response_only(HTTPStatus.CONTINUE)
392*cda5da8dSAndroid Build Coastguard Worker        self.end_headers()
393*cda5da8dSAndroid Build Coastguard Worker        return True
394*cda5da8dSAndroid Build Coastguard Worker
395*cda5da8dSAndroid Build Coastguard Worker    def handle_one_request(self):
396*cda5da8dSAndroid Build Coastguard Worker        """Handle a single HTTP request.
397*cda5da8dSAndroid Build Coastguard Worker
398*cda5da8dSAndroid Build Coastguard Worker        You normally don't need to override this method; see the class
399*cda5da8dSAndroid Build Coastguard Worker        __doc__ string for information on how to handle specific HTTP
400*cda5da8dSAndroid Build Coastguard Worker        commands such as GET and POST.
401*cda5da8dSAndroid Build Coastguard Worker
402*cda5da8dSAndroid Build Coastguard Worker        """
403*cda5da8dSAndroid Build Coastguard Worker        try:
404*cda5da8dSAndroid Build Coastguard Worker            self.raw_requestline = self.rfile.readline(65537)
405*cda5da8dSAndroid Build Coastguard Worker            if len(self.raw_requestline) > 65536:
406*cda5da8dSAndroid Build Coastguard Worker                self.requestline = ''
407*cda5da8dSAndroid Build Coastguard Worker                self.request_version = ''
408*cda5da8dSAndroid Build Coastguard Worker                self.command = ''
409*cda5da8dSAndroid Build Coastguard Worker                self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)
410*cda5da8dSAndroid Build Coastguard Worker                return
411*cda5da8dSAndroid Build Coastguard Worker            if not self.raw_requestline:
412*cda5da8dSAndroid Build Coastguard Worker                self.close_connection = True
413*cda5da8dSAndroid Build Coastguard Worker                return
414*cda5da8dSAndroid Build Coastguard Worker            if not self.parse_request():
415*cda5da8dSAndroid Build Coastguard Worker                # An error code has been sent, just exit
416*cda5da8dSAndroid Build Coastguard Worker                return
417*cda5da8dSAndroid Build Coastguard Worker            mname = 'do_' + self.command
418*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(self, mname):
419*cda5da8dSAndroid Build Coastguard Worker                self.send_error(
420*cda5da8dSAndroid Build Coastguard Worker                    HTTPStatus.NOT_IMPLEMENTED,
421*cda5da8dSAndroid Build Coastguard Worker                    "Unsupported method (%r)" % self.command)
422*cda5da8dSAndroid Build Coastguard Worker                return
423*cda5da8dSAndroid Build Coastguard Worker            method = getattr(self, mname)
424*cda5da8dSAndroid Build Coastguard Worker            method()
425*cda5da8dSAndroid Build Coastguard Worker            self.wfile.flush() #actually send the response if not already done.
426*cda5da8dSAndroid Build Coastguard Worker        except TimeoutError as e:
427*cda5da8dSAndroid Build Coastguard Worker            #a read or a write timed out.  Discard this connection
428*cda5da8dSAndroid Build Coastguard Worker            self.log_error("Request timed out: %r", e)
429*cda5da8dSAndroid Build Coastguard Worker            self.close_connection = True
430*cda5da8dSAndroid Build Coastguard Worker            return
431*cda5da8dSAndroid Build Coastguard Worker
432*cda5da8dSAndroid Build Coastguard Worker    def handle(self):
433*cda5da8dSAndroid Build Coastguard Worker        """Handle multiple requests if necessary."""
434*cda5da8dSAndroid Build Coastguard Worker        self.close_connection = True
435*cda5da8dSAndroid Build Coastguard Worker
436*cda5da8dSAndroid Build Coastguard Worker        self.handle_one_request()
437*cda5da8dSAndroid Build Coastguard Worker        while not self.close_connection:
438*cda5da8dSAndroid Build Coastguard Worker            self.handle_one_request()
439*cda5da8dSAndroid Build Coastguard Worker
440*cda5da8dSAndroid Build Coastguard Worker    def send_error(self, code, message=None, explain=None):
441*cda5da8dSAndroid Build Coastguard Worker        """Send and log an error reply.
442*cda5da8dSAndroid Build Coastguard Worker
443*cda5da8dSAndroid Build Coastguard Worker        Arguments are
444*cda5da8dSAndroid Build Coastguard Worker        * code:    an HTTP error code
445*cda5da8dSAndroid Build Coastguard Worker                   3 digits
446*cda5da8dSAndroid Build Coastguard Worker        * message: a simple optional 1 line reason phrase.
447*cda5da8dSAndroid Build Coastguard Worker                   *( HTAB / SP / VCHAR / %x80-FF )
448*cda5da8dSAndroid Build Coastguard Worker                   defaults to short entry matching the response code
449*cda5da8dSAndroid Build Coastguard Worker        * explain: a detailed message defaults to the long entry
450*cda5da8dSAndroid Build Coastguard Worker                   matching the response code.
451*cda5da8dSAndroid Build Coastguard Worker
452*cda5da8dSAndroid Build Coastguard Worker        This sends an error response (so it must be called before any
453*cda5da8dSAndroid Build Coastguard Worker        output has been generated), logs the error, and finally sends
454*cda5da8dSAndroid Build Coastguard Worker        a piece of HTML explaining the error to the user.
455*cda5da8dSAndroid Build Coastguard Worker
456*cda5da8dSAndroid Build Coastguard Worker        """
457*cda5da8dSAndroid Build Coastguard Worker
458*cda5da8dSAndroid Build Coastguard Worker        try:
459*cda5da8dSAndroid Build Coastguard Worker            shortmsg, longmsg = self.responses[code]
460*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
461*cda5da8dSAndroid Build Coastguard Worker            shortmsg, longmsg = '???', '???'
462*cda5da8dSAndroid Build Coastguard Worker        if message is None:
463*cda5da8dSAndroid Build Coastguard Worker            message = shortmsg
464*cda5da8dSAndroid Build Coastguard Worker        if explain is None:
465*cda5da8dSAndroid Build Coastguard Worker            explain = longmsg
466*cda5da8dSAndroid Build Coastguard Worker        self.log_error("code %d, message %s", code, message)
467*cda5da8dSAndroid Build Coastguard Worker        self.send_response(code, message)
468*cda5da8dSAndroid Build Coastguard Worker        self.send_header('Connection', 'close')
469*cda5da8dSAndroid Build Coastguard Worker
470*cda5da8dSAndroid Build Coastguard Worker        # Message body is omitted for cases described in:
471*cda5da8dSAndroid Build Coastguard Worker        #  - RFC7230: 3.3. 1xx, 204(No Content), 304(Not Modified)
472*cda5da8dSAndroid Build Coastguard Worker        #  - RFC7231: 6.3.6. 205(Reset Content)
473*cda5da8dSAndroid Build Coastguard Worker        body = None
474*cda5da8dSAndroid Build Coastguard Worker        if (code >= 200 and
475*cda5da8dSAndroid Build Coastguard Worker            code not in (HTTPStatus.NO_CONTENT,
476*cda5da8dSAndroid Build Coastguard Worker                         HTTPStatus.RESET_CONTENT,
477*cda5da8dSAndroid Build Coastguard Worker                         HTTPStatus.NOT_MODIFIED)):
478*cda5da8dSAndroid Build Coastguard Worker            # HTML encode to prevent Cross Site Scripting attacks
479*cda5da8dSAndroid Build Coastguard Worker            # (see bug #1100201)
480*cda5da8dSAndroid Build Coastguard Worker            content = (self.error_message_format % {
481*cda5da8dSAndroid Build Coastguard Worker                'code': code,
482*cda5da8dSAndroid Build Coastguard Worker                'message': html.escape(message, quote=False),
483*cda5da8dSAndroid Build Coastguard Worker                'explain': html.escape(explain, quote=False)
484*cda5da8dSAndroid Build Coastguard Worker            })
485*cda5da8dSAndroid Build Coastguard Worker            body = content.encode('UTF-8', 'replace')
486*cda5da8dSAndroid Build Coastguard Worker            self.send_header("Content-Type", self.error_content_type)
487*cda5da8dSAndroid Build Coastguard Worker            self.send_header('Content-Length', str(len(body)))
488*cda5da8dSAndroid Build Coastguard Worker        self.end_headers()
489*cda5da8dSAndroid Build Coastguard Worker
490*cda5da8dSAndroid Build Coastguard Worker        if self.command != 'HEAD' and body:
491*cda5da8dSAndroid Build Coastguard Worker            self.wfile.write(body)
492*cda5da8dSAndroid Build Coastguard Worker
493*cda5da8dSAndroid Build Coastguard Worker    def send_response(self, code, message=None):
494*cda5da8dSAndroid Build Coastguard Worker        """Add the response header to the headers buffer and log the
495*cda5da8dSAndroid Build Coastguard Worker        response code.
496*cda5da8dSAndroid Build Coastguard Worker
497*cda5da8dSAndroid Build Coastguard Worker        Also send two standard headers with the server software
498*cda5da8dSAndroid Build Coastguard Worker        version and the current date.
499*cda5da8dSAndroid Build Coastguard Worker
500*cda5da8dSAndroid Build Coastguard Worker        """
501*cda5da8dSAndroid Build Coastguard Worker        self.log_request(code)
502*cda5da8dSAndroid Build Coastguard Worker        self.send_response_only(code, message)
503*cda5da8dSAndroid Build Coastguard Worker        self.send_header('Server', self.version_string())
504*cda5da8dSAndroid Build Coastguard Worker        self.send_header('Date', self.date_time_string())
505*cda5da8dSAndroid Build Coastguard Worker
506*cda5da8dSAndroid Build Coastguard Worker    def send_response_only(self, code, message=None):
507*cda5da8dSAndroid Build Coastguard Worker        """Send the response header only."""
508*cda5da8dSAndroid Build Coastguard Worker        if self.request_version != 'HTTP/0.9':
509*cda5da8dSAndroid Build Coastguard Worker            if message is None:
510*cda5da8dSAndroid Build Coastguard Worker                if code in self.responses:
511*cda5da8dSAndroid Build Coastguard Worker                    message = self.responses[code][0]
512*cda5da8dSAndroid Build Coastguard Worker                else:
513*cda5da8dSAndroid Build Coastguard Worker                    message = ''
514*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(self, '_headers_buffer'):
515*cda5da8dSAndroid Build Coastguard Worker                self._headers_buffer = []
516*cda5da8dSAndroid Build Coastguard Worker            self._headers_buffer.append(("%s %d %s\r\n" %
517*cda5da8dSAndroid Build Coastguard Worker                    (self.protocol_version, code, message)).encode(
518*cda5da8dSAndroid Build Coastguard Worker                        'latin-1', 'strict'))
519*cda5da8dSAndroid Build Coastguard Worker
520*cda5da8dSAndroid Build Coastguard Worker    def send_header(self, keyword, value):
521*cda5da8dSAndroid Build Coastguard Worker        """Send a MIME header to the headers buffer."""
522*cda5da8dSAndroid Build Coastguard Worker        if self.request_version != 'HTTP/0.9':
523*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(self, '_headers_buffer'):
524*cda5da8dSAndroid Build Coastguard Worker                self._headers_buffer = []
525*cda5da8dSAndroid Build Coastguard Worker            self._headers_buffer.append(
526*cda5da8dSAndroid Build Coastguard Worker                ("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
527*cda5da8dSAndroid Build Coastguard Worker
528*cda5da8dSAndroid Build Coastguard Worker        if keyword.lower() == 'connection':
529*cda5da8dSAndroid Build Coastguard Worker            if value.lower() == 'close':
530*cda5da8dSAndroid Build Coastguard Worker                self.close_connection = True
531*cda5da8dSAndroid Build Coastguard Worker            elif value.lower() == 'keep-alive':
532*cda5da8dSAndroid Build Coastguard Worker                self.close_connection = False
533*cda5da8dSAndroid Build Coastguard Worker
534*cda5da8dSAndroid Build Coastguard Worker    def end_headers(self):
535*cda5da8dSAndroid Build Coastguard Worker        """Send the blank line ending the MIME headers."""
536*cda5da8dSAndroid Build Coastguard Worker        if self.request_version != 'HTTP/0.9':
537*cda5da8dSAndroid Build Coastguard Worker            self._headers_buffer.append(b"\r\n")
538*cda5da8dSAndroid Build Coastguard Worker            self.flush_headers()
539*cda5da8dSAndroid Build Coastguard Worker
540*cda5da8dSAndroid Build Coastguard Worker    def flush_headers(self):
541*cda5da8dSAndroid Build Coastguard Worker        if hasattr(self, '_headers_buffer'):
542*cda5da8dSAndroid Build Coastguard Worker            self.wfile.write(b"".join(self._headers_buffer))
543*cda5da8dSAndroid Build Coastguard Worker            self._headers_buffer = []
544*cda5da8dSAndroid Build Coastguard Worker
545*cda5da8dSAndroid Build Coastguard Worker    def log_request(self, code='-', size='-'):
546*cda5da8dSAndroid Build Coastguard Worker        """Log an accepted request.
547*cda5da8dSAndroid Build Coastguard Worker
548*cda5da8dSAndroid Build Coastguard Worker        This is called by send_response().
549*cda5da8dSAndroid Build Coastguard Worker
550*cda5da8dSAndroid Build Coastguard Worker        """
551*cda5da8dSAndroid Build Coastguard Worker        if isinstance(code, HTTPStatus):
552*cda5da8dSAndroid Build Coastguard Worker            code = code.value
553*cda5da8dSAndroid Build Coastguard Worker        self.log_message('"%s" %s %s',
554*cda5da8dSAndroid Build Coastguard Worker                         self.requestline, str(code), str(size))
555*cda5da8dSAndroid Build Coastguard Worker
556*cda5da8dSAndroid Build Coastguard Worker    def log_error(self, format, *args):
557*cda5da8dSAndroid Build Coastguard Worker        """Log an error.
558*cda5da8dSAndroid Build Coastguard Worker
559*cda5da8dSAndroid Build Coastguard Worker        This is called when a request cannot be fulfilled.  By
560*cda5da8dSAndroid Build Coastguard Worker        default it passes the message on to log_message().
561*cda5da8dSAndroid Build Coastguard Worker
562*cda5da8dSAndroid Build Coastguard Worker        Arguments are the same as for log_message().
563*cda5da8dSAndroid Build Coastguard Worker
564*cda5da8dSAndroid Build Coastguard Worker        XXX This should go to the separate error log.
565*cda5da8dSAndroid Build Coastguard Worker
566*cda5da8dSAndroid Build Coastguard Worker        """
567*cda5da8dSAndroid Build Coastguard Worker
568*cda5da8dSAndroid Build Coastguard Worker        self.log_message(format, *args)
569*cda5da8dSAndroid Build Coastguard Worker
570*cda5da8dSAndroid Build Coastguard Worker    # https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes
571*cda5da8dSAndroid Build Coastguard Worker    _control_char_table = str.maketrans(
572*cda5da8dSAndroid Build Coastguard Worker            {c: fr'\x{c:02x}' for c in itertools.chain(range(0x20), range(0x7f,0xa0))})
573*cda5da8dSAndroid Build Coastguard Worker    _control_char_table[ord('\\')] = r'\\'
574*cda5da8dSAndroid Build Coastguard Worker
575*cda5da8dSAndroid Build Coastguard Worker    def log_message(self, format, *args):
576*cda5da8dSAndroid Build Coastguard Worker        """Log an arbitrary message.
577*cda5da8dSAndroid Build Coastguard Worker
578*cda5da8dSAndroid Build Coastguard Worker        This is used by all other logging functions.  Override
579*cda5da8dSAndroid Build Coastguard Worker        it if you have specific logging wishes.
580*cda5da8dSAndroid Build Coastguard Worker
581*cda5da8dSAndroid Build Coastguard Worker        The first argument, FORMAT, is a format string for the
582*cda5da8dSAndroid Build Coastguard Worker        message to be logged.  If the format string contains
583*cda5da8dSAndroid Build Coastguard Worker        any % escapes requiring parameters, they should be
584*cda5da8dSAndroid Build Coastguard Worker        specified as subsequent arguments (it's just like
585*cda5da8dSAndroid Build Coastguard Worker        printf!).
586*cda5da8dSAndroid Build Coastguard Worker
587*cda5da8dSAndroid Build Coastguard Worker        The client ip and current date/time are prefixed to
588*cda5da8dSAndroid Build Coastguard Worker        every message.
589*cda5da8dSAndroid Build Coastguard Worker
590*cda5da8dSAndroid Build Coastguard Worker        Unicode control characters are replaced with escaped hex
591*cda5da8dSAndroid Build Coastguard Worker        before writing the output to stderr.
592*cda5da8dSAndroid Build Coastguard Worker
593*cda5da8dSAndroid Build Coastguard Worker        """
594*cda5da8dSAndroid Build Coastguard Worker
595*cda5da8dSAndroid Build Coastguard Worker        message = format % args
596*cda5da8dSAndroid Build Coastguard Worker        sys.stderr.write("%s - - [%s] %s\n" %
597*cda5da8dSAndroid Build Coastguard Worker                         (self.address_string(),
598*cda5da8dSAndroid Build Coastguard Worker                          self.log_date_time_string(),
599*cda5da8dSAndroid Build Coastguard Worker                          message.translate(self._control_char_table)))
600*cda5da8dSAndroid Build Coastguard Worker
601*cda5da8dSAndroid Build Coastguard Worker    def version_string(self):
602*cda5da8dSAndroid Build Coastguard Worker        """Return the server software version string."""
603*cda5da8dSAndroid Build Coastguard Worker        return self.server_version + ' ' + self.sys_version
604*cda5da8dSAndroid Build Coastguard Worker
605*cda5da8dSAndroid Build Coastguard Worker    def date_time_string(self, timestamp=None):
606*cda5da8dSAndroid Build Coastguard Worker        """Return the current date and time formatted for a message header."""
607*cda5da8dSAndroid Build Coastguard Worker        if timestamp is None:
608*cda5da8dSAndroid Build Coastguard Worker            timestamp = time.time()
609*cda5da8dSAndroid Build Coastguard Worker        return email.utils.formatdate(timestamp, usegmt=True)
610*cda5da8dSAndroid Build Coastguard Worker
611*cda5da8dSAndroid Build Coastguard Worker    def log_date_time_string(self):
612*cda5da8dSAndroid Build Coastguard Worker        """Return the current time formatted for logging."""
613*cda5da8dSAndroid Build Coastguard Worker        now = time.time()
614*cda5da8dSAndroid Build Coastguard Worker        year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
615*cda5da8dSAndroid Build Coastguard Worker        s = "%02d/%3s/%04d %02d:%02d:%02d" % (
616*cda5da8dSAndroid Build Coastguard Worker                day, self.monthname[month], year, hh, mm, ss)
617*cda5da8dSAndroid Build Coastguard Worker        return s
618*cda5da8dSAndroid Build Coastguard Worker
619*cda5da8dSAndroid Build Coastguard Worker    weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
620*cda5da8dSAndroid Build Coastguard Worker
621*cda5da8dSAndroid Build Coastguard Worker    monthname = [None,
622*cda5da8dSAndroid Build Coastguard Worker                 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
623*cda5da8dSAndroid Build Coastguard Worker                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
624*cda5da8dSAndroid Build Coastguard Worker
625*cda5da8dSAndroid Build Coastguard Worker    def address_string(self):
626*cda5da8dSAndroid Build Coastguard Worker        """Return the client address."""
627*cda5da8dSAndroid Build Coastguard Worker
628*cda5da8dSAndroid Build Coastguard Worker        return self.client_address[0]
629*cda5da8dSAndroid Build Coastguard Worker
630*cda5da8dSAndroid Build Coastguard Worker    # Essentially static class variables
631*cda5da8dSAndroid Build Coastguard Worker
632*cda5da8dSAndroid Build Coastguard Worker    # The version of the HTTP protocol we support.
633*cda5da8dSAndroid Build Coastguard Worker    # Set this to HTTP/1.1 to enable automatic keepalive
634*cda5da8dSAndroid Build Coastguard Worker    protocol_version = "HTTP/1.0"
635*cda5da8dSAndroid Build Coastguard Worker
636*cda5da8dSAndroid Build Coastguard Worker    # MessageClass used to parse headers
637*cda5da8dSAndroid Build Coastguard Worker    MessageClass = http.client.HTTPMessage
638*cda5da8dSAndroid Build Coastguard Worker
639*cda5da8dSAndroid Build Coastguard Worker    # hack to maintain backwards compatibility
640*cda5da8dSAndroid Build Coastguard Worker    responses = {
641*cda5da8dSAndroid Build Coastguard Worker        v: (v.phrase, v.description)
642*cda5da8dSAndroid Build Coastguard Worker        for v in HTTPStatus.__members__.values()
643*cda5da8dSAndroid Build Coastguard Worker    }
644*cda5da8dSAndroid Build Coastguard Worker
645*cda5da8dSAndroid Build Coastguard Worker
646*cda5da8dSAndroid Build Coastguard Workerclass SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
647*cda5da8dSAndroid Build Coastguard Worker
648*cda5da8dSAndroid Build Coastguard Worker    """Simple HTTP request handler with GET and HEAD commands.
649*cda5da8dSAndroid Build Coastguard Worker
650*cda5da8dSAndroid Build Coastguard Worker    This serves files from the current directory and any of its
651*cda5da8dSAndroid Build Coastguard Worker    subdirectories.  The MIME type for files is determined by
652*cda5da8dSAndroid Build Coastguard Worker    calling the .guess_type() method.
653*cda5da8dSAndroid Build Coastguard Worker
654*cda5da8dSAndroid Build Coastguard Worker    The GET and HEAD requests are identical except that the HEAD
655*cda5da8dSAndroid Build Coastguard Worker    request omits the actual contents of the file.
656*cda5da8dSAndroid Build Coastguard Worker
657*cda5da8dSAndroid Build Coastguard Worker    """
658*cda5da8dSAndroid Build Coastguard Worker
659*cda5da8dSAndroid Build Coastguard Worker    server_version = "SimpleHTTP/" + __version__
660*cda5da8dSAndroid Build Coastguard Worker    extensions_map = _encodings_map_default = {
661*cda5da8dSAndroid Build Coastguard Worker        '.gz': 'application/gzip',
662*cda5da8dSAndroid Build Coastguard Worker        '.Z': 'application/octet-stream',
663*cda5da8dSAndroid Build Coastguard Worker        '.bz2': 'application/x-bzip2',
664*cda5da8dSAndroid Build Coastguard Worker        '.xz': 'application/x-xz',
665*cda5da8dSAndroid Build Coastguard Worker    }
666*cda5da8dSAndroid Build Coastguard Worker
667*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, *args, directory=None, **kwargs):
668*cda5da8dSAndroid Build Coastguard Worker        if directory is None:
669*cda5da8dSAndroid Build Coastguard Worker            directory = os.getcwd()
670*cda5da8dSAndroid Build Coastguard Worker        self.directory = os.fspath(directory)
671*cda5da8dSAndroid Build Coastguard Worker        super().__init__(*args, **kwargs)
672*cda5da8dSAndroid Build Coastguard Worker
673*cda5da8dSAndroid Build Coastguard Worker    def do_GET(self):
674*cda5da8dSAndroid Build Coastguard Worker        """Serve a GET request."""
675*cda5da8dSAndroid Build Coastguard Worker        f = self.send_head()
676*cda5da8dSAndroid Build Coastguard Worker        if f:
677*cda5da8dSAndroid Build Coastguard Worker            try:
678*cda5da8dSAndroid Build Coastguard Worker                self.copyfile(f, self.wfile)
679*cda5da8dSAndroid Build Coastguard Worker            finally:
680*cda5da8dSAndroid Build Coastguard Worker                f.close()
681*cda5da8dSAndroid Build Coastguard Worker
682*cda5da8dSAndroid Build Coastguard Worker    def do_HEAD(self):
683*cda5da8dSAndroid Build Coastguard Worker        """Serve a HEAD request."""
684*cda5da8dSAndroid Build Coastguard Worker        f = self.send_head()
685*cda5da8dSAndroid Build Coastguard Worker        if f:
686*cda5da8dSAndroid Build Coastguard Worker            f.close()
687*cda5da8dSAndroid Build Coastguard Worker
688*cda5da8dSAndroid Build Coastguard Worker    def send_head(self):
689*cda5da8dSAndroid Build Coastguard Worker        """Common code for GET and HEAD commands.
690*cda5da8dSAndroid Build Coastguard Worker
691*cda5da8dSAndroid Build Coastguard Worker        This sends the response code and MIME headers.
692*cda5da8dSAndroid Build Coastguard Worker
693*cda5da8dSAndroid Build Coastguard Worker        Return value is either a file object (which has to be copied
694*cda5da8dSAndroid Build Coastguard Worker        to the outputfile by the caller unless the command was HEAD,
695*cda5da8dSAndroid Build Coastguard Worker        and must be closed by the caller under all circumstances), or
696*cda5da8dSAndroid Build Coastguard Worker        None, in which case the caller has nothing further to do.
697*cda5da8dSAndroid Build Coastguard Worker
698*cda5da8dSAndroid Build Coastguard Worker        """
699*cda5da8dSAndroid Build Coastguard Worker        path = self.translate_path(self.path)
700*cda5da8dSAndroid Build Coastguard Worker        f = None
701*cda5da8dSAndroid Build Coastguard Worker        if os.path.isdir(path):
702*cda5da8dSAndroid Build Coastguard Worker            parts = urllib.parse.urlsplit(self.path)
703*cda5da8dSAndroid Build Coastguard Worker            if not parts.path.endswith('/'):
704*cda5da8dSAndroid Build Coastguard Worker                # redirect browser - doing basically what apache does
705*cda5da8dSAndroid Build Coastguard Worker                self.send_response(HTTPStatus.MOVED_PERMANENTLY)
706*cda5da8dSAndroid Build Coastguard Worker                new_parts = (parts[0], parts[1], parts[2] + '/',
707*cda5da8dSAndroid Build Coastguard Worker                             parts[3], parts[4])
708*cda5da8dSAndroid Build Coastguard Worker                new_url = urllib.parse.urlunsplit(new_parts)
709*cda5da8dSAndroid Build Coastguard Worker                self.send_header("Location", new_url)
710*cda5da8dSAndroid Build Coastguard Worker                self.send_header("Content-Length", "0")
711*cda5da8dSAndroid Build Coastguard Worker                self.end_headers()
712*cda5da8dSAndroid Build Coastguard Worker                return None
713*cda5da8dSAndroid Build Coastguard Worker            for index in "index.html", "index.htm":
714*cda5da8dSAndroid Build Coastguard Worker                index = os.path.join(path, index)
715*cda5da8dSAndroid Build Coastguard Worker                if os.path.isfile(index):
716*cda5da8dSAndroid Build Coastguard Worker                    path = index
717*cda5da8dSAndroid Build Coastguard Worker                    break
718*cda5da8dSAndroid Build Coastguard Worker            else:
719*cda5da8dSAndroid Build Coastguard Worker                return self.list_directory(path)
720*cda5da8dSAndroid Build Coastguard Worker        ctype = self.guess_type(path)
721*cda5da8dSAndroid Build Coastguard Worker        # check for trailing "/" which should return 404. See Issue17324
722*cda5da8dSAndroid Build Coastguard Worker        # The test for this was added in test_httpserver.py
723*cda5da8dSAndroid Build Coastguard Worker        # However, some OS platforms accept a trailingSlash as a filename
724*cda5da8dSAndroid Build Coastguard Worker        # See discussion on python-dev and Issue34711 regarding
725*cda5da8dSAndroid Build Coastguard Worker        # parsing and rejection of filenames with a trailing slash
726*cda5da8dSAndroid Build Coastguard Worker        if path.endswith("/"):
727*cda5da8dSAndroid Build Coastguard Worker            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
728*cda5da8dSAndroid Build Coastguard Worker            return None
729*cda5da8dSAndroid Build Coastguard Worker        try:
730*cda5da8dSAndroid Build Coastguard Worker            f = open(path, 'rb')
731*cda5da8dSAndroid Build Coastguard Worker        except OSError:
732*cda5da8dSAndroid Build Coastguard Worker            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
733*cda5da8dSAndroid Build Coastguard Worker            return None
734*cda5da8dSAndroid Build Coastguard Worker
735*cda5da8dSAndroid Build Coastguard Worker        try:
736*cda5da8dSAndroid Build Coastguard Worker            fs = os.fstat(f.fileno())
737*cda5da8dSAndroid Build Coastguard Worker            # Use browser cache if possible
738*cda5da8dSAndroid Build Coastguard Worker            if ("If-Modified-Since" in self.headers
739*cda5da8dSAndroid Build Coastguard Worker                    and "If-None-Match" not in self.headers):
740*cda5da8dSAndroid Build Coastguard Worker                # compare If-Modified-Since and time of last file modification
741*cda5da8dSAndroid Build Coastguard Worker                try:
742*cda5da8dSAndroid Build Coastguard Worker                    ims = email.utils.parsedate_to_datetime(
743*cda5da8dSAndroid Build Coastguard Worker                        self.headers["If-Modified-Since"])
744*cda5da8dSAndroid Build Coastguard Worker                except (TypeError, IndexError, OverflowError, ValueError):
745*cda5da8dSAndroid Build Coastguard Worker                    # ignore ill-formed values
746*cda5da8dSAndroid Build Coastguard Worker                    pass
747*cda5da8dSAndroid Build Coastguard Worker                else:
748*cda5da8dSAndroid Build Coastguard Worker                    if ims.tzinfo is None:
749*cda5da8dSAndroid Build Coastguard Worker                        # obsolete format with no timezone, cf.
750*cda5da8dSAndroid Build Coastguard Worker                        # https://tools.ietf.org/html/rfc7231#section-7.1.1.1
751*cda5da8dSAndroid Build Coastguard Worker                        ims = ims.replace(tzinfo=datetime.timezone.utc)
752*cda5da8dSAndroid Build Coastguard Worker                    if ims.tzinfo is datetime.timezone.utc:
753*cda5da8dSAndroid Build Coastguard Worker                        # compare to UTC datetime of last modification
754*cda5da8dSAndroid Build Coastguard Worker                        last_modif = datetime.datetime.fromtimestamp(
755*cda5da8dSAndroid Build Coastguard Worker                            fs.st_mtime, datetime.timezone.utc)
756*cda5da8dSAndroid Build Coastguard Worker                        # remove microseconds, like in If-Modified-Since
757*cda5da8dSAndroid Build Coastguard Worker                        last_modif = last_modif.replace(microsecond=0)
758*cda5da8dSAndroid Build Coastguard Worker
759*cda5da8dSAndroid Build Coastguard Worker                        if last_modif <= ims:
760*cda5da8dSAndroid Build Coastguard Worker                            self.send_response(HTTPStatus.NOT_MODIFIED)
761*cda5da8dSAndroid Build Coastguard Worker                            self.end_headers()
762*cda5da8dSAndroid Build Coastguard Worker                            f.close()
763*cda5da8dSAndroid Build Coastguard Worker                            return None
764*cda5da8dSAndroid Build Coastguard Worker
765*cda5da8dSAndroid Build Coastguard Worker            self.send_response(HTTPStatus.OK)
766*cda5da8dSAndroid Build Coastguard Worker            self.send_header("Content-type", ctype)
767*cda5da8dSAndroid Build Coastguard Worker            self.send_header("Content-Length", str(fs[6]))
768*cda5da8dSAndroid Build Coastguard Worker            self.send_header("Last-Modified",
769*cda5da8dSAndroid Build Coastguard Worker                self.date_time_string(fs.st_mtime))
770*cda5da8dSAndroid Build Coastguard Worker            self.end_headers()
771*cda5da8dSAndroid Build Coastguard Worker            return f
772*cda5da8dSAndroid Build Coastguard Worker        except:
773*cda5da8dSAndroid Build Coastguard Worker            f.close()
774*cda5da8dSAndroid Build Coastguard Worker            raise
775*cda5da8dSAndroid Build Coastguard Worker
776*cda5da8dSAndroid Build Coastguard Worker    def list_directory(self, path):
777*cda5da8dSAndroid Build Coastguard Worker        """Helper to produce a directory listing (absent index.html).
778*cda5da8dSAndroid Build Coastguard Worker
779*cda5da8dSAndroid Build Coastguard Worker        Return value is either a file object, or None (indicating an
780*cda5da8dSAndroid Build Coastguard Worker        error).  In either case, the headers are sent, making the
781*cda5da8dSAndroid Build Coastguard Worker        interface the same as for send_head().
782*cda5da8dSAndroid Build Coastguard Worker
783*cda5da8dSAndroid Build Coastguard Worker        """
784*cda5da8dSAndroid Build Coastguard Worker        try:
785*cda5da8dSAndroid Build Coastguard Worker            list = os.listdir(path)
786*cda5da8dSAndroid Build Coastguard Worker        except OSError:
787*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
788*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.NOT_FOUND,
789*cda5da8dSAndroid Build Coastguard Worker                "No permission to list directory")
790*cda5da8dSAndroid Build Coastguard Worker            return None
791*cda5da8dSAndroid Build Coastguard Worker        list.sort(key=lambda a: a.lower())
792*cda5da8dSAndroid Build Coastguard Worker        r = []
793*cda5da8dSAndroid Build Coastguard Worker        try:
794*cda5da8dSAndroid Build Coastguard Worker            displaypath = urllib.parse.unquote(self.path,
795*cda5da8dSAndroid Build Coastguard Worker                                               errors='surrogatepass')
796*cda5da8dSAndroid Build Coastguard Worker        except UnicodeDecodeError:
797*cda5da8dSAndroid Build Coastguard Worker            displaypath = urllib.parse.unquote(self.path)
798*cda5da8dSAndroid Build Coastguard Worker        displaypath = html.escape(displaypath, quote=False)
799*cda5da8dSAndroid Build Coastguard Worker        enc = sys.getfilesystemencoding()
800*cda5da8dSAndroid Build Coastguard Worker        title = f'Directory listing for {displaypath}'
801*cda5da8dSAndroid Build Coastguard Worker        r.append('<!DOCTYPE HTML>')
802*cda5da8dSAndroid Build Coastguard Worker        r.append('<html lang="en">')
803*cda5da8dSAndroid Build Coastguard Worker        r.append('<head>')
804*cda5da8dSAndroid Build Coastguard Worker        r.append(f'<meta charset="{enc}">')
805*cda5da8dSAndroid Build Coastguard Worker        r.append(f'<title>{title}</title>\n</head>')
806*cda5da8dSAndroid Build Coastguard Worker        r.append(f'<body>\n<h1>{title}</h1>')
807*cda5da8dSAndroid Build Coastguard Worker        r.append('<hr>\n<ul>')
808*cda5da8dSAndroid Build Coastguard Worker        for name in list:
809*cda5da8dSAndroid Build Coastguard Worker            fullname = os.path.join(path, name)
810*cda5da8dSAndroid Build Coastguard Worker            displayname = linkname = name
811*cda5da8dSAndroid Build Coastguard Worker            # Append / for directories or @ for symbolic links
812*cda5da8dSAndroid Build Coastguard Worker            if os.path.isdir(fullname):
813*cda5da8dSAndroid Build Coastguard Worker                displayname = name + "/"
814*cda5da8dSAndroid Build Coastguard Worker                linkname = name + "/"
815*cda5da8dSAndroid Build Coastguard Worker            if os.path.islink(fullname):
816*cda5da8dSAndroid Build Coastguard Worker                displayname = name + "@"
817*cda5da8dSAndroid Build Coastguard Worker                # Note: a link to a directory displays with @ and links with /
818*cda5da8dSAndroid Build Coastguard Worker            r.append('<li><a href="%s">%s</a></li>'
819*cda5da8dSAndroid Build Coastguard Worker                    % (urllib.parse.quote(linkname,
820*cda5da8dSAndroid Build Coastguard Worker                                          errors='surrogatepass'),
821*cda5da8dSAndroid Build Coastguard Worker                       html.escape(displayname, quote=False)))
822*cda5da8dSAndroid Build Coastguard Worker        r.append('</ul>\n<hr>\n</body>\n</html>\n')
823*cda5da8dSAndroid Build Coastguard Worker        encoded = '\n'.join(r).encode(enc, 'surrogateescape')
824*cda5da8dSAndroid Build Coastguard Worker        f = io.BytesIO()
825*cda5da8dSAndroid Build Coastguard Worker        f.write(encoded)
826*cda5da8dSAndroid Build Coastguard Worker        f.seek(0)
827*cda5da8dSAndroid Build Coastguard Worker        self.send_response(HTTPStatus.OK)
828*cda5da8dSAndroid Build Coastguard Worker        self.send_header("Content-type", "text/html; charset=%s" % enc)
829*cda5da8dSAndroid Build Coastguard Worker        self.send_header("Content-Length", str(len(encoded)))
830*cda5da8dSAndroid Build Coastguard Worker        self.end_headers()
831*cda5da8dSAndroid Build Coastguard Worker        return f
832*cda5da8dSAndroid Build Coastguard Worker
833*cda5da8dSAndroid Build Coastguard Worker    def translate_path(self, path):
834*cda5da8dSAndroid Build Coastguard Worker        """Translate a /-separated PATH to the local filename syntax.
835*cda5da8dSAndroid Build Coastguard Worker
836*cda5da8dSAndroid Build Coastguard Worker        Components that mean special things to the local file system
837*cda5da8dSAndroid Build Coastguard Worker        (e.g. drive or directory names) are ignored.  (XXX They should
838*cda5da8dSAndroid Build Coastguard Worker        probably be diagnosed.)
839*cda5da8dSAndroid Build Coastguard Worker
840*cda5da8dSAndroid Build Coastguard Worker        """
841*cda5da8dSAndroid Build Coastguard Worker        # abandon query parameters
842*cda5da8dSAndroid Build Coastguard Worker        path = path.split('?',1)[0]
843*cda5da8dSAndroid Build Coastguard Worker        path = path.split('#',1)[0]
844*cda5da8dSAndroid Build Coastguard Worker        # Don't forget explicit trailing slash when normalizing. Issue17324
845*cda5da8dSAndroid Build Coastguard Worker        trailing_slash = path.rstrip().endswith('/')
846*cda5da8dSAndroid Build Coastguard Worker        try:
847*cda5da8dSAndroid Build Coastguard Worker            path = urllib.parse.unquote(path, errors='surrogatepass')
848*cda5da8dSAndroid Build Coastguard Worker        except UnicodeDecodeError:
849*cda5da8dSAndroid Build Coastguard Worker            path = urllib.parse.unquote(path)
850*cda5da8dSAndroid Build Coastguard Worker        path = posixpath.normpath(path)
851*cda5da8dSAndroid Build Coastguard Worker        words = path.split('/')
852*cda5da8dSAndroid Build Coastguard Worker        words = filter(None, words)
853*cda5da8dSAndroid Build Coastguard Worker        path = self.directory
854*cda5da8dSAndroid Build Coastguard Worker        for word in words:
855*cda5da8dSAndroid Build Coastguard Worker            if os.path.dirname(word) or word in (os.curdir, os.pardir):
856*cda5da8dSAndroid Build Coastguard Worker                # Ignore components that are not a simple file/directory name
857*cda5da8dSAndroid Build Coastguard Worker                continue
858*cda5da8dSAndroid Build Coastguard Worker            path = os.path.join(path, word)
859*cda5da8dSAndroid Build Coastguard Worker        if trailing_slash:
860*cda5da8dSAndroid Build Coastguard Worker            path += '/'
861*cda5da8dSAndroid Build Coastguard Worker        return path
862*cda5da8dSAndroid Build Coastguard Worker
863*cda5da8dSAndroid Build Coastguard Worker    def copyfile(self, source, outputfile):
864*cda5da8dSAndroid Build Coastguard Worker        """Copy all data between two file objects.
865*cda5da8dSAndroid Build Coastguard Worker
866*cda5da8dSAndroid Build Coastguard Worker        The SOURCE argument is a file object open for reading
867*cda5da8dSAndroid Build Coastguard Worker        (or anything with a read() method) and the DESTINATION
868*cda5da8dSAndroid Build Coastguard Worker        argument is a file object open for writing (or
869*cda5da8dSAndroid Build Coastguard Worker        anything with a write() method).
870*cda5da8dSAndroid Build Coastguard Worker
871*cda5da8dSAndroid Build Coastguard Worker        The only reason for overriding this would be to change
872*cda5da8dSAndroid Build Coastguard Worker        the block size or perhaps to replace newlines by CRLF
873*cda5da8dSAndroid Build Coastguard Worker        -- note however that this the default server uses this
874*cda5da8dSAndroid Build Coastguard Worker        to copy binary data as well.
875*cda5da8dSAndroid Build Coastguard Worker
876*cda5da8dSAndroid Build Coastguard Worker        """
877*cda5da8dSAndroid Build Coastguard Worker        shutil.copyfileobj(source, outputfile)
878*cda5da8dSAndroid Build Coastguard Worker
879*cda5da8dSAndroid Build Coastguard Worker    def guess_type(self, path):
880*cda5da8dSAndroid Build Coastguard Worker        """Guess the type of a file.
881*cda5da8dSAndroid Build Coastguard Worker
882*cda5da8dSAndroid Build Coastguard Worker        Argument is a PATH (a filename).
883*cda5da8dSAndroid Build Coastguard Worker
884*cda5da8dSAndroid Build Coastguard Worker        Return value is a string of the form type/subtype,
885*cda5da8dSAndroid Build Coastguard Worker        usable for a MIME Content-type header.
886*cda5da8dSAndroid Build Coastguard Worker
887*cda5da8dSAndroid Build Coastguard Worker        The default implementation looks the file's extension
888*cda5da8dSAndroid Build Coastguard Worker        up in the table self.extensions_map, using application/octet-stream
889*cda5da8dSAndroid Build Coastguard Worker        as a default; however it would be permissible (if
890*cda5da8dSAndroid Build Coastguard Worker        slow) to look inside the data to make a better guess.
891*cda5da8dSAndroid Build Coastguard Worker
892*cda5da8dSAndroid Build Coastguard Worker        """
893*cda5da8dSAndroid Build Coastguard Worker        base, ext = posixpath.splitext(path)
894*cda5da8dSAndroid Build Coastguard Worker        if ext in self.extensions_map:
895*cda5da8dSAndroid Build Coastguard Worker            return self.extensions_map[ext]
896*cda5da8dSAndroid Build Coastguard Worker        ext = ext.lower()
897*cda5da8dSAndroid Build Coastguard Worker        if ext in self.extensions_map:
898*cda5da8dSAndroid Build Coastguard Worker            return self.extensions_map[ext]
899*cda5da8dSAndroid Build Coastguard Worker        guess, _ = mimetypes.guess_type(path)
900*cda5da8dSAndroid Build Coastguard Worker        if guess:
901*cda5da8dSAndroid Build Coastguard Worker            return guess
902*cda5da8dSAndroid Build Coastguard Worker        return 'application/octet-stream'
903*cda5da8dSAndroid Build Coastguard Worker
904*cda5da8dSAndroid Build Coastguard Worker
905*cda5da8dSAndroid Build Coastguard Worker# Utilities for CGIHTTPRequestHandler
906*cda5da8dSAndroid Build Coastguard Worker
907*cda5da8dSAndroid Build Coastguard Workerdef _url_collapse_path(path):
908*cda5da8dSAndroid Build Coastguard Worker    """
909*cda5da8dSAndroid Build Coastguard Worker    Given a URL path, remove extra '/'s and '.' path elements and collapse
910*cda5da8dSAndroid Build Coastguard Worker    any '..' references and returns a collapsed path.
911*cda5da8dSAndroid Build Coastguard Worker
912*cda5da8dSAndroid Build Coastguard Worker    Implements something akin to RFC-2396 5.2 step 6 to parse relative paths.
913*cda5da8dSAndroid Build Coastguard Worker    The utility of this function is limited to is_cgi method and helps
914*cda5da8dSAndroid Build Coastguard Worker    preventing some security attacks.
915*cda5da8dSAndroid Build Coastguard Worker
916*cda5da8dSAndroid Build Coastguard Worker    Returns: The reconstituted URL, which will always start with a '/'.
917*cda5da8dSAndroid Build Coastguard Worker
918*cda5da8dSAndroid Build Coastguard Worker    Raises: IndexError if too many '..' occur within the path.
919*cda5da8dSAndroid Build Coastguard Worker
920*cda5da8dSAndroid Build Coastguard Worker    """
921*cda5da8dSAndroid Build Coastguard Worker    # Query component should not be involved.
922*cda5da8dSAndroid Build Coastguard Worker    path, _, query = path.partition('?')
923*cda5da8dSAndroid Build Coastguard Worker    path = urllib.parse.unquote(path)
924*cda5da8dSAndroid Build Coastguard Worker
925*cda5da8dSAndroid Build Coastguard Worker    # Similar to os.path.split(os.path.normpath(path)) but specific to URL
926*cda5da8dSAndroid Build Coastguard Worker    # path semantics rather than local operating system semantics.
927*cda5da8dSAndroid Build Coastguard Worker    path_parts = path.split('/')
928*cda5da8dSAndroid Build Coastguard Worker    head_parts = []
929*cda5da8dSAndroid Build Coastguard Worker    for part in path_parts[:-1]:
930*cda5da8dSAndroid Build Coastguard Worker        if part == '..':
931*cda5da8dSAndroid Build Coastguard Worker            head_parts.pop() # IndexError if more '..' than prior parts
932*cda5da8dSAndroid Build Coastguard Worker        elif part and part != '.':
933*cda5da8dSAndroid Build Coastguard Worker            head_parts.append( part )
934*cda5da8dSAndroid Build Coastguard Worker    if path_parts:
935*cda5da8dSAndroid Build Coastguard Worker        tail_part = path_parts.pop()
936*cda5da8dSAndroid Build Coastguard Worker        if tail_part:
937*cda5da8dSAndroid Build Coastguard Worker            if tail_part == '..':
938*cda5da8dSAndroid Build Coastguard Worker                head_parts.pop()
939*cda5da8dSAndroid Build Coastguard Worker                tail_part = ''
940*cda5da8dSAndroid Build Coastguard Worker            elif tail_part == '.':
941*cda5da8dSAndroid Build Coastguard Worker                tail_part = ''
942*cda5da8dSAndroid Build Coastguard Worker    else:
943*cda5da8dSAndroid Build Coastguard Worker        tail_part = ''
944*cda5da8dSAndroid Build Coastguard Worker
945*cda5da8dSAndroid Build Coastguard Worker    if query:
946*cda5da8dSAndroid Build Coastguard Worker        tail_part = '?'.join((tail_part, query))
947*cda5da8dSAndroid Build Coastguard Worker
948*cda5da8dSAndroid Build Coastguard Worker    splitpath = ('/' + '/'.join(head_parts), tail_part)
949*cda5da8dSAndroid Build Coastguard Worker    collapsed_path = "/".join(splitpath)
950*cda5da8dSAndroid Build Coastguard Worker
951*cda5da8dSAndroid Build Coastguard Worker    return collapsed_path
952*cda5da8dSAndroid Build Coastguard Worker
953*cda5da8dSAndroid Build Coastguard Worker
954*cda5da8dSAndroid Build Coastguard Worker
955*cda5da8dSAndroid Build Coastguard Workernobody = None
956*cda5da8dSAndroid Build Coastguard Worker
957*cda5da8dSAndroid Build Coastguard Workerdef nobody_uid():
958*cda5da8dSAndroid Build Coastguard Worker    """Internal routine to get nobody's uid"""
959*cda5da8dSAndroid Build Coastguard Worker    global nobody
960*cda5da8dSAndroid Build Coastguard Worker    if nobody:
961*cda5da8dSAndroid Build Coastguard Worker        return nobody
962*cda5da8dSAndroid Build Coastguard Worker    try:
963*cda5da8dSAndroid Build Coastguard Worker        import pwd
964*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
965*cda5da8dSAndroid Build Coastguard Worker        return -1
966*cda5da8dSAndroid Build Coastguard Worker    try:
967*cda5da8dSAndroid Build Coastguard Worker        nobody = pwd.getpwnam('nobody')[2]
968*cda5da8dSAndroid Build Coastguard Worker    except KeyError:
969*cda5da8dSAndroid Build Coastguard Worker        nobody = 1 + max(x[2] for x in pwd.getpwall())
970*cda5da8dSAndroid Build Coastguard Worker    return nobody
971*cda5da8dSAndroid Build Coastguard Worker
972*cda5da8dSAndroid Build Coastguard Worker
973*cda5da8dSAndroid Build Coastguard Workerdef executable(path):
974*cda5da8dSAndroid Build Coastguard Worker    """Test for executable file."""
975*cda5da8dSAndroid Build Coastguard Worker    return os.access(path, os.X_OK)
976*cda5da8dSAndroid Build Coastguard Worker
977*cda5da8dSAndroid Build Coastguard Worker
978*cda5da8dSAndroid Build Coastguard Workerclass CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
979*cda5da8dSAndroid Build Coastguard Worker
980*cda5da8dSAndroid Build Coastguard Worker    """Complete HTTP server with GET, HEAD and POST commands.
981*cda5da8dSAndroid Build Coastguard Worker
982*cda5da8dSAndroid Build Coastguard Worker    GET and HEAD also support running CGI scripts.
983*cda5da8dSAndroid Build Coastguard Worker
984*cda5da8dSAndroid Build Coastguard Worker    The POST command is *only* implemented for CGI scripts.
985*cda5da8dSAndroid Build Coastguard Worker
986*cda5da8dSAndroid Build Coastguard Worker    """
987*cda5da8dSAndroid Build Coastguard Worker
988*cda5da8dSAndroid Build Coastguard Worker    # Determine platform specifics
989*cda5da8dSAndroid Build Coastguard Worker    have_fork = hasattr(os, 'fork')
990*cda5da8dSAndroid Build Coastguard Worker
991*cda5da8dSAndroid Build Coastguard Worker    # Make rfile unbuffered -- we need to read one line and then pass
992*cda5da8dSAndroid Build Coastguard Worker    # the rest to a subprocess, so we can't use buffered input.
993*cda5da8dSAndroid Build Coastguard Worker    rbufsize = 0
994*cda5da8dSAndroid Build Coastguard Worker
995*cda5da8dSAndroid Build Coastguard Worker    def do_POST(self):
996*cda5da8dSAndroid Build Coastguard Worker        """Serve a POST request.
997*cda5da8dSAndroid Build Coastguard Worker
998*cda5da8dSAndroid Build Coastguard Worker        This is only implemented for CGI scripts.
999*cda5da8dSAndroid Build Coastguard Worker
1000*cda5da8dSAndroid Build Coastguard Worker        """
1001*cda5da8dSAndroid Build Coastguard Worker
1002*cda5da8dSAndroid Build Coastguard Worker        if self.is_cgi():
1003*cda5da8dSAndroid Build Coastguard Worker            self.run_cgi()
1004*cda5da8dSAndroid Build Coastguard Worker        else:
1005*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
1006*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.NOT_IMPLEMENTED,
1007*cda5da8dSAndroid Build Coastguard Worker                "Can only POST to CGI scripts")
1008*cda5da8dSAndroid Build Coastguard Worker
1009*cda5da8dSAndroid Build Coastguard Worker    def send_head(self):
1010*cda5da8dSAndroid Build Coastguard Worker        """Version of send_head that support CGI scripts"""
1011*cda5da8dSAndroid Build Coastguard Worker        if self.is_cgi():
1012*cda5da8dSAndroid Build Coastguard Worker            return self.run_cgi()
1013*cda5da8dSAndroid Build Coastguard Worker        else:
1014*cda5da8dSAndroid Build Coastguard Worker            return SimpleHTTPRequestHandler.send_head(self)
1015*cda5da8dSAndroid Build Coastguard Worker
1016*cda5da8dSAndroid Build Coastguard Worker    def is_cgi(self):
1017*cda5da8dSAndroid Build Coastguard Worker        """Test whether self.path corresponds to a CGI script.
1018*cda5da8dSAndroid Build Coastguard Worker
1019*cda5da8dSAndroid Build Coastguard Worker        Returns True and updates the cgi_info attribute to the tuple
1020*cda5da8dSAndroid Build Coastguard Worker        (dir, rest) if self.path requires running a CGI script.
1021*cda5da8dSAndroid Build Coastguard Worker        Returns False otherwise.
1022*cda5da8dSAndroid Build Coastguard Worker
1023*cda5da8dSAndroid Build Coastguard Worker        If any exception is raised, the caller should assume that
1024*cda5da8dSAndroid Build Coastguard Worker        self.path was rejected as invalid and act accordingly.
1025*cda5da8dSAndroid Build Coastguard Worker
1026*cda5da8dSAndroid Build Coastguard Worker        The default implementation tests whether the normalized url
1027*cda5da8dSAndroid Build Coastguard Worker        path begins with one of the strings in self.cgi_directories
1028*cda5da8dSAndroid Build Coastguard Worker        (and the next character is a '/' or the end of the string).
1029*cda5da8dSAndroid Build Coastguard Worker
1030*cda5da8dSAndroid Build Coastguard Worker        """
1031*cda5da8dSAndroid Build Coastguard Worker        collapsed_path = _url_collapse_path(self.path)
1032*cda5da8dSAndroid Build Coastguard Worker        dir_sep = collapsed_path.find('/', 1)
1033*cda5da8dSAndroid Build Coastguard Worker        while dir_sep > 0 and not collapsed_path[:dir_sep] in self.cgi_directories:
1034*cda5da8dSAndroid Build Coastguard Worker            dir_sep = collapsed_path.find('/', dir_sep+1)
1035*cda5da8dSAndroid Build Coastguard Worker        if dir_sep > 0:
1036*cda5da8dSAndroid Build Coastguard Worker            head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
1037*cda5da8dSAndroid Build Coastguard Worker            self.cgi_info = head, tail
1038*cda5da8dSAndroid Build Coastguard Worker            return True
1039*cda5da8dSAndroid Build Coastguard Worker        return False
1040*cda5da8dSAndroid Build Coastguard Worker
1041*cda5da8dSAndroid Build Coastguard Worker
1042*cda5da8dSAndroid Build Coastguard Worker    cgi_directories = ['/cgi-bin', '/htbin']
1043*cda5da8dSAndroid Build Coastguard Worker
1044*cda5da8dSAndroid Build Coastguard Worker    def is_executable(self, path):
1045*cda5da8dSAndroid Build Coastguard Worker        """Test whether argument path is an executable file."""
1046*cda5da8dSAndroid Build Coastguard Worker        return executable(path)
1047*cda5da8dSAndroid Build Coastguard Worker
1048*cda5da8dSAndroid Build Coastguard Worker    def is_python(self, path):
1049*cda5da8dSAndroid Build Coastguard Worker        """Test whether argument path is a Python script."""
1050*cda5da8dSAndroid Build Coastguard Worker        head, tail = os.path.splitext(path)
1051*cda5da8dSAndroid Build Coastguard Worker        return tail.lower() in (".py", ".pyw")
1052*cda5da8dSAndroid Build Coastguard Worker
1053*cda5da8dSAndroid Build Coastguard Worker    def run_cgi(self):
1054*cda5da8dSAndroid Build Coastguard Worker        """Execute a CGI script."""
1055*cda5da8dSAndroid Build Coastguard Worker        dir, rest = self.cgi_info
1056*cda5da8dSAndroid Build Coastguard Worker        path = dir + '/' + rest
1057*cda5da8dSAndroid Build Coastguard Worker        i = path.find('/', len(dir)+1)
1058*cda5da8dSAndroid Build Coastguard Worker        while i >= 0:
1059*cda5da8dSAndroid Build Coastguard Worker            nextdir = path[:i]
1060*cda5da8dSAndroid Build Coastguard Worker            nextrest = path[i+1:]
1061*cda5da8dSAndroid Build Coastguard Worker
1062*cda5da8dSAndroid Build Coastguard Worker            scriptdir = self.translate_path(nextdir)
1063*cda5da8dSAndroid Build Coastguard Worker            if os.path.isdir(scriptdir):
1064*cda5da8dSAndroid Build Coastguard Worker                dir, rest = nextdir, nextrest
1065*cda5da8dSAndroid Build Coastguard Worker                i = path.find('/', len(dir)+1)
1066*cda5da8dSAndroid Build Coastguard Worker            else:
1067*cda5da8dSAndroid Build Coastguard Worker                break
1068*cda5da8dSAndroid Build Coastguard Worker
1069*cda5da8dSAndroid Build Coastguard Worker        # find an explicit query string, if present.
1070*cda5da8dSAndroid Build Coastguard Worker        rest, _, query = rest.partition('?')
1071*cda5da8dSAndroid Build Coastguard Worker
1072*cda5da8dSAndroid Build Coastguard Worker        # dissect the part after the directory name into a script name &
1073*cda5da8dSAndroid Build Coastguard Worker        # a possible additional path, to be stored in PATH_INFO.
1074*cda5da8dSAndroid Build Coastguard Worker        i = rest.find('/')
1075*cda5da8dSAndroid Build Coastguard Worker        if i >= 0:
1076*cda5da8dSAndroid Build Coastguard Worker            script, rest = rest[:i], rest[i:]
1077*cda5da8dSAndroid Build Coastguard Worker        else:
1078*cda5da8dSAndroid Build Coastguard Worker            script, rest = rest, ''
1079*cda5da8dSAndroid Build Coastguard Worker
1080*cda5da8dSAndroid Build Coastguard Worker        scriptname = dir + '/' + script
1081*cda5da8dSAndroid Build Coastguard Worker        scriptfile = self.translate_path(scriptname)
1082*cda5da8dSAndroid Build Coastguard Worker        if not os.path.exists(scriptfile):
1083*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
1084*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.NOT_FOUND,
1085*cda5da8dSAndroid Build Coastguard Worker                "No such CGI script (%r)" % scriptname)
1086*cda5da8dSAndroid Build Coastguard Worker            return
1087*cda5da8dSAndroid Build Coastguard Worker        if not os.path.isfile(scriptfile):
1088*cda5da8dSAndroid Build Coastguard Worker            self.send_error(
1089*cda5da8dSAndroid Build Coastguard Worker                HTTPStatus.FORBIDDEN,
1090*cda5da8dSAndroid Build Coastguard Worker                "CGI script is not a plain file (%r)" % scriptname)
1091*cda5da8dSAndroid Build Coastguard Worker            return
1092*cda5da8dSAndroid Build Coastguard Worker        ispy = self.is_python(scriptname)
1093*cda5da8dSAndroid Build Coastguard Worker        if self.have_fork or not ispy:
1094*cda5da8dSAndroid Build Coastguard Worker            if not self.is_executable(scriptfile):
1095*cda5da8dSAndroid Build Coastguard Worker                self.send_error(
1096*cda5da8dSAndroid Build Coastguard Worker                    HTTPStatus.FORBIDDEN,
1097*cda5da8dSAndroid Build Coastguard Worker                    "CGI script is not executable (%r)" % scriptname)
1098*cda5da8dSAndroid Build Coastguard Worker                return
1099*cda5da8dSAndroid Build Coastguard Worker
1100*cda5da8dSAndroid Build Coastguard Worker        # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
1101*cda5da8dSAndroid Build Coastguard Worker        # XXX Much of the following could be prepared ahead of time!
1102*cda5da8dSAndroid Build Coastguard Worker        env = copy.deepcopy(os.environ)
1103*cda5da8dSAndroid Build Coastguard Worker        env['SERVER_SOFTWARE'] = self.version_string()
1104*cda5da8dSAndroid Build Coastguard Worker        env['SERVER_NAME'] = self.server.server_name
1105*cda5da8dSAndroid Build Coastguard Worker        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
1106*cda5da8dSAndroid Build Coastguard Worker        env['SERVER_PROTOCOL'] = self.protocol_version
1107*cda5da8dSAndroid Build Coastguard Worker        env['SERVER_PORT'] = str(self.server.server_port)
1108*cda5da8dSAndroid Build Coastguard Worker        env['REQUEST_METHOD'] = self.command
1109*cda5da8dSAndroid Build Coastguard Worker        uqrest = urllib.parse.unquote(rest)
1110*cda5da8dSAndroid Build Coastguard Worker        env['PATH_INFO'] = uqrest
1111*cda5da8dSAndroid Build Coastguard Worker        env['PATH_TRANSLATED'] = self.translate_path(uqrest)
1112*cda5da8dSAndroid Build Coastguard Worker        env['SCRIPT_NAME'] = scriptname
1113*cda5da8dSAndroid Build Coastguard Worker        env['QUERY_STRING'] = query
1114*cda5da8dSAndroid Build Coastguard Worker        env['REMOTE_ADDR'] = self.client_address[0]
1115*cda5da8dSAndroid Build Coastguard Worker        authorization = self.headers.get("authorization")
1116*cda5da8dSAndroid Build Coastguard Worker        if authorization:
1117*cda5da8dSAndroid Build Coastguard Worker            authorization = authorization.split()
1118*cda5da8dSAndroid Build Coastguard Worker            if len(authorization) == 2:
1119*cda5da8dSAndroid Build Coastguard Worker                import base64, binascii
1120*cda5da8dSAndroid Build Coastguard Worker                env['AUTH_TYPE'] = authorization[0]
1121*cda5da8dSAndroid Build Coastguard Worker                if authorization[0].lower() == "basic":
1122*cda5da8dSAndroid Build Coastguard Worker                    try:
1123*cda5da8dSAndroid Build Coastguard Worker                        authorization = authorization[1].encode('ascii')
1124*cda5da8dSAndroid Build Coastguard Worker                        authorization = base64.decodebytes(authorization).\
1125*cda5da8dSAndroid Build Coastguard Worker                                        decode('ascii')
1126*cda5da8dSAndroid Build Coastguard Worker                    except (binascii.Error, UnicodeError):
1127*cda5da8dSAndroid Build Coastguard Worker                        pass
1128*cda5da8dSAndroid Build Coastguard Worker                    else:
1129*cda5da8dSAndroid Build Coastguard Worker                        authorization = authorization.split(':')
1130*cda5da8dSAndroid Build Coastguard Worker                        if len(authorization) == 2:
1131*cda5da8dSAndroid Build Coastguard Worker                            env['REMOTE_USER'] = authorization[0]
1132*cda5da8dSAndroid Build Coastguard Worker        # XXX REMOTE_IDENT
1133*cda5da8dSAndroid Build Coastguard Worker        if self.headers.get('content-type') is None:
1134*cda5da8dSAndroid Build Coastguard Worker            env['CONTENT_TYPE'] = self.headers.get_content_type()
1135*cda5da8dSAndroid Build Coastguard Worker        else:
1136*cda5da8dSAndroid Build Coastguard Worker            env['CONTENT_TYPE'] = self.headers['content-type']
1137*cda5da8dSAndroid Build Coastguard Worker        length = self.headers.get('content-length')
1138*cda5da8dSAndroid Build Coastguard Worker        if length:
1139*cda5da8dSAndroid Build Coastguard Worker            env['CONTENT_LENGTH'] = length
1140*cda5da8dSAndroid Build Coastguard Worker        referer = self.headers.get('referer')
1141*cda5da8dSAndroid Build Coastguard Worker        if referer:
1142*cda5da8dSAndroid Build Coastguard Worker            env['HTTP_REFERER'] = referer
1143*cda5da8dSAndroid Build Coastguard Worker        accept = self.headers.get_all('accept', ())
1144*cda5da8dSAndroid Build Coastguard Worker        env['HTTP_ACCEPT'] = ','.join(accept)
1145*cda5da8dSAndroid Build Coastguard Worker        ua = self.headers.get('user-agent')
1146*cda5da8dSAndroid Build Coastguard Worker        if ua:
1147*cda5da8dSAndroid Build Coastguard Worker            env['HTTP_USER_AGENT'] = ua
1148*cda5da8dSAndroid Build Coastguard Worker        co = filter(None, self.headers.get_all('cookie', []))
1149*cda5da8dSAndroid Build Coastguard Worker        cookie_str = ', '.join(co)
1150*cda5da8dSAndroid Build Coastguard Worker        if cookie_str:
1151*cda5da8dSAndroid Build Coastguard Worker            env['HTTP_COOKIE'] = cookie_str
1152*cda5da8dSAndroid Build Coastguard Worker        # XXX Other HTTP_* headers
1153*cda5da8dSAndroid Build Coastguard Worker        # Since we're setting the env in the parent, provide empty
1154*cda5da8dSAndroid Build Coastguard Worker        # values to override previously set values
1155*cda5da8dSAndroid Build Coastguard Worker        for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
1156*cda5da8dSAndroid Build Coastguard Worker                  'HTTP_USER_AGENT', 'HTTP_COOKIE', 'HTTP_REFERER'):
1157*cda5da8dSAndroid Build Coastguard Worker            env.setdefault(k, "")
1158*cda5da8dSAndroid Build Coastguard Worker
1159*cda5da8dSAndroid Build Coastguard Worker        self.send_response(HTTPStatus.OK, "Script output follows")
1160*cda5da8dSAndroid Build Coastguard Worker        self.flush_headers()
1161*cda5da8dSAndroid Build Coastguard Worker
1162*cda5da8dSAndroid Build Coastguard Worker        decoded_query = query.replace('+', ' ')
1163*cda5da8dSAndroid Build Coastguard Worker
1164*cda5da8dSAndroid Build Coastguard Worker        if self.have_fork:
1165*cda5da8dSAndroid Build Coastguard Worker            # Unix -- fork as we should
1166*cda5da8dSAndroid Build Coastguard Worker            args = [script]
1167*cda5da8dSAndroid Build Coastguard Worker            if '=' not in decoded_query:
1168*cda5da8dSAndroid Build Coastguard Worker                args.append(decoded_query)
1169*cda5da8dSAndroid Build Coastguard Worker            nobody = nobody_uid()
1170*cda5da8dSAndroid Build Coastguard Worker            self.wfile.flush() # Always flush before forking
1171*cda5da8dSAndroid Build Coastguard Worker            pid = os.fork()
1172*cda5da8dSAndroid Build Coastguard Worker            if pid != 0:
1173*cda5da8dSAndroid Build Coastguard Worker                # Parent
1174*cda5da8dSAndroid Build Coastguard Worker                pid, sts = os.waitpid(pid, 0)
1175*cda5da8dSAndroid Build Coastguard Worker                # throw away additional data [see bug #427345]
1176*cda5da8dSAndroid Build Coastguard Worker                while select.select([self.rfile], [], [], 0)[0]:
1177*cda5da8dSAndroid Build Coastguard Worker                    if not self.rfile.read(1):
1178*cda5da8dSAndroid Build Coastguard Worker                        break
1179*cda5da8dSAndroid Build Coastguard Worker                exitcode = os.waitstatus_to_exitcode(sts)
1180*cda5da8dSAndroid Build Coastguard Worker                if exitcode:
1181*cda5da8dSAndroid Build Coastguard Worker                    self.log_error(f"CGI script exit code {exitcode}")
1182*cda5da8dSAndroid Build Coastguard Worker                return
1183*cda5da8dSAndroid Build Coastguard Worker            # Child
1184*cda5da8dSAndroid Build Coastguard Worker            try:
1185*cda5da8dSAndroid Build Coastguard Worker                try:
1186*cda5da8dSAndroid Build Coastguard Worker                    os.setuid(nobody)
1187*cda5da8dSAndroid Build Coastguard Worker                except OSError:
1188*cda5da8dSAndroid Build Coastguard Worker                    pass
1189*cda5da8dSAndroid Build Coastguard Worker                os.dup2(self.rfile.fileno(), 0)
1190*cda5da8dSAndroid Build Coastguard Worker                os.dup2(self.wfile.fileno(), 1)
1191*cda5da8dSAndroid Build Coastguard Worker                os.execve(scriptfile, args, env)
1192*cda5da8dSAndroid Build Coastguard Worker            except:
1193*cda5da8dSAndroid Build Coastguard Worker                self.server.handle_error(self.request, self.client_address)
1194*cda5da8dSAndroid Build Coastguard Worker                os._exit(127)
1195*cda5da8dSAndroid Build Coastguard Worker
1196*cda5da8dSAndroid Build Coastguard Worker        else:
1197*cda5da8dSAndroid Build Coastguard Worker            # Non-Unix -- use subprocess
1198*cda5da8dSAndroid Build Coastguard Worker            import subprocess
1199*cda5da8dSAndroid Build Coastguard Worker            cmdline = [scriptfile]
1200*cda5da8dSAndroid Build Coastguard Worker            if self.is_python(scriptfile):
1201*cda5da8dSAndroid Build Coastguard Worker                interp = sys.executable
1202*cda5da8dSAndroid Build Coastguard Worker                if interp.lower().endswith("w.exe"):
1203*cda5da8dSAndroid Build Coastguard Worker                    # On Windows, use python.exe, not pythonw.exe
1204*cda5da8dSAndroid Build Coastguard Worker                    interp = interp[:-5] + interp[-4:]
1205*cda5da8dSAndroid Build Coastguard Worker                cmdline = [interp, '-u'] + cmdline
1206*cda5da8dSAndroid Build Coastguard Worker            if '=' not in query:
1207*cda5da8dSAndroid Build Coastguard Worker                cmdline.append(query)
1208*cda5da8dSAndroid Build Coastguard Worker            self.log_message("command: %s", subprocess.list2cmdline(cmdline))
1209*cda5da8dSAndroid Build Coastguard Worker            try:
1210*cda5da8dSAndroid Build Coastguard Worker                nbytes = int(length)
1211*cda5da8dSAndroid Build Coastguard Worker            except (TypeError, ValueError):
1212*cda5da8dSAndroid Build Coastguard Worker                nbytes = 0
1213*cda5da8dSAndroid Build Coastguard Worker            p = subprocess.Popen(cmdline,
1214*cda5da8dSAndroid Build Coastguard Worker                                 stdin=subprocess.PIPE,
1215*cda5da8dSAndroid Build Coastguard Worker                                 stdout=subprocess.PIPE,
1216*cda5da8dSAndroid Build Coastguard Worker                                 stderr=subprocess.PIPE,
1217*cda5da8dSAndroid Build Coastguard Worker                                 env = env
1218*cda5da8dSAndroid Build Coastguard Worker                                 )
1219*cda5da8dSAndroid Build Coastguard Worker            if self.command.lower() == "post" and nbytes > 0:
1220*cda5da8dSAndroid Build Coastguard Worker                data = self.rfile.read(nbytes)
1221*cda5da8dSAndroid Build Coastguard Worker            else:
1222*cda5da8dSAndroid Build Coastguard Worker                data = None
1223*cda5da8dSAndroid Build Coastguard Worker            # throw away additional data [see bug #427345]
1224*cda5da8dSAndroid Build Coastguard Worker            while select.select([self.rfile._sock], [], [], 0)[0]:
1225*cda5da8dSAndroid Build Coastguard Worker                if not self.rfile._sock.recv(1):
1226*cda5da8dSAndroid Build Coastguard Worker                    break
1227*cda5da8dSAndroid Build Coastguard Worker            stdout, stderr = p.communicate(data)
1228*cda5da8dSAndroid Build Coastguard Worker            self.wfile.write(stdout)
1229*cda5da8dSAndroid Build Coastguard Worker            if stderr:
1230*cda5da8dSAndroid Build Coastguard Worker                self.log_error('%s', stderr)
1231*cda5da8dSAndroid Build Coastguard Worker            p.stderr.close()
1232*cda5da8dSAndroid Build Coastguard Worker            p.stdout.close()
1233*cda5da8dSAndroid Build Coastguard Worker            status = p.returncode
1234*cda5da8dSAndroid Build Coastguard Worker            if status:
1235*cda5da8dSAndroid Build Coastguard Worker                self.log_error("CGI script exit status %#x", status)
1236*cda5da8dSAndroid Build Coastguard Worker            else:
1237*cda5da8dSAndroid Build Coastguard Worker                self.log_message("CGI script exited OK")
1238*cda5da8dSAndroid Build Coastguard Worker
1239*cda5da8dSAndroid Build Coastguard Worker
1240*cda5da8dSAndroid Build Coastguard Workerdef _get_best_family(*address):
1241*cda5da8dSAndroid Build Coastguard Worker    infos = socket.getaddrinfo(
1242*cda5da8dSAndroid Build Coastguard Worker        *address,
1243*cda5da8dSAndroid Build Coastguard Worker        type=socket.SOCK_STREAM,
1244*cda5da8dSAndroid Build Coastguard Worker        flags=socket.AI_PASSIVE,
1245*cda5da8dSAndroid Build Coastguard Worker    )
1246*cda5da8dSAndroid Build Coastguard Worker    family, type, proto, canonname, sockaddr = next(iter(infos))
1247*cda5da8dSAndroid Build Coastguard Worker    return family, sockaddr
1248*cda5da8dSAndroid Build Coastguard Worker
1249*cda5da8dSAndroid Build Coastguard Worker
1250*cda5da8dSAndroid Build Coastguard Workerdef test(HandlerClass=BaseHTTPRequestHandler,
1251*cda5da8dSAndroid Build Coastguard Worker         ServerClass=ThreadingHTTPServer,
1252*cda5da8dSAndroid Build Coastguard Worker         protocol="HTTP/1.0", port=8000, bind=None):
1253*cda5da8dSAndroid Build Coastguard Worker    """Test the HTTP request handler class.
1254*cda5da8dSAndroid Build Coastguard Worker
1255*cda5da8dSAndroid Build Coastguard Worker    This runs an HTTP server on port 8000 (or the port argument).
1256*cda5da8dSAndroid Build Coastguard Worker
1257*cda5da8dSAndroid Build Coastguard Worker    """
1258*cda5da8dSAndroid Build Coastguard Worker    ServerClass.address_family, addr = _get_best_family(bind, port)
1259*cda5da8dSAndroid Build Coastguard Worker    HandlerClass.protocol_version = protocol
1260*cda5da8dSAndroid Build Coastguard Worker    with ServerClass(addr, HandlerClass) as httpd:
1261*cda5da8dSAndroid Build Coastguard Worker        host, port = httpd.socket.getsockname()[:2]
1262*cda5da8dSAndroid Build Coastguard Worker        url_host = f'[{host}]' if ':' in host else host
1263*cda5da8dSAndroid Build Coastguard Worker        print(
1264*cda5da8dSAndroid Build Coastguard Worker            f"Serving HTTP on {host} port {port} "
1265*cda5da8dSAndroid Build Coastguard Worker            f"(http://{url_host}:{port}/) ..."
1266*cda5da8dSAndroid Build Coastguard Worker        )
1267*cda5da8dSAndroid Build Coastguard Worker        try:
1268*cda5da8dSAndroid Build Coastguard Worker            httpd.serve_forever()
1269*cda5da8dSAndroid Build Coastguard Worker        except KeyboardInterrupt:
1270*cda5da8dSAndroid Build Coastguard Worker            print("\nKeyboard interrupt received, exiting.")
1271*cda5da8dSAndroid Build Coastguard Worker            sys.exit(0)
1272*cda5da8dSAndroid Build Coastguard Worker
1273*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__':
1274*cda5da8dSAndroid Build Coastguard Worker    import argparse
1275*cda5da8dSAndroid Build Coastguard Worker    import contextlib
1276*cda5da8dSAndroid Build Coastguard Worker
1277*cda5da8dSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
1278*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('--cgi', action='store_true',
1279*cda5da8dSAndroid Build Coastguard Worker                        help='run as CGI server')
1280*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('-b', '--bind', metavar='ADDRESS',
1281*cda5da8dSAndroid Build Coastguard Worker                        help='bind to this address '
1282*cda5da8dSAndroid Build Coastguard Worker                             '(default: all interfaces)')
1283*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('-d', '--directory', default=os.getcwd(),
1284*cda5da8dSAndroid Build Coastguard Worker                        help='serve this directory '
1285*cda5da8dSAndroid Build Coastguard Worker                             '(default: current directory)')
1286*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('-p', '--protocol', metavar='VERSION',
1287*cda5da8dSAndroid Build Coastguard Worker                        default='HTTP/1.0',
1288*cda5da8dSAndroid Build Coastguard Worker                        help='conform to this HTTP version '
1289*cda5da8dSAndroid Build Coastguard Worker                             '(default: %(default)s)')
1290*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('port', default=8000, type=int, nargs='?',
1291*cda5da8dSAndroid Build Coastguard Worker                        help='bind to this port '
1292*cda5da8dSAndroid Build Coastguard Worker                             '(default: %(default)s)')
1293*cda5da8dSAndroid Build Coastguard Worker    args = parser.parse_args()
1294*cda5da8dSAndroid Build Coastguard Worker    if args.cgi:
1295*cda5da8dSAndroid Build Coastguard Worker        handler_class = CGIHTTPRequestHandler
1296*cda5da8dSAndroid Build Coastguard Worker    else:
1297*cda5da8dSAndroid Build Coastguard Worker        handler_class = SimpleHTTPRequestHandler
1298*cda5da8dSAndroid Build Coastguard Worker
1299*cda5da8dSAndroid Build Coastguard Worker    # ensure dual-stack is not disabled; ref #38907
1300*cda5da8dSAndroid Build Coastguard Worker    class DualStackServer(ThreadingHTTPServer):
1301*cda5da8dSAndroid Build Coastguard Worker
1302*cda5da8dSAndroid Build Coastguard Worker        def server_bind(self):
1303*cda5da8dSAndroid Build Coastguard Worker            # suppress exception when protocol is IPv4
1304*cda5da8dSAndroid Build Coastguard Worker            with contextlib.suppress(Exception):
1305*cda5da8dSAndroid Build Coastguard Worker                self.socket.setsockopt(
1306*cda5da8dSAndroid Build Coastguard Worker                    socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
1307*cda5da8dSAndroid Build Coastguard Worker            return super().server_bind()
1308*cda5da8dSAndroid Build Coastguard Worker
1309*cda5da8dSAndroid Build Coastguard Worker        def finish_request(self, request, client_address):
1310*cda5da8dSAndroid Build Coastguard Worker            self.RequestHandlerClass(request, client_address, self,
1311*cda5da8dSAndroid Build Coastguard Worker                                     directory=args.directory)
1312*cda5da8dSAndroid Build Coastguard Worker
1313*cda5da8dSAndroid Build Coastguard Worker    test(
1314*cda5da8dSAndroid Build Coastguard Worker        HandlerClass=handler_class,
1315*cda5da8dSAndroid Build Coastguard Worker        ServerClass=DualStackServer,
1316*cda5da8dSAndroid Build Coastguard Worker        port=args.port,
1317*cda5da8dSAndroid Build Coastguard Worker        bind=args.bind,
1318*cda5da8dSAndroid Build Coastguard Worker        protocol=args.protocol,
1319*cda5da8dSAndroid Build Coastguard Worker    )
1320