Source code for CGI

#!/usr/bin/env python3
# Generated by "pythonizer -d5 -v3 -saM ../CGI.pm" v1.025 run by SNOOPYJC on Fri Feb 10 13:57:17 2023
__author__ = """Joe Cool"""
__email__ = "snoopyjc@gmail.com"
__version__ = "1.025"
import builtins, os, perllib, re, sys, types

_bn = lambda s: "" if s is None else s
_pb = lambda b: 1 if b else ""
_str = lambda s: "" if s is None else str(s)
_locals_stack = []
from perllib import Die


[docs]class EvalReturn(Exception): pass
[docs]class LoopControl(Exception): pass
[docs]class LoopControl_METHOD(Exception): pass
[docs]class LoopControl_REDIRECT(Exception): pass
[docs]class LoopControl_UPLOADS(Exception): pass
from CGI.Util import ( ascii2ebcdic, ebcdic2ascii, escape, expires, make_attributes, rearrange, rearrange_header, unescape, ) perllib.init_package("CGI", is_class=True) perllib.init_package("CGI.MultipartBuffer", is_class=True) perllib.init_package("MultipartBuffer") # Return true when we've finished reading
[docs]def eof(*_args): [self] = perllib.list_of_n(_args, 1) if (len(_str(self.get("BUFFER"))) == 0) and (perllib.num(self.get("LENGTH")) <= 0): return 1 return None
CGI.MultipartBuffer.eof = lambda *_args, **_kwargs: perllib.tie_call(eof, _args, _kwargs) # This fills up our internal buffer in such a way that the # boundary is never split between reads
[docs]def fillBuffer(*_args): [self, bytes_] = perllib.list_of_n(_args, 2) if not (self.get("CHUNKED") or self.get("LENGTH")): return [boundaryLength] = perllib.list_of_n(len(_str(self.get("BOUNDARY"))), 1) [bufferLength] = perllib.list_of_n(len(_str(self.get("BUFFER"))), 1) [bytesToRead] = perllib.list_of_n( perllib.num(bytes_) - perllib.num(bufferLength) + perllib.num(boundaryLength) + 2, 1 ) if not self.get("CHUNKED") and perllib.num(self.get("LENGTH")) < perllib.num(bytesToRead): bytesToRead = self.get("LENGTH") # Try to read some data. We may hang here if the browser is screwed up. bytesRead = ( perllib.method_call( self.get("INTERFACE"), "read_from_client", self.get("BUFFER"), bytesToRead, bufferLength, ), perllib.set_element(self, "BUFFER", perllib.fetch_out_parameter(1)), )[0] if CGI.MultipartBuffer._DEBUG_v: perllib.perl_print( f"bytesToRead={_bn(bytesToRead)}, bufferLength={_bn(bufferLength)}, buffer={_bn(self).get('BUFFER','')}\n", file=sys.stderr, ) if not (self.get("BUFFER") is not None): self["BUFFER"] = "" # An apparent bug in the Apache server causes the read() # to return zero bytes repeatedly without blocking if the # remote user aborts during a file transfer. I don't know how # they manage this, but the workaround is to abort if we get # more than SPIN_LOOP_MAX consecutive zero reads. if perllib.num(bytesRead) <= 0: if (perllib.add_element(self, "ZERO_LOOP_COUNTER", 1) - 1) >= perllib.num( CGI.MultipartBuffer.SPIN_LOOP_MAX_v ): raise Die("CGI.pm: Server closed socket during multipart read (client aborted?).\n") else: self["ZERO_LOOP_COUNTER"] = 0 if not self.get("CHUNKED") and bytesRead: self["LENGTH"] = perllib.num(self["LENGTH"]) - perllib.num(bytesRead) return self.get("LENGTH")
CGI.MultipartBuffer.fillBuffer = lambda *_args, **_kwargs: perllib.tie_call( fillBuffer, _args, _kwargs ) # This will read $bytes or until the boundary is hit, whichever happens # first. After the boundary is hit, we return undef. The next read will # skip over the boundary and begin reading again;
[docs]def read(*_args): [self, bytes_] = perllib.list_of_n(_args, 2) # default number of bytes to read bytes_ = bytes_ or CGI.MultipartBuffer.FILLUNIT_v # Fill up our internal buffer in such a way that the boundary # is never split between reads. self.fillBuffer(bytes_) boundary_start = ( CGI.Util.ebcdic2ascii(self.get("BOUNDARY")) if CGI.EBCDIC_v else self.get("BOUNDARY") ) boundary_end = ( CGI.Util.ebcdic2ascii(_str(self.get("BOUNDARY"))) if CGI.EBCDIC_v else _str(self.get("BOUNDARY")) + "--" ) # Find the boundary in the buffer (it may not be there). start = _str(self.get("BUFFER")).find(_str(boundary_start)) if CGI.MultipartBuffer._DEBUG_v: perllib.perl_print( f"boundary={_bn(self).get('BOUNDARY','')} length={_bn(self).get('LENGTH','')} start={start}\n", file=sys.stderr, ) # protect against malformed multipart POST operations if not (self.get("CHUNKED") or (start >= 0 or perllib.num(self.get("LENGTH")) > 0)): raise Die("Malformed multipart POST\n") # EBCDIC NOTE: want to translate boundary search into ASCII here. # If the boundary begins the data, then skip past it # and return undef. if start == 0: # clear us out completely if we've hit the last boundary. if _str(self.get("BUFFER")).find(_str(boundary_end)) == 0: self["BUFFER"] = "" self["LENGTH"] = 0 return None # just remove the boundary. self["BUFFER"] = ( _str(self["BUFFER"])[:0] + _str(self["BUFFER"])[0 + len(_str(boundary_start)) :] ) perllib.substitute_element(self, "BUFFER", r"^\012\015?", r"", count=1) return None bytesToReturn = None if start > 0: # read up to the boundary bytesToReturn = bytes_ if start - 2 > perllib.num(bytes_) else start else: # read the requested number of bytes # leave enough bytes in the buffer to allow us to read # the boundary. Thanks to Kevin Hendrick for finding # this one. bytesToReturn = perllib.num(bytes_) - (len(_str(boundary_start)) + 1) returnval = _str(self.get("BUFFER"))[0 : 0 + perllib.int_(bytesToReturn)] self["BUFFER"] = ( _str(self["BUFFER"])[:0] + _str(self["BUFFER"])[0 + perllib.int_(bytesToReturn) :] ) # If we hit the boundary, remove the CRLF from the end. return returnval[0:-2] if (perllib.num(bytesToReturn) == start) else returnval
CGI.MultipartBuffer.read = lambda *_args, **_kwargs: perllib.tie_call(read, _args, _kwargs) # This reads and returns the body as a single scalar value.
[docs]def readBody(*_args): [self] = perllib.list_of_n(_args, 1) data_v = None [returnval] = perllib.list_of_n("", 1) # EBCDIC NOTE: want to translate returnval into EBCDIC HERE while (data_v := self.read()) is not None: returnval = _str(returnval) + _str(data_v) if CGI.EBCDIC_v: if CGI.MultipartBuffer._DEBUG_v: perllib.perl_print(f"untranslated body={_bn(returnval)}\n", file=sys.stderr) returnval = CGI.Util.ascii2ebcdic(returnval) if CGI.MultipartBuffer._DEBUG_v: perllib.perl_print(f"translated body={_bn(returnval)}\n", file=sys.stderr) return returnval
CGI.MultipartBuffer.readBody = lambda *_args, **_kwargs: perllib.tie_call( readBody, _args, _kwargs ) # internal routine, don't use def _set_attributes(*_args): _args = list(_args) self = _args.pop(0) if _args else None [element, attributes] = perllib.list_of_n(_args, 2) if not (attributes.get(_str(element)) is not None): return "" CGI.attribs_v = " " for attrib_l in sorted(list(attributes[_str(element)].keys())): clean_attrib = re.sub(r"^-", r"", attrib_l, count=1) CGI.attribs_v = ( _str(CGI.attribs_v) + f"""{perllib.LIST_SEPARATOR.join(map(_str,[clean_attrib.lower()]))}="{_bn(attributes)[_str(element)].get(attrib_l,'')}" """ ) CGI.attribs_v = re.sub(r" $", r"", _str(CGI.attribs_v), count=1) return CGI.attribs_v CGI._set_attributes = lambda *_args, **_kwargs: perllib.tie_call(_set_attributes, _args, _kwargs) ######################################################### # Globals and stubs for other packages that we use. ######################################################### ######################## CGI::MultipartBuffer #################### # internal routine, don't use def _set_values_and_labels(*_args): _args = list(_args) perllib.init_out_parameters(_args, 2) # refs: 2 self = _args.pop(0) if _args else None [v_v, l, n] = perllib.list_of_n(_args, 3) if perllib.refs(v_v) == "HASH" and not perllib.ref(l): perllib.store_out_parameter(None, 2, (l := v_v)) if v_v is None: return self.param(n) if not perllib.ref_scalar(v_v): return v_v return ( (sorted((v_v if v_v is not None else perllib.Hash()).keys())) if perllib.refs(v_v) == "HASH" else v_v ) CGI._set_values_and_labels = lambda *_args, **_kwargs: perllib.tie_call( _set_values_and_labels, _args, _kwargs ) def _mp_value_parse(*_args): [string, field] = perllib.list_of_n(_args, 2) is_quoted = ( 1 if (_m := re.search(rf"""[\s;]{_bn(field)}=\"""", _str(string)), _pb(_m))[1] else 0 ) param_v = "" if is_quoted: # a quoted token cannot contain anything but an unescaped quote [param_v] = perllib.list_of_n( ( _m := re.search(rf"""[\s;]{_bn(field)}="((?:\\"|[^"])*)\"""", _str(string)), _m.groups() if _m else [], )[1], 1, ) else: # a plain token cannot contain any reserved characters # https://tools.ietf.org/html/rfc2616#section-2.2 # separators = "(" | ")" | "<" | ">" | "@" # | "," | ";" | ":" | "\" | <"> # | "/" | "[" | "]" | "?" | "=" # | "{" | "}" | SP | HT [param_v] = perllib.list_of_n( ( _m := re.search( rf"""[\s;]{_bn(field)}=([^\(\)<>@,;:\\"/\[\]\?=\{{\}} \015\n\t]*)""", _str(string), ), _m.groups() if _m else [], )[1], 1, ) return param_v CGI._mp_value_parse = lambda *_args, **_kwargs: perllib.tie_call(_mp_value_parse, _args, _kwargs) ##### # subroutine: read_multipart_related # # Read multipart/related data and store it into our parameters. The # first parameter sets the start of the data. The part identified by # this Content-ID will not be stored as a file upload, but will be # returned by this method. All other parts will be available as file # uploads accessible by their Content-ID #####
[docs]def read_from_cmdline(*_args): global _d input_ = "" words = perllib.Array() query_string_v = "" subpath = "" if CGI.DEBUG_v and sys.argv[1:]: words = sys.argv[1:].copy() elif perllib.num(CGI.DEBUG_v) > 1: import Text.ParseWords as _Text_ParseWords perllib.perl_print( "(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)", file=sys.stderr, ) CGI.lines_a = sys.stdin.readlines() # remove newlines for _i in range(len(CGI.lines_a)): CGI.lines_a[_i] = _str(CGI.lines_a[_i]).rstrip("\n") # remove newlines input_ = " ".join(map(_str, CGI.lines_a)) words = perllib.Array(Text.ParseWords.old_shellwords(input_)) for _i3314, _d in enumerate(words): _d = re.sub(re.compile(r"\\="), r"%3D", _str(_d), count=0) words[_i3314] = _d _d = re.sub(re.compile(r"\\&"), r"%26", _str(_d), count=0) words[_i3314] = _d if re.search(r"=", f"{perllib.LIST_SEPARATOR.join(map(_str,words))}"): query_string_v = "&".join(map(_str, words)) else: query_string_v = "+".join(map(_str, words)) if _m := re.search(r"^(.*?)\?(.*)$", query_string_v): query_string_v = _m.group(2) subpath = _m.group(1) return perllib.Hash({"query_string": query_string_v, "subpath": subpath})
CGI.read_from_cmdline = lambda *_args, **_kwargs: perllib.tie_call( read_from_cmdline, _args, _kwargs ) ##### # subroutine: read_multipart # # Read multipart data and store it into our parameters. # An interesting feature is that if any of the parts is a file, we # create a temporary file and open up a filehandle on it so that the # caller can read from it if necessary. #####
[docs]def register_parameter(*_args): [self, param_v] = perllib.list_of_n(_args, 2) self[".parametersToAdd"][_s0] = ( perllib.num(self[".parametersToAdd"].get(_s0 := _str(param_v))) + 1 ) return perllib.num(self[".parametersToAdd"].get(_str(param_v))) - 1
CGI.register_parameter = lambda *_args, **_kwargs: perllib.tie_call( register_parameter, _args, _kwargs )
[docs]def previous_or_default(*_args): global _d [self, name, defaults_v, override] = perllib.list_of_n(_args, 4) selected = perllib.Hash() if not override and (self[".fieldnames"].get(_str(name)) or self.param(name) is not None): for _d in perllib.flatten([self.param(name, wantarray=True)]): selected[_s0] = perllib.num(selected.get(_s0 := _str(_d))) + 1 elif ( defaults_v is not None and perllib.ref_scalar(defaults_v) and (perllib.refs(defaults_v) == "ARRAY") ): for _d in defaults_v: selected[_s0] = perllib.num(selected.get(_s0 := _str(_d))) + 1 else: if defaults_v is not None: selected[_s0] = perllib.num(selected.get(_s0 := _str(defaults_v))) + 1 return selected
CGI.previous_or_default = lambda *_args, **_kwargs: perllib.tie_call( previous_or_default, _args, _kwargs ) #### Method: private_tempfiles # Set or return the private_tempfiles global flag ####
[docs]def private_tempfiles(*_args): perllib.perl_print("private_tempfiles has been deprecated", file=sys.stderr) return 0
CGI.private_tempfiles = lambda *_args, **_kwargs: perllib.tie_call( private_tempfiles, _args, _kwargs ) #### Method: close_upload_files # Set or return the close_upload_files global flag #### #### Method: remote_user # Return the authorization name used for user # verification. ####
[docs]def remote_user(*_args): return os.environ.get("REMOTE_USER") if (os.environ.get("REMOTE_USER") is not None) else None
CGI.remote_user = lambda *_args, **_kwargs: perllib.tie_call(remote_user, _args, _kwargs) #### Method: user_name # Try to return the remote user's name by hook or by # crook #### #### Method: auth_type # Return the type of use verification/authorization in use, if any. ####
[docs]def auth_type(*_args): return os.environ.get("AUTH_TYPE") if (os.environ.get("AUTH_TYPE") is not None) else None
CGI.auth_type = lambda *_args, **_kwargs: perllib.tie_call(auth_type, _args, _kwargs) #### Method: remote_ident # Return the identity of the remote user # (but only if his host is running identd) ####
[docs]def remote_ident(*_args): return ( os.environ.get("REMOTE_IDENT") if (os.environ.get("REMOTE_IDENT") is not None) else None )
CGI.remote_ident = lambda *_args, **_kwargs: perllib.tie_call(remote_ident, _args, _kwargs) #### Method: server_protocol # Return the protocol (usually HTTP/1.0) ####
[docs]def server_protocol(*_args): return os.environ.get("SERVER_PROTOCOL") or "HTTP/1.0" # for debugging
CGI.server_protocol = lambda *_args, **_kwargs: perllib.tie_call(server_protocol, _args, _kwargs) #### Method: http # Return the value of an HTTP variable, or # the list of variables if none provided #### #### Method: server_port # Return the tcp/ip port the server is running on ####
[docs]def server_port(*_args): return os.environ.get("SERVER_PORT") or 80 # for debugging
CGI.server_port = lambda *_args, **_kwargs: perllib.tie_call(server_port, _args, _kwargs) #### Method: server_software # Return the name of the server software ####
[docs]def server_software(*_args): return os.environ.get("SERVER_SOFTWARE") or "cmdline"
CGI.server_software = lambda *_args, **_kwargs: perllib.tie_call(server_software, _args, _kwargs) #### Method: virtual_port # Return the server port, taking virtual hosts into account #### #### Method: server_name # Return the name of the server ####
[docs]def server_name(*_args): return os.environ.get("SERVER_NAME") or "localhost"
CGI.server_name = lambda *_args, **_kwargs: perllib.tie_call(server_name, _args, _kwargs) #### Method: remote_addr # Return the IP addr of the remote host. ####
[docs]def remote_addr(*_args): return os.environ.get("REMOTE_ADDR") or "127.0.0.1"
CGI.remote_addr = lambda *_args, **_kwargs: perllib.tie_call(remote_addr, _args, _kwargs) #### Method: script_name # Return the partial URL to this script for # self-referencing scripts. Also see # self_url(), which returns a URL with all state information # preserved. #### #### Method: remote_host # Return the name of the remote host, or its IP # address if unavailable. If this variable isn't # defined, it returns "localhost" for debugging # purposes. ####
[docs]def remote_host(*_args): return os.environ.get("REMOTE_HOST") or os.environ.get("REMOTE_ADDR") or "localhost"
CGI.remote_host = lambda *_args, **_kwargs: perllib.tie_call(remote_host, _args, _kwargs)
[docs]def env_query_string(*_args): return ( os.environ.get("QUERY_STRING") if (os.environ.get("QUERY_STRING") is not None) else None )
CGI.env_query_string = lambda *_args, **_kwargs: perllib.tie_call( env_query_string, _args, _kwargs ) #### Method: accept # Without parameters, returns an array of the # MIME types the browser accepts. # With a single parameter equal to a MIME # type, will return undef if the browser won't # accept it, 1 if the browser accepts it but # doesn't give a preference, or a floating point # value between 0.0 and 1.0 if the browser # declares a quantitative score for it. # This handles MIME type globs correctly. #### #### Method: request_uri # Return the literal request URI ####
[docs]def request_uri(*_args): return os.environ.get("REQUEST_URI") if (os.environ.get("REQUEST_URI") is not None) else None
CGI.request_uri = lambda *_args, **_kwargs: perllib.tie_call(request_uri, _args, _kwargs) #### Method: query_string # Synthesize a query string from our current # parameters #### #### Method: path_translated # Return the physical path information provided # by the URL (if any) ####
[docs]def path_translated(*_args): return ( os.environ.get("PATH_TRANSLATED") if (os.environ.get("PATH_TRANSLATED") is not None) else None )
CGI.path_translated = lambda *_args, **_kwargs: perllib.tie_call(path_translated, _args, _kwargs) #### Method: content_type # Returns the content_type string ####
[docs]def content_type(*_args): return ( os.environ.get("CONTENT_TYPE") if (os.environ.get("CONTENT_TYPE") is not None) else None )
CGI.content_type = lambda *_args, **_kwargs: perllib.tie_call(content_type, _args, _kwargs) #### Method: request_method # Returns 'POST', 'GET', 'PUT', 'PATCH' or 'HEAD' ####
[docs]def request_method(*_args): return ( os.environ.get("REQUEST_METHOD") if (os.environ.get("REQUEST_METHOD") is not None) else None )
CGI.request_method = lambda *_args, **_kwargs: perllib.tie_call(request_method, _args, _kwargs) # This function returns a potentially modified version of SCRIPT_NAME # and PATH_INFO. Some HTTP servers do sanitise the paths in those # variables. It is the case of at least Apache 2. If for instance the # user requests: /path/./to/script.cgi/x//y/z/../x?y, Apache will set: # REQUEST_URI=/path/./to/script.cgi/x//y/z/../x?y # SCRIPT_NAME=/path/to/env.cgi # PATH_INFO=/x/y/x # # This is all fine except that some bogus CGI scripts expect # PATH_INFO=/http://foo when the user requests # http://xxx/script.cgi/http://foo # # Old versions of this module used to accomodate with those scripts, so # this is why we do this here to keep those scripts backward compatible. # Basically, we accomodate with those scripts but within limits, that is # we only try to preserve the number of / that were provided by the user # if $REQUEST_URI and "$SCRIPT_NAME$PATH_INFO" only differ by the number # of consecutive /. # # So for instance, in: http://foo/x//y/script.cgi/a//b, we'll return a # script_name of /x//y/script.cgi and a path_info of /a//b, but in: # http://foo/./x//z/script.cgi/a/../b//c, we'll return the versions # possibly sanitised by the HTTP server, so in the case of Apache 2: # script_name == /foo/x/z/script.cgi and path_info == /b/c. # # Future versions of this module may no longer do that, so one should # avoid relying on the browser, proxy, server, and CGI.pm preserving the # number of consecutive slashes as no guarantee can be made there. def _name_and_path_from_env(*_args): _args = list(_args) path_info_pattern = "" script_name_pattern = "" self = _args.pop(0) if _args else None script_name_v = os.environ.get("SCRIPT_NAME") or "" path_info_v = os.environ.get("PATH_INFO") or "" uri = self.request_uri() or "" uri = re.sub(re.compile(r"\?.*", re.S), r"", _str(uri), count=1) uri = unescape(uri) if CGI.IIS_v: # IIS doesn't set $ENV{PATH_INFO} correctly. It sets it to # $ENV{SCRIPT_NAME}path_info # IIS also doesn't set $ENV{REQUEST_URI} so we don't want to do # the test below, hence this comes first def _f2886(_m_): global _m _m = _m_ return _m.expand(r"\g<1>") path_info_v = re.sub( re.compile(rf"^{perllib.quotemeta(_bn(script_name_v))}(.*)"), _f2886, _str(path_info_v), count=1, ) elif _str(uri) != f"{_bn(script_name_v)}{_bn(path_info_v)}": script_name_pattern = perllib.quotemeta(_str(script_name_v)) path_info_pattern = perllib.quotemeta(_str(path_info_v)) script_name_pattern = re.sub(re.compile(r"(?:\\/)+"), r"/+", script_name_pattern, count=0) path_info_pattern = re.sub(re.compile(r"(?:\\/)+"), r"/+", path_info_pattern, count=0) if _m := re.search( re.compile(rf"^({script_name_pattern})({path_info_pattern})$", re.S), _str(uri) ): # REQUEST_URI and SCRIPT_NAME . PATH_INFO only differ by the # numer of consecutive slashes, so we can extract the info from # REQUEST_URI: [script_name_v, path_info_v] = (_m.group(1), _m.group(2)) return perllib.Array([script_name_v, path_info_v]) CGI._name_and_path_from_env = lambda *_args, **_kwargs: perllib.tie_call( _name_and_path_from_env, _args, _kwargs )
[docs]def parse_keywordlist(*_args): [self, tosplit] = perllib.list_of_n(_args, 2) tosplit = unescape(tosplit) # unescape the keywords tosplit = _str(tosplit).translate(str.maketrans("+", " ")) # pluses to spaces keywords_a = perllib.Array(perllib.split(r"\s+", _str(tosplit))) return keywords_a
CGI.parse_keywordlist = lambda *_args, **_kwargs: perllib.tie_call( parse_keywordlist, _args, _kwargs ) # Internal procedure - don't use def _tableize(*_args): global _d [rows, columns, rowheaders, colheaders, *elements] = perllib.list_of_at_least_n(_args, 4) elements = perllib.Array(elements) rowheaders_a = perllib.Array(rowheaders if rowheaders else perllib.Array()) colheaders_a = perllib.Array(colheaders if colheaders else perllib.Array()) result_v = "" if columns is not None: if rows is None: rows = perllib.int_(0.99 + len(elements) / perllib.num(columns)) if rows is not None: if columns is None: columns = perllib.int_(0.99 + len(elements) / perllib.num(rows)) # rearrange into a pretty table result_v = "<table>" row = 0 column = 0 if colheaders_a and rowheaders_a: colheaders_a[0:0] = [""] if colheaders_a: result_v += "<tr>" for _d in colheaders_a: result_v += f"<th>{_bn(_d)}</th>" for row in range(0, perllib.num(rows)): result_v += "<tr>" if rowheaders_a: result_v += f"<th>{rowheaders_a[row]}</th>" for column in range(0, perllib.num(columns)): if ( elements.get( column * perllib.int_(rows) + row if column * perllib.int_(rows) + row >= 0 else len(elements) + column * perllib.int_(rows) + row ) is not None ): result_v += "<td>" + _str(elements[column * perllib.int_(rows) + row]) + "</td>" result_v += "</tr>" result_v += "</table>" return result_v CGI._tableize = lambda *_args, **_kwargs: perllib.tie_call(_tableize, _args, _kwargs) #### Method: radio_group # Create a list of logically-linked radio buttons. # Parameters: # $name -> Common name for all the buttons. # $values -> A pointer to a regular array containing the # values for each button in the group. # $default -> (optional) Value of the button to turn on by default. Pass '-' # to turn _nothing_ on. # $linebreak -> (optional) Set to true to place linebreaks # between the buttons. # $labels -> (optional) # A pointer to a hash of labels to print next to each checkbox # in the form $label{'value'}="Long explanatory label". # Otherwise the provided values are used as the labels. # Returns: # An ARRAY containing a series of <input type="radio"> fields #### #### Method: end_html # End an HTML document. # Trivial method for completeness. Just returns "</body>" ####
[docs]def end_html(*_args): return "\n</body>\n</html>"
CGI.end_html = lambda *_args, **_kwargs: perllib.tie_call(end_html, _args, _kwargs) ################################ # METHODS USED IN BUILDING FORMS ################################ #### Method: isindex # Just prints out the isindex tag. # Parameters: # $action -> optional URL of script to run # Returns: # A string containing a <isindex> tag def _script(*_args): [self, script] = perllib.list_of_n(_args, 2) result = perllib.Array() scripts = perllib.Array(script if perllib.refs(script) == "ARRAY" else (script)) for script_l in scripts: src = code = language = charset_v = None if perllib.ref_scalar(script_l): # script is a hash [src, code, CGI.type_v, charset_v] = perllib.list_of_n( rearrange( perllib.Array(["SRC", "CODE", ["LANGUAGE", "TYPE"], "CHARSET"]), "-foo", "bar", script_l if perllib.refs(script_l) == "ARRAY" else script_l, ), 4, ) # a trick to allow the '-' to be omitted CGI.type_v = CGI.type_v or "text/javascript" if not ((re.search(r"\w+/\w+", _str(CGI.type_v)))): CGI.type_v = re.sub(r"[\d.]+$", r"", _str(CGI.type_v), count=1) CGI.type_v = f"text/{_bn(CGI.type_v)}" else: [src, code, CGI.type_v, charset_v] = ("", script_l, "text/javascript", "") comment_v = "//" # javascript by default if re.search(re.compile(r"perl|tcl", re.I), _str(CGI.type_v)): comment_v = "#" if re.search(re.compile(r"vbscript", re.I), _str(CGI.type_v)): comment_v = "'" cdata_start = "" cdata_end = "" if CGI.XHTML_v: cdata_start = f"{comment_v}<![CDATA[\n" cdata_end += f"\n{comment_v}]]>" else: cdata_start = "\n<!-- Hide script\n" cdata_end = comment_v cdata_end += " End script hiding -->\n" satts = perllib.Array() if src: satts.extend(perllib.make_list("src", src)) satts.extend(perllib.make_list("type", CGI.type_v)) if src and charset_v: satts.extend(perllib.make_list("charset", charset_v)) if code is not None: code = cdata_start + _str(code) + cdata_end result.extend( perllib.make_list( self.script( perllib.Hash( perllib.Hash({satts[_i]: satts[_i + 1] for _i in range(0, len(satts), 2)}) ), code or "", ) ) ) return result CGI._script = lambda *_args, **_kwargs: perllib.tie_call(_script, _args, _kwargs) #### Method: restore_parameters # A way to restore CGI parameters from an initializer. # Only intended to be used with the function (non-OO) interface. ####
[docs]def restore_parameters(*_args): CGI.Q_v = perllib.method_call(CGI.DefaultClass_v, "new", *_args) return CGI.Q_v
CGI.restore_parameters = lambda *_args, **_kwargs: perllib.tie_call( restore_parameters, _args, _kwargs ) #### Method: multipart_init # Return a Content-Type: style header for server-push # This has to be NPH on most web servers, and it is advisable to set $| = 1 # # Many thanks to Ed Jordan <ed@fidalgo.net> for this # contribution, updated by Andrew Benham (adsb@bigfoot.com) #### #### Method: version # Return the current version ####
[docs]def version(*_args): return CGI.VERSION_v
CGI.version = lambda *_args, **_kwargs: perllib.tie_call(version, _args, _kwargs) #### Method: url_param # Return a parameter in the QUERY_STRING, regardless of # whether this was a POST or a GET ####
[docs]def CLEAR(*_args): _args[0] = perllib.Hash() return _args[0]
CGI.CLEAR = lambda *_args, **_kwargs: perllib.tie_call(CLEAR, _args, _kwargs) #### #### # Append a new value to an existing query ####
[docs]def DELETE(*_args): [self, param_v] = perllib.list_of_n(_args, 2) value_v = self.FETCH(param_v) self.delete(param_v) return value_v
CGI.DELETE = lambda *_args, **_kwargs: perllib.tie_call(DELETE, _args, _kwargs)
[docs]def EXISTS(*_args): return _str(_args[1]) in _args[0]["param"]
CGI.EXISTS = lambda *_args, **_kwargs: perllib.tie_call(EXISTS, _args, _kwargs)
[docs]def NEXTKEY(*_args): return _args[0][".parameters"][ (perllib.int_(perllib.add_element(_args[0], ".iterator", 1)) - 1) ]
CGI.NEXTKEY = lambda *_args, **_kwargs: perllib.tie_call(NEXTKEY, _args, _kwargs)
[docs]def FIRSTKEY(*_args): _args[0][".iterator"] = 0 return _args[0][".parameters"][ (perllib.int_(perllib.add_element(_args[0], ".iterator", 1)) - 1) ]
CGI.FIRSTKEY = lambda *_args, **_kwargs: perllib.tie_call(FIRSTKEY, _args, _kwargs)
[docs]def STORE(*_args): _args = list(_args) self = _args.pop(0) if _args else None tag = _args.pop(0) if _args else None vals = _args.pop(0) if _args else None vals_a = perllib.Array( _str(vals).split("\0") if vals is not None and _str(vals).find("\0") != -1 else vals ) return self.param("-name", tag, "-value", vals_a)
CGI.STORE = lambda *_args, **_kwargs: perllib.tie_call(STORE, _args, _kwargs)
[docs]def MethPut(*_args): return _pb(_str(request_method()) == "PUT")
CGI.MethPut = lambda *_args, **_kwargs: perllib.tie_call(MethPut, _args, _kwargs)
[docs]def MethPost(*_args): return _pb(_str(request_method()) == "POST")
CGI.MethPost = lambda *_args, **_kwargs: perllib.tie_call(MethPost, _args, _kwargs)
[docs]def MethPatch(*_args): return _pb(_str(request_method()) == "PATCH")
CGI.MethPatch = lambda *_args, **_kwargs: perllib.tie_call(MethPatch, _args, _kwargs)
[docs]def MethGet(*_args): return _pb(_str(request_method()) == "GET")
CGI.MethGet = lambda *_args, **_kwargs: perllib.tie_call(MethGet, _args, _kwargs)
[docs]def SplitParam(*_args, wantarray=False): [param_v] = perllib.list_of_n(_args, 1) params = perllib.Array(_str(param_v).split("\0")) return params if wantarray else params[0]
CGI.SplitParam = lambda *_args, **_kwargs: perllib.tie_call(SplitParam, _args, _kwargs)
[docs]def SERVER_PUSH(*_args): _args = list(_args) return 'multipart/x-mixed-replace;boundary="' + _str(_args.pop(0) if _args else None) + '"'
CGI.SERVER_PUSH = lambda *_args, **_kwargs: perllib.tie_call(SERVER_PUSH, _args, _kwargs) # Create a new multipart buffer
[docs]def MULTIPART(*_args): return "multipart/form-data"
CGI.MULTIPART = lambda *_args, **_kwargs: perllib.tie_call(MULTIPART, _args, _kwargs)
[docs]def URL_ENCODED(*_args): return "application/x-www-form-urlencoded"
CGI.URL_ENCODED = lambda *_args, **_kwargs: perllib.tie_call(URL_ENCODED, _args, _kwargs) def _checked(*_args): _args = list(_args) self = _args.pop(0) if _args else None value_v = _args.pop(0) if _args else None if not value_v: return "" return 'checked="checked" ' if CGI.XHTML_v else "checked " CGI._checked = lambda *_args, **_kwargs: perllib.tie_call(_checked, _args, _kwargs) def _selected(*_args): _args = list(_args) self = _args.pop(0) if _args else None value_v = _args.pop(0) if _args else None if not value_v: return "" return 'selected="selected" ' if CGI.XHTML_v else "selected " CGI._selected = lambda *_args, **_kwargs: perllib.tie_call(_selected, _args, _kwargs) def _all_html_tags(*_args): return "a abbr acronym address applet Area b base basefont bdo big blink blockquote body br caption center cite code col colgroup dd del dfn div dl dt em embed fieldset font fontsize frame frameset h1 h2 h3 h4 h5 h6 head hr html i iframe ilayer img input ins kbd label layer legend li Link Map menu meta nextid nobr noframes noscript object ol option p Param pre Q samp script Select small span strike strong style Sub sup table tbody td tfoot th thead title Tr TR tt u ul var".split() CGI._all_html_tags = lambda *_args, **_kwargs: perllib.tie_call(_all_html_tags, _args, _kwargs) # back compatibility html tag generation functions - noop # since this is now the default having removed AUTOLOAD
[docs]def compile_(*_args): return 1
CGI.compile_ = lambda *_args, **_kwargs: perllib.tie_call(compile_, _args, _kwargs) # put a filehandle into binary mode (DOS)
[docs]def binmode(*_args): _args = list(_args) perllib.init_out_parameters(_args, 1) if not ( (1 < len(_args) and _args[1] is not None) and perllib.ref_scalar(_args[1]) and perllib.fileno(_args[1]) is not None ): return return perllib.store_out_parameter( _args, 1, perllib.binmode(_args[1], mode="b", encoding=None, errors=None) )
CGI.binmode = lambda *_args, **_kwargs: perllib.tie_call(binmode, _args, _kwargs)
[docs]def all_parameters(*_args, wantarray=False): _args = list(_args) self = _args.pop(0) if _args else None if not (self is not None and self.get(".parameters")): return perllib.Array() if wantarray else None if not self.get(".parameters"): return perllib.Array() if wantarray else None return self.get(".parameters")
CGI.all_parameters = lambda *_args, **_kwargs: perllib.tie_call(all_parameters, _args, _kwargs)
[docs]def save_request(*_args): global _d [self] = perllib.list_of_n(_args, 1) # We're going to play with the package globals now so that if we get called # again, we initialize ourselves in exactly the same way. This allows # us to have several of these objects. CGI.QUERY_PARAM_a = perllib.Array(self.param(wantarray=True)) # save list of parameters for _d in CGI.QUERY_PARAM_a: if _d is None: continue CGI.QUERY_PARAM_h[_str(_d)] = self["param"].get(_str(_d)) CGI.QUERY_CHARSET_v = self.charset() CGI.QUERY_FIELDNAMES_h = perllib.Hash(self.get(".fieldnames")) CGI.QUERY_TMPFILES_h = perllib.Hash(self.get(".tmpfiles") or perllib.Hash()) return CGI.QUERY_TMPFILES_h
CGI.save_request = lambda *_args, **_kwargs: perllib.tie_call(save_request, _args, _kwargs) # print to standard output (for overriding in mod_perl) CGI.print_ = lambda *_args, **_kwargs: perllib.tie_call(print_, _args, _kwargs) # get/set last cgi_error # FUNCTIONS TO OVERRIDE: # Turn a string into a filehandle
[docs]def to_filehandle(*_args): _args = list(_args) caller = 0 package = None tmp = None thingy = _args.pop(0) if _args else None if not thingy: return None if perllib.isa(thingy, "GLOB"): return thingy if perllib.isa(thingy, "FileHandle"): return thingy if not perllib.ref_scalar(thingy): caller = 1 while package := perllib.caller_s((caller := caller + 1) - 1): [tmp] = perllib.list_of_n( thingy if (re.search(r"[\':]", _str(thingy))) else f"{_bn(package)}::{_bn(thingy)}", 1, ) if perllib.fileno(tmp) is not None: return tmp return None
CGI.to_filehandle = lambda *_args, **_kwargs: perllib.tie_call(to_filehandle, _args, _kwargs) # send output to the browser def _get_query_string_from_env(*_args): _args = list(_args) key = "" prev = None self = _args.pop(0) if _args else None query_string_v = "" if CGI.MOD_PERL_v: query_string_v = perllib.method_call(self.r(), "args") if not query_string_v and perllib.num(CGI.MOD_PERL_v) == 2: # possibly a redirect, inspect prev request # (->prev only supported under mod_perl2) if prev := perllib.method_call(self.r(), "prev"): query_string_v = prev.args() if os.environ.get("QUERY_STRING") is not None: query_string_v = query_string_v or os.environ.get("QUERY_STRING") if not query_string_v: # try to get from REDIRECT_ env variables, support # 5 levels of redirect and no more (RT #36312) # REDIRECT for r_l in range(1, 5 + 1): key = "".join(map(_str, ("REDIRECT_" * r_l))) if os.environ.get(f"{key}QUERY_STRING") is not None: query_string_v = query_string_v or os.environ.get(f"{key}QUERY_STRING") if query_string_v: break return query_string_v CGI._get_query_string_from_env = lambda *_args, **_kwargs: perllib.tie_call( _get_query_string_from_env, _args, _kwargs )
[docs]def self_or_default(*_args, wantarray=False): _args = list(_args) if ( (0 < len(_args) and _args[0] is not None) and (not perllib.ref_scalar(_args[0])) and (_str(_args[0]) == "CGI") ): return _args if not ( (0 < len(_args) and _args[0] is not None) and (perllib.ref_scalar(_args[0]) == "CGI" or perllib.isa(_args[0], "CGI")) ): # slightly optimized for common case if CGI.Q_v is None: CGI.Q_v = perllib.method_call(CGI.DefaultClass_v, "new") _args[0:0] = [CGI.Q_v] return _args if wantarray else CGI.Q_v
CGI.self_or_default = lambda *_args, **_kwargs: perllib.tie_call(self_or_default, _args, _kwargs)
[docs]def uploadInfo(*_args): [self, filename] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) if filename is None: return return self[".tmpfiles"][_str(filename) + _str(filename)].get("info")
CGI.uploadInfo = lambda *_args, **_kwargs: perllib.tie_call(uploadInfo, _args, _kwargs)
[docs]def tmpFileName(*_args): [self, filename] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) # preferred calling convention: $filename came directly from param or upload if perllib.ref_scalar(filename): return self[".tmpfiles"][_str(filename) + _str(filename)].get("name") or "" # backwards compatible with older versions: $filename is merely equal to # one of our filenames when compared as strings for param_name_l in perllib.flatten([self.param(wantarray=True)]): for filehandle_l in perllib.flatten([self.multi_param(param_name_l)]): if _str(filehandle_l) == _str(filename): return ( self[".tmpfiles"][_str(filehandle_l) + _str(filehandle_l)].get("name") or "" ) return ""
CGI.tmpFileName = lambda *_args, **_kwargs: perllib.tie_call(tmpFileName, _args, _kwargs)
[docs]def upload(*_args, wantarray=False): global _d [self, param_name] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) param_a = perllib.Array( list( filter( lambda _d: perllib.ref_scalar(_d) and perllib.fileno(_d) is not None, perllib.make_list(self.param(param_name, wantarray=True)), ) ) ) if not param_a: return perllib.Array() if wantarray else None return param_a if wantarray else param_a[0]
CGI.upload = lambda *_args, **_kwargs: perllib.tie_call(upload, _args, _kwargs)
[docs]def virtual_port(*_args): [self] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 1) vh = self.http("x_forwarded_host") or self.http("host") protocol_v = self.protocol() if vh: return ((_m := re.search(r":(\d+)$", _str(vh)), _m.groups() if _m else [])[1])[0] or ( 443 if _str(protocol_v) == "https" else 80 ) else: return self.server_port()
CGI.virtual_port = lambda *_args, **_kwargs: perllib.tie_call(virtual_port, _args, _kwargs)
[docs]def script_name(*_args): path_info_v = None script_name_v = None [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) if p: self[".script_name"] = p.pop(0) if p else None elif not ".script_name" in self: [script_name_v, path_info_v] = perllib.list_of_n(self._name_and_path_from_env(), 2) self[".script_name"] = script_name_v return self.get(".script_name")
CGI.script_name = lambda *_args, **_kwargs: perllib.tie_call(script_name, _args, _kwargs) #### Method: referer # Return the HTTP_REFERER: useful for generating # a GO BACK button. #### ############################################### # OTHER INFORMATION PROVIDED BY THE ENVIRONMENT ############################################### #### Method: path_info # Return the extra virtual path information provided # after the URL (if any) ####
[docs]def path_info(*_args): path_info_v = None [self, info] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) if info is not None: if _str(info) != "" and _str(info)[0:1] != "/": info = f"/{_bn(info)}" self[".path_info"] = info elif self.get(".path_info") is None: [_, path_info_v] = perllib.list_of_n(self._name_and_path_from_env(), 2) self[".path_info"] = path_info_v or "" return self.get(".path_info")
CGI.path_info = lambda *_args, **_kwargs: perllib.tie_call(path_info, _args, _kwargs)
[docs]def param_fetch(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [name] = perllib.list_of_n(rearrange(perllib.Array(["NAME"]), *p), 1) if name is None: return perllib.Array() if not (_str(name) in self["param"]): self.add_parameter(name) self["param"][_str(name)] = perllib.Array() return self["param"].get(_str(name))
CGI.param_fetch = lambda *_args, **_kwargs: perllib.tie_call(param_fetch, _args, _kwargs) #### Method: self_url # Returns a URL containing the current script and all its # param/value pairs arranged as a query. You can use this # to create a link that, when selected, will reinvoke the # script with all its state information preserved. ####
[docs]def self_url(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.url("-path_info", 1, "-query", 1, "-full", 1, *p)
CGI.self_url = lambda *_args, **_kwargs: perllib.tie_call(self_url, _args, _kwargs) # This is provided as a synonym to self_url() for people unfortunate # enough to have incorporated it into their programs already!
[docs]def state(*_args): return self_url(*_args)
CGI.state = lambda *_args, **_kwargs: perllib.tie_call(state, _args, _kwargs) #### Method: url # Like self_url, but doesn't return the query string part of # the URL. #### #### Method: image_button # Parameters: # $name -> Name of the button # $src -> URL of the image source # $align -> Alignment style (TOP, BOTTOM or MIDDLE) # Returns: # A string containing a <input type="image" name="name" src="url" align="alignment"> ####
[docs]def image_button(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [name, src, alignment, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["NAME", "SRC", "ALIGN"]), *p), 3 ) other = perllib.Array(other) [align] = perllib.list_of_n( f""" align={(chr(34)+_bn(alignment)+chr(34)).lower()}""" if alignment else "", 1 ) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) name = self._maybe_escapeHTML(name) return ( f'<input type="image" name="{_bn(name)}" src="{_bn(src)}"{_bn(align)}{_bn(other_v)} />' if CGI.XHTML_v else f'<input type="image" name="{_bn(name)}" src="{_bn(src)}"{_bn(align)}{_bn(other_v)}>' )
CGI.image_button = lambda *_args, **_kwargs: perllib.tie_call(image_button, _args, _kwargs) #### Method: scrolling_list # Create a scrolling list. # Parameters: # $name -> name for the list # $values -> A pointer to a regular array containing the # values for each option line in the list. # $defaults -> (optional) # 1. If a pointer to a regular array of options, # then this will be used to decide which # lines to turn on by default. # 2. Otherwise holds the value of the single line to turn on. # $size -> (optional) Size of the list. # $multiple -> (optional) If set, allow multiple selections. # $labels -> (optional) # A pointer to a hash of labels to print next to each checkbox # in the form $label{'value'}="Long explanatory label". # Otherwise the provided values are used as the labels. # Returns: # A string containing the definition of a scrolling list. ####
[docs]def scrolling_list(*_args): global _d attribs_v = None label = None selectit = None value_v = None [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [ name, values_v, defaults_v, size, multiple, labels, attributes, override, tabindex, *other, ] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ "NAME", ["VALUES", "VALUE"], ["DEFAULTS", "DEFAULT"], "SIZE", "MULTIPLE", "LABELS", "ATTRIBUTES", ["OVERRIDE", "FORCE"], "TABINDEX", ] ), *p, ), 9, ) other = perllib.Array(other) result_v = "" values_ = perllib.Array() values_ = perllib.Array( ( self._set_values_and_labels(values_v, labels, name), (labels := perllib.fetch_out_parameter(2)), )[0] ) size = size or len(values_) selected = perllib.Hash(self.previous_or_default(name, defaults_v, override)) [is_multiple] = perllib.list_of_n(' multiple="multiple"' if multiple else "", 1) [has_size] = perllib.list_of_n(f' size="{_bn(size)}"' if size else "", 1) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) name = self._maybe_escapeHTML(name) tabindex = self.element_tab(tabindex) result_v = f"""<select name="{_bn(name)}" {_bn(tabindex)}{_bn(has_size)}{_bn(is_multiple)}{_bn(other_v)}>\n""" for _d in values_: if re.search(r"<optgroup", _str(_d)): for _i2580, v_l in enumerate(_s2580 := perllib.split(r"\n", _d)): selectit = 'selected="selected"' if CGI.XHTML_v else "selected" for selected_l in sorted(list(selected.keys())): def _f2583(_m_): global _m _m = _m_ return _m.expand(rf"{_bn(selectit)} \g<1>") _s2580[_i2580] = v_l v_l = re.sub( re.compile(rf'(value="{selected_l}")'), _f2583, _str(v_l), count=1 ) _s2580[_i2580] = v_l result_v += f"{_bn(v_l)}\n" else: attribs_v = self._set_attributes(_d, attributes) [selectit] = perllib.list_of_n(self._selected(selected.get(_d)), 1) [label] = perllib.list_of_n(_d, 1) if labels is not None and labels.get(_str(_d)) is not None: label = labels.get(_str(_d)) [value_v] = perllib.list_of_n(self._maybe_escapeHTML(_d), 1) label = self._maybe_escapeHTML(label, 1) result_v += f"""<option{_bn(attribs_v)} {_bn(selectit)}value="{_bn(value_v)}">{_bn(label)}</option>\n""" result_v += "</select>" self.register_parameter(name) return result_v
CGI.scrolling_list = lambda *_args, **_kwargs: perllib.tie_call(scrolling_list, _args, _kwargs) #### Method: hidden # Parameters: # $name -> Name of the hidden field # @default -> (optional) Initial values of field (may be an array) # or # $default->[initial values of field] # Returns: # A string containing a <input type="hidden" name="name" value="value"> #### #### Method: optgroup # Create a optgroup. # Parameters: # $name -> Label for the group # $values -> A pointer to a regular array containing the # values for each option line in the group. # $labels -> (optional) # A pointer to a hash of labels to print next to each item # in the form $label{'value'}="Long explanatory label". # Otherwise the provided values are used as the labels. # $labeled -> (optional) # A true value indicates the value should be used as the label attribute # in the option elements. # The label attribute specifies the option label presented to the user. # This defaults to the content of the <option> element, but the label # attribute allows authors to more easily use optgroup without sacrificing # compatibility with browsers that do not support option groups. # $novals -> (optional) # A true value indicates to suppress the val attribute in the option elements # Returns: # A string containing the definition of an option group. ####
[docs]def optgroup(*_args): global _d attribs_v = None label = None selectit = "" value_v = None [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [name, values_v, attributes, labeled, noval, labels, *other] = perllib.list_of_at_least_n( rearrange( perllib.Array( ["NAME", ["VALUES", "VALUE"], "ATTRIBUTES", "LABELED", "NOVALS", "LABELS"] ), *p, ), 6, ) other = perllib.Array(other) result_v = "" values_ = perllib.Array() values_ = perllib.Array( ( self._set_values_and_labels(values_v, labels, name, labeled, CGI.novals_v), (labels := perllib.fetch_out_parameter(2)), )[0] ) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) name = self._maybe_escapeHTML(name) or "" result_v = f"""<optgroup label="{_bn(name)}"{_bn(other_v)}>\n""" for _d in values_: if re.search(r"<optgroup", _str(_d)): for _i2516, _d in enumerate(_s2516 := perllib.split(r"\n", _d)): selectit = 'selected="selected"' if CGI.XHTML_v else "selected" if CGI.selected_v is not None: def _f2518(_m_): global _m _m = _m_ return _m.expand(rf"{_bn(selectit)} \g<1>") _s2516[_i2516] = _d _d = re.sub( re.compile(rf'(value="{_bn(CGI.selected_v)}")'), _f2518, _d, count=1 ) _s2516[_i2516] = _d result_v += f"{_bn(_d)}\n" else: attribs_v = self._set_attributes(_d, attributes) [label] = perllib.list_of_n(_d, 1) if labels is not None and labels.get(_str(_d)) is not None: label = labels.get(_str(_d)) label = self._maybe_escapeHTML(label) [value_v] = perllib.list_of_n(self._maybe_escapeHTML(_d, 1), 1) result_v += ( ( f"""<option{_bn(attribs_v)} label="{_bn(value_v)}">{_bn(label)}</option>\n""" if CGI.novals_v else f"""<option{_bn(attribs_v)} label="{_bn(value_v)}" value="{_bn(value_v)}">{_bn(label)}</option>\n""" ) if labeled else f"<option{_bn(attribs_v)}>{_bn(label)}</option>\n" if CGI.novals_v else f"""<option{_bn(attribs_v)} value="{_bn(value_v)}">{_bn(label)}</option>\n""" ) result_v += "</optgroup>" return result_v
CGI.optgroup = lambda *_args, **_kwargs: perllib.tie_call(optgroup, _args, _kwargs) #### Method: popup_menu # Create a popup menu. # Parameters: # $name -> Name for all the menu # $values -> A pointer to a regular array containing the # text of each menu item. # $default -> (optional) Default item to display # $labels -> (optional) # A pointer to a hash of labels to print next to each checkbox # in the form $label{'value'}="Long explanatory label". # Otherwise the provided values are used as the labels. # Returns: # A string containing the definition of a popup menu. #### CGI.popup_menu = lambda *_args, **_kwargs: perllib.tie_call(popup_menu, _args, _kwargs) #### Method: checkbox_group # Create a list of logically-linked checkboxes. # Parameters: # $name -> Common name for all the check boxes # $values -> A pointer to a regular array containing the # values for each checkbox in the group. # $defaults -> (optional) # 1. If a pointer to a regular array of checkbox values, # then this will be used to decide which # checkboxes to turn on by default. # 2. If a scalar, will be assumed to hold the # value of a single checkbox in the group to turn on. # $linebreak -> (optional) Set to true to place linebreaks # between the buttons. # $labels -> (optional) # A pointer to a hash of labels to print next to each checkbox # in the form $label{'value'}="Long explanatory label". # Otherwise the provided values are used as the labels. # Returns: # An ARRAY containing a series of <input type="checkbox"> fields ####
[docs]def checkbox_group(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self._box_group("checkbox", *p)
CGI.checkbox_group = lambda *_args, **_kwargs: perllib.tie_call(checkbox_group, _args, _kwargs)
[docs]def radio_group(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self._box_group("radio", *p)
CGI.radio_group = lambda *_args, **_kwargs: perllib.tie_call(radio_group, _args, _kwargs) #### Method: checkbox # Create a checkbox that is not logically linked to any others. # The field value is "on" when the button is checked. # Parameters: # $name -> Name of the checkbox # $checked -> (optional) turned on by default if true # $value -> (optional) value of the checkbox, 'on' by default # $label -> (optional) a user-readable label printed next to the box. # Otherwise the checkbox name is used. # Returns: # A string containing a <input type="checkbox"> field ####
[docs]def checkbox(*_args): global _d [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [ name, checked, value_v, label, labelattributes, override, tabindex, *other, ] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ "NAME", ["CHECKED", "SELECTED", "ON"], "VALUE", "LABEL", "LABELATTRIBUTES", ["OVERRIDE", "FORCE"], "TABINDEX", ] ), *p, ), 7, ) other = perllib.Array(other) value_v = value_v if value_v is not None else "on" if not override and (self[".fieldnames"].get(_str(name)) or self.param(name) is not None): checked = ( self._checked(1) if len( list( filter( lambda _d: _pb(_str(_d) == _str(value_v)), perllib.make_list(self.param(name)), ) ) ) else "" ) else: checked = self._checked(checked) [the_label] = perllib.list_of_n(label if label is not None else name, 1) name = self._maybe_escapeHTML(name) value_v = self._maybe_escapeHTML(value_v, 1) the_label = self._maybe_escapeHTML(the_label) [other_v] = perllib.list_of_n( f"{perllib.LIST_SEPARATOR.join(map(_str,other))} " if other else "", 1 ) tabindex = self.element_tab(tabindex) self.register_parameter(name) return ( CGI.label( labelattributes, f'<input type="checkbox" name="{_bn(name)}" value="{_bn(value_v)}" {_bn(tabindex)}{_bn(checked)}{_bn(other_v)}/>{_bn(the_label)}', ) if CGI.XHTML_v else f'<input type="checkbox" name="{_bn(name)}" value="{_bn(value_v)}"{_bn(checked)}{_bn(other_v)}>{_bn(the_label)}' )
CGI.checkbox = lambda *_args, **_kwargs: perllib.tie_call(checkbox, _args, _kwargs) # Escape HTML #### Method: defaults # Create a "defaults" button. # Parameters: # $name -> (optional) Name for the button. # Returns: # A string containing a <input type="submit" name=".defaults"> tag # # Note: this button has a special meaning to the initialization script, # and tells it to ERASE the current query string so that your defaults # are used again! ####
[docs]def defaults(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [label, tabindex, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array([["NAME", "VALUE"], "TABINDEX"]), *p), 2 ) other = perllib.Array(other) label = self._maybe_escapeHTML(label, 1) label = label or "Defaults" [value_v] = perllib.list_of_n(f' value="{_bn(label)}"', 1) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) tabindex = self.element_tab(tabindex) return ( f'<input type="submit" name=".defaults" {_bn(tabindex)}{_bn(value_v)}{_bn(other_v)} />' if CGI.XHTML_v else f'<input type="submit" NAME=".defaults"{_bn(value_v)}{_bn(other_v)}>' )
CGI.defaults = lambda *_args, **_kwargs: perllib.tie_call(defaults, _args, _kwargs) #### Method: comment # Create an HTML <!-- comment --> # Parameters: a string #### Method: reset # Create a "reset" button. # Parameters: # $name -> (optional) Name for the button. # Returns: # A string containing a <input type="reset"> tag ####
[docs]def reset(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [label, value_v, tabindex, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["NAME", ["VALUE", "LABEL"], "TABINDEX"]), *p), 3 ) other = perllib.Array(other) label = self._maybe_escapeHTML(label) value_v = self._maybe_escapeHTML(value_v, 1) [name] = perllib.list_of_n(' name=".reset"', 1) if label is not None: name = f' name="{_bn(label)}"' value_v = value_v if value_v is not None else label [val] = perllib.list_of_n("", 1) if value_v is not None: val = f' value="{_bn(value_v)}"' [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) tabindex = self.element_tab(tabindex) return ( f'<input type="reset" {_bn(tabindex)}{_bn(name)}{_bn(val)}{_bn(other_v)} />' if CGI.XHTML_v else f'<input type="reset"{_bn(name)}{_bn(val)}{_bn(other_v)}>' )
CGI.reset = lambda *_args, **_kwargs: perllib.tie_call(reset, _args, _kwargs) #### Method: submit # Create a "submit query" button. # Parameters: # $name -> (optional) Name for the button. # $value -> (optional) Value of the button when selected (also doubles as label). # $label -> (optional) Label printed on the button(also doubles as the value). # Returns: # A string containing a <input type="submit"> tag ####
[docs]def submit(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [label, value_v, tabindex, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["NAME", ["VALUE", "LABEL"], "TABINDEX"]), *p), 3 ) other = perllib.Array(other) label = self._maybe_escapeHTML(label) value_v = self._maybe_escapeHTML(value_v, 1) name = "" if CGI.NOSTICKY_v else 'name=".submit" ' if label is not None: name = f'name="{_bn(label)}" ' value_v = value_v if value_v is not None else label val = "" if value_v is not None: val = f'value="{_bn(value_v)}" ' tabindex = self.element_tab(tabindex) [other_v] = perllib.list_of_n( f"{perllib.LIST_SEPARATOR.join(map(_str,other))} " if other else "", 1 ) return ( f'<input type="submit" {_bn(tabindex)}{name}{val}{_bn(other_v)}/>' if CGI.XHTML_v else f'<input type="submit" {name}{val}{_bn(other_v)}>' )
CGI.submit = lambda *_args, **_kwargs: perllib.tie_call(submit, _args, _kwargs) #### Method: button # Create a javascript button. # Parameters: # $name -> (optional) Name for the button. (-name) # $value -> (optional) Value of the button when selected (and visible name) (-value) # $onclick -> (optional) Text of the JavaScript to run when the button is # clicked. # Returns: # A string containing a <input type="button"> tag ####
[docs]def button(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [label, value_v, script, tabindex, *other] = perllib.list_of_at_least_n( rearrange( perllib.Array(["NAME", ["VALUE", "LABEL"], ["ONCLICK", "SCRIPT"], "TABINDEX"]), *p ), 4, ) other = perllib.Array(other) label = self._maybe_escapeHTML(label) value_v = self._maybe_escapeHTML(value_v, 1) script = self._maybe_escapeHTML(script) script = script or "" [name] = perllib.list_of_n("", 1) if label: name = f' name="{_bn(label)}"' value_v = value_v or label [val] = perllib.list_of_n("", 1) if value_v: val = f' value="{_bn(value_v)}"' if script: script = f' onclick="{_bn(script)}"' [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) tabindex = self.element_tab(tabindex) return ( f'<input type="button" {_bn(tabindex)}{_bn(name)}{_bn(val)}{_bn(script)}{_bn(other_v)} />' if CGI.XHTML_v else f'<input type="button"{_bn(name)}{_bn(val)}{_bn(script)}{_bn(other_v)}>' )
CGI.button = lambda *_args, **_kwargs: perllib.tie_call(button, _args, _kwargs) #### Method: textarea # Parameters: # $name -> Name of the text field # $default -> Optional default value of the field if not # already defined. # $rows -> Optional number of rows in text area # $columns -> Optional number of columns in text area # Returns: # A string containing a <textarea></textarea> tag #
[docs]def textarea(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [name, default, rows, cols, override, tabindex, *other] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ "NAME", ["DEFAULT", "VALUE"], "ROWS", ["COLS", "COLUMNS"], ["OVERRIDE", "FORCE"], "TABINDEX", ] ), *p, ), 6, ) other = perllib.Array(other) [current] = perllib.list_of_n( default if override else ( self.param(name, wantarray=True) if self.param(name, wantarray=True) is not None else default ), 1, ) name = self._maybe_escapeHTML(name) if name is not None else "" current = self._maybe_escapeHTML(current) if current is not None else "" [r_v] = perllib.list_of_n(f' rows="{_bn(rows)}"' if rows else "", 1) [c_v] = perllib.list_of_n(f' cols="{_bn(cols)}"' if cols else "", 1) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) tabindex = self.element_tab(tabindex) return f'<textarea name="{_bn(name)}" {_bn(tabindex)}{_bn(r_v)}{_bn(c_v)}{_bn(other_v)}>{_bn(current)}</textarea>'
CGI.textarea = lambda *_args, **_kwargs: perllib.tie_call(textarea, _args, _kwargs) #### Method: password # Create a "secret password" entry field # Parameters: # $name -> Name of the field # $default -> Optional default value of the field if not # already defined. # $size -> Optional width of field in characters. # $maxlength -> Optional maximum characters that can be entered. # Returns: # A string containing a <input type="password"> field #
[docs]def password_field(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self._textfield("password", *p)
CGI.password_field = lambda *_args, **_kwargs: perllib.tie_call(password_field, _args, _kwargs) #### Method: filefield # Parameters: # $name -> Name of the file upload field # $size -> Optional width of field in characaters. # $maxlength -> Optional maximum number of characters. # Returns: # A string containing a <input type="file"> field #
[docs]def filefield(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self._textfield("file", *p)
CGI.filefield = lambda *_args, **_kwargs: perllib.tie_call(filefield, _args, _kwargs) #### Method: textfield # Parameters: # $name -> Name of the text field # $default -> Optional default value of the field if not # already defined. # $size -> Optional width of field in characaters. # $maxlength -> Optional maximum number of characters. # Returns: # A string containing a <input type="text"> field #
[docs]def textfield(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self._textfield("text", *p)
CGI.textfield = lambda *_args, **_kwargs: perllib.tie_call(textfield, _args, _kwargs) def _textfield(*_args): [self, tag, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 2) p = perllib.Array(p) [name, default, size, maxlength, override, tabindex, *other] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ "NAME", ["DEFAULT", "VALUE", "VALUES"], "SIZE", "MAXLENGTH", ["OVERRIDE", "FORCE"], "TABINDEX", ] ), *p, ), 6, ) other = perllib.Array(other) current = ( default if override else (self.param(name) if self.param(name) is not None else default) ) current = self._maybe_escapeHTML(current, 1) if current is not None else "" name = self._maybe_escapeHTML(name) if name is not None else "" [s_v] = perllib.list_of_n(f' size="{_bn(size)}"' if size is not None else "", 1) [m] = perllib.list_of_n(f' maxlength="{_bn(maxlength)}"' if maxlength is not None else "", 1) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) # this entered at cristy's request to fix problems with file upload fields # and WebTV -- not sure it won't break stuff [value_v] = perllib.list_of_n(f'value="{_bn(current)}"' if _str(current) != "" else "", 1) tabindex = self.element_tab(tabindex) return ( f'<input type="{_bn(tag)}" name="{_bn(name)}" {_bn(tabindex)}{_bn(value_v)}{_bn(s_v)}{_bn(m)}{_bn(other_v)} />' if CGI.XHTML_v else f'<input type="{_bn(tag)}" name="{_bn(name)}" {_bn(value_v)}{_bn(s_v)}{_bn(m)}{_bn(other_v)}>' ) CGI._textfield = lambda *_args, **_kwargs: perllib.tie_call(_textfield, _args, _kwargs) #### Method: end_form # End a form # Note: This repeated below under the older name.
[docs]def end_form(*_args, wantarray=False): fields = perllib.Array() [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) if CGI.NOSTICKY_v: return ("</form>") if wantarray else "\n</form>" else: if fields := self.get_fields(): return ( ("<div>", fields, "</div>", "</form>") if wantarray else "<div>" + ("".join(map(_str, fields))) + "</div>\n</form>" ) else: return "</form>"
CGI.end_form = lambda *_args, **_kwargs: perllib.tie_call(end_form, _args, _kwargs) #### Method: end_multipart_form # end a multipart form
[docs]def end_multipart_form(*_args, wantarray=False): return end_form(_args, wantarray=False)
CGI.end_multipart_form = lambda *_args, **_kwargs: perllib.tie_call( end_multipart_form, _args, _kwargs ) #### Method: start_multipart_form
[docs]def start_multipart_form(*_args): action = None method = None other = perllib.Array() [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) if p.get(0) is not None and _str(p[0])[0:1] == "-": return self.start_form("-enctype", MULTIPART(*_args), *p) else: [method, action, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["METHOD", "ACTION"]), *p), 2 ) other = perllib.Array(other) return self.start_form(method, action, MULTIPART(*_args), *other)
CGI.start_multipart_form = lambda *_args, **_kwargs: perllib.tie_call( start_multipart_form, _args, _kwargs ) #### Method: start_form # Start a form # Parameters: # $method -> optional submission method to use (GET or POST) # $action -> optional URL of script to run # $enctype ->encoding to use (URL_ENCODED or MULTIPART)
[docs]def start_form(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [method, action, enctype, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["METHOD", "ACTION", "ENCTYPE"]), *p), 3 ) other = perllib.Array(other) method = self._maybe_escapeHTML(method or "post".lower()) if CGI.XHTML_v: enctype = self._maybe_escapeHTML(enctype or MULTIPART(*_args)) else: enctype = self._maybe_escapeHTML(enctype or URL_ENCODED(*_args)) if action is not None: action = self._maybe_escapeHTML(action) else: action = self._maybe_escapeHTML(self.request_uri() or self.self_url()) action = f'action="{_bn(action)}"' [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) self[".parametersToAdd"] = perllib.Hash() return f'<form method="{_bn(method)}" {_bn(action)} enctype="{_bn(enctype)}"{_bn(other_v)}>'
CGI.start_form = lambda *_args, **_kwargs: perllib.tie_call(start_form, _args, _kwargs)
[docs]def isindex(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [action, *other] = perllib.list_of_at_least_n(rearrange(perllib.Array(["ACTION"]), *p), 1) other = perllib.Array(other) if action: action = f' action="{_bn(action)}"' [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) return ( f"<isindex{_bn(action)}{_bn(other_v)} />" if CGI.XHTML_v else f"<isindex{_bn(action)}{_bn(other_v)}>" )
CGI.isindex = lambda *_args, **_kwargs: perllib.tie_call(isindex, _args, _kwargs) #### Method: redirect # Return a Location: style header # ####
[docs]def redirect(*_args): global _d [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [url_v, target, status, cookie_v, nph_v, *other] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ ["LOCATION", "URI", "URL"], "TARGET", "STATUS", ["COOKIE", "COOKIES", "SET-COOKIE"], "NPH", ] ), *p, ), 5, ) other = perllib.Array(other) if status is None: status = "302 Found" url_v = url_v or self.self_url() o = perllib.Array() for _d in other: _d = _str(_d).translate(str.maketrans("", "", '"')) o.extend(perllib.make_list(_str(_d).split("=", 2 - 1))) o[0:0] = ["-Status", status, "-Location", url_v, "-nph", nph_v] if target: o[0:0] = ["-Target", target] o[0:0] = ["-Type", ""] unescaped = perllib.Array() if cookie_v: unescaped[0:0] = ["-Cookie", cookie_v] return self.header(*(perllib.flatten(map(lambda _d: self.unescapeHTML(_d), o))), *unescaped)
CGI.redirect = lambda *_args, **_kwargs: perllib.tie_call(redirect, _args, _kwargs) #### Method: start_html # Canned HTML header # # Parameters: # $title -> (optional) The title for this HTML document (-title) # $author -> (optional) e-mail address of the author (-author) # $base -> (optional) if set to true, will enter the BASE address of this document # for resolving relative references (-base) # $xbase -> (optional) alternative base at some remote location (-xbase) # $target -> (optional) target window to load all links into (-target) # $script -> (option) Javascript code (-script) # $no_script -> (option) Javascript <noscript> tag (-noscript) # $meta -> (optional) Meta information tags # $head -> (optional) any other elements you'd like to incorporate into the <head> tag # (a scalar or array ref) # $style -> (optional) reference to an external style sheet # @other -> (optional) any other named parameters you'd like to incorporate into # the <body> tag. #### #### Method: cache # Control whether header() will produce the no-cache # Pragma directive. ####
[docs]def cache(*_args): [self, new_value] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) if not new_value: new_value = "" if _str(new_value) != "": self["cache"] = new_value return self.get("cache")
CGI.cache = lambda *_args, **_kwargs: perllib.tie_call(cache, _args, _kwargs) #### Method: multipart_final # Return a MIME boundary separator for server-push, end of all sections # # Contributed by Andrew Benham (adsb@bigfoot.com) ####
[docs]def multipart_final(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return ( _str(self.get("final_separator")) + "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." + _str(CGI.CRLF_v) )
CGI.multipart_final = lambda *_args, **_kwargs: perllib.tie_call(multipart_final, _args, _kwargs) #### Method: header # Return a Content-Type: style header # #### #### Method: multipart_end # Return a MIME boundary separator for server-push, end of section # # Many thanks to Ed Jordan <ed@fidalgo.net> for this # contribution ####
[docs]def multipart_end(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.get("separator")
CGI.multipart_end = lambda *_args, **_kwargs: perllib.tie_call(multipart_end, _args, _kwargs)
[docs]def multipart_init(*_args): global _d chrs = perllib.Array() [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [boundary, charset_v, *other] = perllib.list_of_at_least_n( rearrange_header(perllib.Array(["BOUNDARY", "CHARSET"]), *p), 2 ) other = perllib.Array(other) if not boundary: boundary = "------- =_" chrs = perllib.Array( [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ] ) for _d in range(1, 17 + 1): boundary = _str(boundary) + _str(chrs[perllib.int_(perllib.rand(len(chrs)))]) self["separator"] = f"{_bn(CGI.CRLF_v)}--{_bn(boundary)}{_bn(CGI.CRLF_v)}" self["final_separator"] = f"{_bn(CGI.CRLF_v)}--{_bn(boundary)}--{_bn(CGI.CRLF_v)}" CGI.type_v = SERVER_PUSH(boundary) return ( _str( self.header( "-nph", 0, "-type", CGI.type_v, "-charset", charset_v, *(perllib.flatten(map(lambda _d: _d.split("=", 2 - 1), other))), ) ) + "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." + _str(self.multipart_end()) )
CGI.multipart_init = lambda *_args, **_kwargs: perllib.tie_call(multipart_init, _args, _kwargs) #### Method: multipart_start # Return a Content-Type: style header for server-push, start of section # # Many thanks to Ed Jordan <ed@fidalgo.net> for this # contribution, updated by Andrew Benham (adsb@bigfoot.com) #### #### Method: autoescape # If you want to turn off the autoescaping features, # call this method with undef as the argument
[docs]def autoEscape(*_args): [self, escape_v] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) d = self.get("escape") self["escape"] = escape_v return d
CGI.autoEscape = lambda *_args, **_kwargs: perllib.tie_call(autoEscape, _args, _kwargs)
[docs]def Delete_all(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.delete_all(*p)
CGI.Delete_all = lambda *_args, **_kwargs: perllib.tie_call(Delete_all, _args, _kwargs)
[docs]def Delete(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.delete(*p)
CGI.Delete = lambda *_args, **_kwargs: perllib.tie_call(Delete, _args, _kwargs) #### Method: delete_all # Delete all parameters ####
[docs]def delete_all(*_args): [self] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 1) param_a = perllib.Array(self.param(wantarray=True)) return self.delete(*param_a)
CGI.delete_all = lambda *_args, **_kwargs: perllib.tie_call(delete_all, _args, _kwargs)
[docs]def append(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [name, value_v] = perllib.list_of_n( rearrange(perllib.Array(["NAME", ["VALUE", "VALUES"]]), *p), 2 ) values_ = perllib.Array( (value_v if perllib.ref_scalar(value_v) else value_v) if value_v is not None else perllib.Array() ) if values_: self.add_parameter(name) self["param"].get(_str(name)).extend(values_) return self.param(name)
CGI.append = lambda *_args, **_kwargs: perllib.tie_call(append, _args, _kwargs)
[docs]def readHeader(*_args, wantarray=False): global CRLF_v CGI.CRLF_v = perllib.init_global("CGI", "CRLF_v", None) try: _locals_stack.append(CGI.CRLF_v) [self] = perllib.list_of_n(_args, 1) end = None [ok] = perllib.list_of_n(0, 1) [bad] = perllib.list_of_n(0, 1) if _str(CGI.OS_v) == "VMS" or CGI.EBCDIC_v: [CGI.MultipartBuffer.CRLF_v] = perllib.list_of_n("\015\012", 1) _do_3729 = True while _do_3729: self.fillBuffer(CGI.MultipartBuffer.FILLUNIT_v) if ( end := _str(self.get("BUFFER")).find( f"{_bn(CGI.MultipartBuffer.CRLF_v)}{_bn(CGI.MultipartBuffer.CRLF_v)}" ) ) >= 0: ok = perllib.num(ok) + 1 if _str(self.get("BUFFER")) == "": ok = perllib.num(ok) + 1 if not ok and perllib.num(self.get("LENGTH")) <= 0: bad = perllib.num(bad) + 1 # this was a bad idea # $FILLUNIT *= 2 if length($self->{BUFFER}) >= $FILLUNIT; _do_3729 = not (ok or bad) if bad: return perllib.Array() if wantarray else None # EBCDIC NOTE: translate header into EBCDIC, but watch out for continuation lines! [header_v] = perllib.list_of_n(_str(self.get("BUFFER"))[0 : 0 + perllib.int_(end) + 2], 1) self["BUFFER"] = ( _str(self["BUFFER"])[:0] + _str(self["BUFFER"])[0 + perllib.int_(end) + 4 :] ) return_ = perllib.Hash() if CGI.EBCDIC_v: if CGI.MultipartBuffer._DEBUG_v: perllib.perl_print(f"untranslated header={_bn(header_v)}\n", file=sys.stderr) header_v = CGI.Util.ascii2ebcdic(header_v) if CGI.MultipartBuffer._DEBUG_v: perllib.perl_print(f"translated header={_bn(header_v)}\n", file=sys.stderr) # See RFC 2045 Appendix A and RFC 822 sections 3.4.8 # (Folding Long Header Fields), 3.4.3 (Comments) # and 3.4.5 (Quoted-Strings). token = "[-\w!\#$%&'*+.^_\`|{}~]" def _f3756(_m_): global _m _m = _m_ return _m.expand(r" ") header_v = re.sub( re.compile(rf"{_bn(CGI.MultipartBuffer.CRLF_v)}\s+"), _f3756, _str(header_v), count=0 ) # merge continuation lines for _m in re.finditer( re.compile(rf"({token}+):\s+([^{_bn(CGI.MultipartBuffer.CRLF_v)}]*)", re.M | re.X), _str(header_v), ): [field_name, field_value] = (_m.group(1), _m.group(2)) def _f3760(_m_): global _m _m = _m_ return _m.group(1).upper() field_name = re.sub( re.compile(r"\b(\w)"), _f3760, field_name, count=0 ) # canonicalize return_[field_name] = field_value return return_ finally: CGI.CRLF_v = _locals_stack.pop()
CGI.MultipartBuffer.readHeader = lambda *_args, **_kwargs: perllib.tie_call( readHeader, _args, _kwargs ) # -------------- really private subroutines ----------------- def _maybe_escapeHTML(*_args): _args = list(_args) # hack to work around earlier hacks if len(_args) == 1 and _str(_args[0]) == "CGI": _args.append(_args[0]) [self, toencode, newlinestoo] = perllib.list_of_n( CGI.self_or_default(*_args, wantarray=True), 3 ) if toencode is None: return None if perllib.ref_scalar(self) and not self.get("escape"): return toencode return self.escapeHTML(toencode, newlinestoo) CGI._maybe_escapeHTML = lambda *_args, **_kwargs: perllib.tie_call( _maybe_escapeHTML, _args, _kwargs ) #### Method: protocol # Return the protocol (http or https currently) ####
[docs]def protocol(*_args): _args = list(_args) try: _locals_stack.append(perllib.WARNING) [perllib.WARNING] = perllib.list_of_n(0, 1) self = _args.pop(0) if _args else None if _str(self.https()).upper() == "ON": return "https" if perllib.num(self.server_port()) == 443: return "https" prot = self.server_protocol() [protocol_v, version_v] = perllib.list_of_n(_str(prot).split("/"), 2) return f"{(_bn(protocol_v)).lower()}" finally: perllib.WARNING = _locals_stack.pop()
CGI.protocol = lambda *_args, **_kwargs: perllib.tie_call(protocol, _args, _kwargs)
[docs]def query_string(*_args): global _d, param_l, value_l [self] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 1) param_v = None value_v = None pairs = perllib.Array() for param_l in perllib.flatten([self.param(wantarray=True)]): [eparam] = perllib.list_of_n(escape(param_l), 1) for _i2941, value_l in enumerate( _s2941 := perllib.flatten([self.param(param_l, wantarray=True)]) ): value_l = escape(value_l) _s2941[_i2941] = value_l if value_l is None: continue pairs.append(f"{_bn(eparam)}={_bn(value_l)}") for _d in sorted(list(self[".fieldnames"].keys())): pairs.extend(perllib.make_list(".cgifields=" + _str(escape(f"{_bn(_d)}")))) return (";" if CGI.USE_PARAM_SEMICOLONS_v else "&").join(map(_str, pairs))
CGI.query_string = lambda *_args, **_kwargs: perllib.tie_call(query_string, _args, _kwargs)
[docs]def hidden(*_args, wantarray=False): global _d [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) # this is the one place where we departed from our standard # calling scheme, so we have to special-case (darn) result = perllib.Array() value_a = perllib.Array() [name, default, override, *other] = perllib.list_of_at_least_n( rearrange( perllib.Array(["NAME", ["DEFAULT", "VALUE", "VALUES"], ["OVERRIDE", "FORCE"]]), *p ), 3, ) other = perllib.Array(other) do_override = 0 if perllib.ref_scalar(p[0]) or _str(p[0])[0:1] == "-": value_a = perllib.Array(default if perllib.ref_scalar(default) else default) do_override = override else: for _d in (default, override, other): if _d is not None: value_a.append(_d) other = perllib.Array() # use previous values if override is not set prev_a = perllib.Array(self.param(name, wantarray=True)) if not do_override and prev_a: value_a = prev_a.copy() name = self._maybe_escapeHTML(name) for _i2638, _d in enumerate(value_a): _d = self._maybe_escapeHTML(_d, 1) if _d is not None else "" value_a[_i2638] = _d result.extend( perllib.make_list( f'<input type="hidden" name="{_bn(name)}" value="{_bn(_d)}" {perllib.LIST_SEPARATOR.join(map(_str,other))} />' if CGI.XHTML_v else f'<input type="hidden" name="{_bn(name)}" value="{_bn(_d)}" {perllib.LIST_SEPARATOR.join(map(_str,other))}>' ) ) return result if wantarray else "".join(map(_str, result))
CGI.hidden = lambda *_args, **_kwargs: perllib.tie_call(hidden, _args, _kwargs)
[docs]def get_fields(*_args): [self] = perllib.list_of_n(_args, 1) return CGI.hidden( self, "-name", ".cgifields", "-values", (sorted(self[".parametersToAdd"].keys())), "-override", 1, )
CGI.get_fields = lambda *_args, **_kwargs: perllib.tie_call(get_fields, _args, _kwargs) def _box_group(*_args, wantarray=False): _args = list(_args) global _d self = _args.pop(0) if _args else None box_type = _args.pop(0) if _args else None [ name, values_v, defaults_v, linebreak, labels, labelattributes, attributes, rows, columns, rowheaders, colheaders, override, nolabels, tabindex, disabled, *other, ] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ "NAME", ["VALUES", "VALUE"], ["DEFAULT", "DEFAULTS"], "LINEBREAK", "LABELS", "LABELATTRIBUTES", "ATTRIBUTES", "ROWS", ["COLUMNS", "COLS"], ["ROWHEADERS", "ROWHEADER"], ["COLHEADERS", "COLHEADER"], ["OVERRIDE", "FORCE"], "NOLABELS", "TABINDEX", "DISABLED", ] ), *_args, ), 15, ) other = perllib.Array(other) result_v = None checked = None elements = perllib.Array() values_ = perllib.Array() values_ = perllib.Array( ( self._set_values_and_labels(values_v, labels, name), (labels := perllib.fetch_out_parameter(2)), )[0] ) checked_h = perllib.Hash(self.previous_or_default(name, defaults_v, override)) # If no check array is specified, check the first by default if _str(box_type) == "radio" and not checked_h: checked_h[_s0] = perllib.num(checked_h.get(_s0 := _str(values_[0]))) + 1 name = self._maybe_escapeHTML(name) tabs = perllib.Hash() if CGI.TABINDEX_v and tabindex: if not perllib.ref_scalar(tabindex): self.element_tab(tabindex) elif perllib.refs(tabindex) == "ARRAY": tabs = perllib.Hash( perllib.list_to_hash( perllib.flatten( map(lambda _d: [_d, self.element_tab()], perllib.make_list(tabindex)) ) ) ) elif perllib.refs(tabindex) == "HASH": tabs = tabindex if not tabs: tabs = perllib.Hash( perllib.list_to_hash( perllib.flatten(map(lambda _d: [_d, self.element_tab()], values_)) ) ) other_v = f"{perllib.LIST_SEPARATOR.join(map(_str,other))} " if other else "" radio_checked = 0 # for disabling groups of radio/checkbox buttons disabled_h = perllib.Hash() for _d in disabled: disabled_h[_str(_d)] = 1 for _i2376, _d in enumerate(values_): disable = "" if disabled_h.get(_str(_d)): disable = "disabled='1'" checkit = self._checked( (checked_h.get(_d) and not ((radio_checked := radio_checked + 1) - 1)) if box_type == "radio" else checked_h.get(_d) ) break_ = "" if linebreak: break_ = "<br />" if CGI.XHTML_v else "<br>" else: break_ = "" [label] = perllib.list_of_n("", 1) if not (nolabels is not None and nolabels): label = _d if labels is not None and labels.get(_str(_d)) is not None: label = labels.get(_str(_d)) label = self._maybe_escapeHTML(label, 1) if disabled_h.get(_str(_d)): label = f'<span style="color:gray">{_bn(label)}</span>' attribs_v = self._set_attributes(_d, attributes) tab = tabs.get(_str(_d)) _d = self._maybe_escapeHTML(_d) values_[_i2376] = _d if CGI.XHTML_v: elements.extend( perllib.make_list( _str( CGI.label( labelattributes, f'<input type="{_bn(box_type)}" name="{_bn(name)}" value="{_bn(_d)}" {_bn(checkit)}{other_v}{_bn(tab)}{_bn(attribs_v)}{disable}/>{_bn(label)}', ) ) + break_ ) ) else: elements.append( f"""<input type="{_bn(box_type)}" name="{_bn(name)}" value="{_bn(_d)}" {_bn(checkit)}{other_v}{_bn(tab)}{_bn(attribs_v)}{disable}>{_bn(label)}{break_}""" ) self.register_parameter(name) if not (columns is not None or rows is not None): return elements if wantarray else f"{perllib.LIST_SEPARATOR.join(map(_str,elements))}" return _tableize(rows, columns, rowheaders, colheaders, *elements) CGI._box_group = lambda *_args, **_kwargs: perllib.tie_call(_box_group, _args, _kwargs) # unescape HTML -- used internally
[docs]def unescapeHTML(*_args): _args = list(_args) import HTML.Entities as _HTML_Entities # hack to work around earlier hacks if len(_args) == 1 and _str(_args[0]) == "CGI": _args.append(_args[0]) [self, string] = perllib.list_of_n(CGI.self_or_default(*_args, wantarray=True), 2) if string is None: return None return (HTML.Entities.decode_entities(string), (string := perllib.fetch_out_parameter(0)))[0]
CGI.unescapeHTML = lambda *_args, **_kwargs: perllib.tie_call(unescapeHTML, _args, _kwargs)
[docs]def escapeHTML(*_args): _args = list(_args) import HTML.Entities as _HTML_Entities # hack to work around earlier hacks if len(_args) == 1 and _str(_args[0]) == "CGI": _args.append(_args[0]) [self, toencode, newlinestoo] = perllib.list_of_n( CGI.self_or_default(*_args, wantarray=True), 3 ) if toencode is None: return None encode_entities_v = CGI.ENCODE_ENTITIES_v if encode_entities_v and newlinestoo: encode_entities_v = _str(encode_entities_v) + "\012\015" return ( HTML.Entities.encode_entities(toencode, encode_entities_v), (toencode := perllib.fetch_out_parameter(0)), )[0]
CGI.escapeHTML = lambda *_args, **_kwargs: perllib.tie_call(escapeHTML, _args, _kwargs) ### Method: _style # internal method for generating a CSS style section #### def _style(*_args): global _d, src_l alternate = None c = perllib.Array() code = None foo = None other = perllib.Array() src = None stype = None v = perllib.Array() verbatim = None [self, style] = perllib.list_of_n(_args, 2) result = perllib.Array() type_v = "text/css" rel = "stylesheet" cdata_start = "\n<!--/* <![CDATA[ */" if CGI.XHTML_v else "\n<!-- " cdata_end = "\n/* ]]> */-->\n" if CGI.XHTML_v else " -->\n" s = perllib.Array(style if perllib.refs(style) == "ARRAY" else style) other_v = "" for s_l in s: if perllib.ref_scalar(s_l): [src, code, verbatim, stype, alternate, foo, *other] = perllib.list_of_at_least_n( rearrange( "SRC CODE VERBATIM TYPE ALTERNATE FOO".split(), ("-foo", "bar", s_l if perllib.refs(s_l) == "ARRAY" else s_l), ), 6, ) other = perllib.Array(other) type_v = stype if stype is not None else "text/css" rel = "alternate stylesheet" if alternate else "stylesheet" if other: other_v = f"{perllib.LIST_SEPARATOR.join(map(_str,other))}" if ( perllib.refs(src) == "ARRAY" ): # Check to see if the $src variable is an array reference # If it is, push a LINK tag for each one for src_l in src_l: if src_l: result.extend( perllib.make_list( f'<link rel="{rel}" type="{_bn(type_v)}" href="{_bn(src_l)}" {other_v}/>' if CGI.XHTML_v else f'<link rel="{rel}" type="{_bn(type_v)}" href="{_bn(src_l)}"{other_v}>' ) ) else: # Otherwise, push the single -src, if it exists. if src: result.extend( perllib.make_list( f'<link rel="{rel}" type="{_bn(type_v)}" href="{_bn(src)}" {other_v}/>' if CGI.XHTML_v else f'<link rel="{rel}" type="{_bn(type_v)}" href="{_bn(src)}"{other_v}>' ) ) if verbatim: v = perllib.Array(verbatim if perllib.refs(verbatim) == "ARRAY" else verbatim) for _d in v: result.append(f"""<style type="text/css">\n{_bn(_d)}\n</style>""") if code: c = perllib.Array(code if perllib.refs(code) == "ARRAY" else code) for _d in c: result.extend( perllib.make_list( CGI.style({"type": type_v}, f"{cdata_start}\n{_bn(_d)}\n{cdata_end}") ) ) else: src = s_l result.extend( perllib.make_list( f'<link rel="{rel}" type="{_bn(type_v)}" href="{_bn(src)}" {other_v}/>' if CGI.XHTML_v else f'<link rel="{rel}" type="{_bn(type_v)}" href="{_bn(src)}"{other_v}>' ) ) return result CGI._style = lambda *_args, **_kwargs: perllib.tie_call(_style, _args, _kwargs)
[docs]def start_html(*_args): global _d href = None meta_bits = None t = "" [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [ title, author, base, xbase, script, noscript, target, meta, head, style, dtd, lang, encoding, declare_xml, *other, ] = perllib.list_of_at_least_n( rearrange( perllib.Array( [ "TITLE", "AUTHOR", "BASE", "XBASE", "SCRIPT", "NOSCRIPT", "TARGET", "META", "HEAD", "STYLE", "DTD", "LANG", "ENCODING", "DECLARE_XML", ] ), *p, ), 14, ) other = perllib.Array(other) self.element_id(0) self.element_tab(0) if encoding is None: encoding = _str(self.charset()).lower() # Need to sort out the DTD before it's okay to call escapeHTML(). result = perllib.Array() xml_dtd = 0 if dtd: if perllib.ref_scalar(dtd) is not None and (perllib.refs(dtd) == "ARRAY"): if not ((re.search(r"^-//", _str(dtd[0])))): dtd = CGI.DEFAULT_DTD_v else: if not ((re.search(r"^-//", _str(dtd)))): dtd = CGI.DEFAULT_DTD_v else: dtd = CGI._XHTML_DTD_v if CGI.XHTML_v else CGI.DEFAULT_DTD_v if perllib.refs(dtd) == "ARRAY" and (re.search(re.compile(r"\bXHTML\b", re.I), _str(dtd[0]))): xml_dtd += 1 if perllib.ref_scalar(dtd) == "" and (re.search(re.compile(r"\bXHTML\b", re.I), _str(dtd))): xml_dtd += 1 if xml_dtd and declare_xml: result.append(f'<?xml version="1.0" encoding="{_bn(encoding)}"?>') if perllib.ref_scalar(dtd) and perllib.refs(dtd) == "ARRAY": result.append(f"""<!DOCTYPE html\n\tPUBLIC "{_bn(dtd)[0]}"\n\t "{_bn(dtd)[1]}">""") CGI.DTD_PUBLIC_IDENTIFIER_v = dtd[0] else: result.append(f"""<!DOCTYPE html\n\tPUBLIC "{_bn(dtd)}">""") CGI.DTD_PUBLIC_IDENTIFIER_v = dtd # Now that we know whether we're using the HTML 3.2 DTD or not, it's okay to # call escapeHTML(). Strangely enough, the title needs to be escaped as # HTML while the author needs to be escaped as a URL. title = self._maybe_escapeHTML(title or "Untitled Document") author = self.escape(author) if _m := re.search( re.compile(r"[^X]HTML (2\.0|3\.2|4\.01?)", re.I), _str(CGI.DTD_PUBLIC_IDENTIFIER_v) ): if lang is None: lang = "" CGI.XHTML_v = 0 else: if lang is None: lang = "en-US" lang_bits = f' lang="{_bn(lang)}" xml:lang="{_bn(lang)}"' if _str(lang) != "" else "" if CGI.XHTML_v and encoding and not declare_xml: meta_bits = ( f'<meta http-equiv="Content-Type" content="text/html; charset={_bn(encoding)}" />' ) result.extend( perllib.make_list( f"""<html xmlns="http://www.w3.org/1999/xhtml"{lang_bits}>\n<head>\n<title>{_bn(title)}</title>""" if CGI.XHTML_v else (f'<html lang="{_bn(lang)}">' if lang else "<html>") + f"<head><title>{_bn(title)}</title>" ) ) if author is not None: result.extend( perllib.make_list( f'<link rev="made" href="mailto:{_bn(author)}" />' if CGI.XHTML_v else f'<link rev="made" href="mailto:{_bn(author)}">' ) ) if base or xbase or target: href = xbase or self.url("-path", 1) t = f' target="{_bn(target)}"' if target else "" result.extend( perllib.make_list( f'<base href="{_bn(href)}"{t} />' if CGI.XHTML_v else f'<base href="{_bn(href)}"{t}>' ) ) if meta and perllib.ref_scalar(meta) and (perllib.refs(meta) == "HASH"): for _d in sorted(list((meta if meta is not None else perllib.Hash()).keys())): result.extend( perllib.make_list( f"""<meta name="{_bn(_d)}" content="{_bn(meta).get(_str(_d),'')}" />""" if CGI.XHTML_v else f"""<meta name="{_bn(_d)}" content="{_bn(meta).get(_str(_d),'')}">""" ) ) meta_bits_set = 0 if head: if perllib.ref_scalar(head): result.append(head) if list( filter(lambda _d: r"""http-equiv=["']Content-Type""" "i", perllib.make_list(head)) ): meta_bits_set = 1 else: result.append(head) if re.search(re.compile(r"""http-equiv=["']Content-Type""", re.I), _str(head)): meta_bits_set = 1 # handle the infrequently-used -style and -script parameters if style is not None: result.extend(perllib.make_list(self._style(style))) if script is not None: result.extend(perllib.make_list(self._script(script))) if meta_bits is not None and not meta_bits_set: result.append(meta_bits) # handle -noscript parameter if noscript: result.append( f"""<noscript> {_bn(noscript)} </noscript> """ ) [other_v] = perllib.list_of_n( f" {perllib.LIST_SEPARATOR.join(map(_str,other))}" if other else "", 1 ) result.append(f"</head>\n<body{_bn(other_v)}>\n") return "\n".join(map(_str, result))
CGI.start_html = lambda *_args, **_kwargs: perllib.tie_call(start_html, _args, _kwargs)
[docs]def multipart_start(*_args): global CRLF_v, _d header_a = perllib.Array() [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [type_v, charset_v, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["TYPE", "CHARSET"]), *p), 2 ) other = perllib.Array(other) type_v = type_v or "text/html" if charset_v: header_a.append(f"Content-Type: {_bn(type_v)}; charset={_bn(charset_v)}") else: header_a.append(f"Content-Type: {_bn(type_v)}") # rearrange() was designed for the HTML portion, so we # need to fix it up a little. for _i1503, _d in enumerate(other): # Don't use \s because of perl bug 21951 [CGI.header_v, CGI.value_v] = perllib.list_of_n( ( (_m := re.search(r"([^ \r\n\t=]+)=\"?(.+?)\"?$", _str(_d))), _m.groups() if _m else [], )[1], 2, ) if not _m: continue def _f1506(_m_): global _m _m = _m_ nonlocal self return _m.group(1) + _m.group(2).lower() + ": " + _str(self.unescapeHTML(CGI.value_v)) other[_i1503] = _d _d = re.sub(re.compile(r"^(\w)(.*)"), _f1506, _str(CGI.header_v), count=1) other[_i1503] = _d header_a.extend(other) header_v = (_str(CGI.CRLF_v)).join( map(_str, header_a) ) + f"{_bn(CGI.CRLF_v)}{_bn(CGI.CRLF_v)}" return header_v
CGI.multipart_start = lambda *_args, **_kwargs: perllib.tie_call(multipart_start, _args, _kwargs) #### Method: save # Write values out to a filehandle in such a way that they can # be reinitialized by the filehandle form of the new() method ####
[docs]def save(*_args): global _d, param_l, value_l try: _locals_stack.append(perllib.OUTPUT_FIELD_SEPARATOR) _locals_stack.append(perllib.OUTPUT_RECORD_SEPARATOR) [self, filehandle] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) filehandle = to_filehandle(filehandle) param_v = None [perllib.OUTPUT_FIELD_SEPARATOR] = perllib.list_of_n( "", 1 ) # set print field separator back to a sane value [perllib.OUTPUT_RECORD_SEPARATOR] = perllib.list_of_n( "", 1 ) # set output line separator to a sane value for param_l in perllib.flatten([self.param(wantarray=True)]): [escaped_param] = perllib.list_of_n(escape(param_l), 1) value_v = None for value_l in perllib.flatten([self.param(param_l, wantarray=True)]): if len(_str(escaped_param)) or len(_str(value_l)): perllib.perl_print( f"{_bn(escaped_param)}=", escape(f"{_bn(value_l)}"), "", file=filehandle ) for _d in sorted(list(self[".fieldnames"].keys())): perllib.perl_print(".cgifields=", escape(f"{_bn(_d)}"), "", file=filehandle) return perllib.perl_print("=", file=filehandle) # end of record finally: perllib.OUTPUT_RECORD_SEPARATOR = _locals_stack.pop() perllib.OUTPUT_FIELD_SEPARATOR = _locals_stack.pop()
CGI.save = lambda *_args, **_kwargs: perllib.tie_call(save, _args, _kwargs) #### Method: save_parameters # An alias for save() that is a better name for exportation. # Only intended to be used with the function (non-OO) interface. ####
[docs]def save_parameters(*_args): _args = list(_args) fh = _args.pop(0) if _args else None return save(to_filehandle(fh))
CGI.save_parameters = lambda *_args, **_kwargs: perllib.tie_call(save_parameters, _args, _kwargs) #### Method: Dump # Returns a string in which all the known parameter/value # pairs are represented as nested lists, mainly for the purposes # of debugging. ####
[docs]def Dump(*_args): global param_l, value_l [self] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 1) param_v = None value_v = None result = perllib.Array() if not self.param(): return "<ul></ul>" result.append("<ul>") for param_l in perllib.flatten([self.param(wantarray=True)]): [name] = perllib.list_of_n(self._maybe_escapeHTML(param_l), 1) result.append(f"<li><strong>{_bn(name)}</strong></li>") result.append("<ul>") for _i1395, value_l in enumerate( _s1395 := perllib.flatten([self.param(param_l, wantarray=True)]) ): value_l = self._maybe_escapeHTML(value_l) _s1395[_i1395] = value_l value_l = re.sub(re.compile(r"\n"), r"<br />\n", _str(value_l), count=0) _s1395[_i1395] = value_l result.append(f"<li>{_bn(value_l)}</li>") result.append("</ul>") result.append("</ul>") return "\n".join(map(_str, result))
CGI.Dump = lambda *_args, **_kwargs: perllib.tie_call(Dump, _args, _kwargs) #### Method as_string # # synonym for "dump" ####
[docs]def as_string(*_args): return Dump(*_args)
CGI.as_string = lambda *_args, **_kwargs: perllib.tie_call(as_string, _args, _kwargs) CGI.header = lambda *_args, **_kwargs: perllib.tie_call(header, _args, _kwargs)
[docs]def url_param(*_args, wantarray=False): _args = list(_args) global _d keywords_a = perllib.Array() pairs = perllib.Array() param_v = None value_v = None [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) name = p.pop(0) if p else None if not ("QUERY_STRING" in os.environ): return None if not (".url_param" in self): self[".url_param"] = perllib.Hash() # empty hash if re.search(r"=", _str(os.environ.get("QUERY_STRING"))): pairs = perllib.Array(perllib.split(r"[&;]", _str(os.environ.get("QUERY_STRING")))) param_v = value_v = None for _d in pairs: [param_v, value_v] = perllib.list_of_n(_str(_d).split("=", 2 - 1), 2) if param_v is None: continue param_v = unescape(param_v) value_v = unescape(value_v) self[".url_param"].get(_str(param_v)).append(value_v) else: keywords_a = perllib.Array(self.parse_keywordlist(os.environ.get("QUERY_STRING"))) if keywords_a: self[".url_param"]["keywords"] = keywords_a if name is None: return self[".url_param"].keys() if not (self[".url_param"].get(_str(name))): return perllib.Array() if wantarray else None return self[".url_param"].get(_str(name)) if wantarray else self[".url_param"][_str(name)][0]
CGI.url_param = lambda *_args, **_kwargs: perllib.tie_call(url_param, _args, _kwargs) # Read data from a file handle
[docs]def read_from_client(*_args): perllib.init_out_parameters(_args, 1) # refs: 1 try: _locals_stack.append(perllib.WARNING) [self, buff, len_, offset] = perllib.list_of_n(_args, 4) perllib.WARNING = 0 # prevent a warning return ( (perllib.method_call(self.r(), "read", buff, len_, offset)) if CGI.MOD_PERL_v else ( ( perllib.store_out_parameter( None, 1, ( buff := ( _s := perllib.read( sys.stdin, buff, perllib.int_(len_), perllib.int_(offset), need_len=True, ) )[0] ), ) ), _s[1], )[1] ) finally: perllib.WARNING = _locals_stack.pop()
CGI.read_from_client = lambda *_args, **_kwargs: perllib.tie_call( read_from_client, _args, _kwargs ) #### Method: delete # Deletes the named parameter entirely. ####
[docs]def add_parameter(*_args): [self, param_v] = perllib.list_of_n(_args, 2) if param_v is None: return if not (self["param"].get(_str(param_v)) is not None): return self.get(".parameters").append(param_v)
CGI.add_parameter = lambda *_args, **_kwargs: perllib.tie_call(add_parameter, _args, _kwargs)
[docs]def parse_params(*_args): global _d [self, tosplit] = perllib.list_of_n(_args, 2) pairs = perllib.Array(perllib.split(r"[&;]", _str(tosplit))) param_v = value_v = None for _d in pairs: [param_v, value_v] = perllib.list_of_n(_str(_d).split("=", 2 - 1), 2) if param_v is None: continue if CGI.NO_UNDEF_PARAMS_v and value_v is None: continue if value_v is None: value_v = "" param_v = unescape(param_v) value_v = unescape(value_v) self.add_parameter(param_v) self["param"].get(_str(param_v)).append(value_v)
CGI.parse_params = lambda *_args, **_kwargs: perllib.tie_call(parse_params, _args, _kwargs) ######################################## # THESE METHODS ARE MORE OR LESS PRIVATE # GO TO THE __DATA__ SECTION TO SEE MORE # PUBLIC METHODS ######################################## # Initialize the query object from the environment. # If a parameter list is found, this object will be set # to a hash in which parameter names are keys # and the values are stored as lists # If a keyword list is found, this method creates a bogus # parameter list with the single parameter 'keywords'.
[docs]def init(*_args): _args = list(_args) global _d boundary = None cmdline_ret = perllib.Hash() line = None param_v = None postOrPut = "" start = "" val = None value_v = None try: _locals_stack.append(perllib.INPUT_RECORD_SEPARATOR) self = _args.pop(0) if _args else None [query_string_v, meth, content_length, fh, *lines_a] = perllib.list_of_at_least_n( ("", "", "", ""), 4 ) lines_a = perllib.Array(lines_a) is_xforms = 0 initializer_v = _args.pop(0) if _args else None # for backward compatibility [perllib.INPUT_RECORD_SEPARATOR] = perllib.list_of_n("\n", 1) # set autoescaping on by default self["escape"] = 1 # if we get called more than once, we want to initialize # ourselves from the original query (which may be gone # if it was read from STDIN originally.) if CGI.QUERY_PARAM_a and initializer_v is None: for name_l in CGI.QUERY_PARAM_a: val = CGI.QUERY_PARAM_h.get(_str(name_l)) # always an arrayref; self.param("-name", name_l, "-value", val) if val is not None and perllib.refs(val) == "ARRAY": for fh_l in list( filter( lambda _d: _d is not None and perllib.ref_scalar(_d) and perllib.fileno(_d) is not None, perllib.make_list(val), ) ): perllib.seek(fh_l, 0, 0) # reset the filehandle. self.charset(CGI.QUERY_CHARSET_v) self[".fieldnames"] = CGI.QUERY_FIELDNAMES_h.copy() self[".tmpfiles"] = CGI.QUERY_TMPFILES_h.copy() return if os.environ.get("REQUEST_METHOD") is not None: meth = os.environ.get("REQUEST_METHOD") content_length = ( os.environ.get("CONTENT_LENGTH") if os.environ.get("CONTENT_LENGTH") is not None else 0 ) if initializer_v: fh = to_filehandle(initializer_v) # set charset to the safe ISO-8859-1 self.charset("ISO-8859-1") # METHOD for _ in range(1): try: # avoid unreasonably large postings if (perllib.num(CGI.POST_MAX_v) > 0) and ( perllib.num(content_length) > perllib.num(CGI.POST_MAX_v) ): # discard the post, unread self.cgi_error("413 Request entity too large") break # Process multipart postings, but only if the initializer is # not defined. if ( _str(meth) == "POST" and os.environ.get("CONTENT_TYPE") is not None and (re.search(r"^multipart/form-data", _str(os.environ.get("CONTENT_TYPE")))) and initializer_v is None ): [boundary] = perllib.list_of_n( ( _m := re.search( r"boundary=\"?([^\";,]+)\"?", _str(os.environ.get("CONTENT_TYPE")) ), _m.groups() if _m else [], )[1], 1, ) self.read_multipart(boundary, content_length) if CGI.APPEND_QUERY_STRING_v: # Some people want to have their cake and eat it too! # Set $APPEND_QUERY_STRING = 1 to have the contents of the query string # APPENDED to the POST data. if os.environ.get("QUERY_STRING") is not None: query_string_v = _str(query_string_v) + ( ("&" if len(_str(query_string_v)) else "") + _str(os.environ.get("QUERY_STRING")) ) break # Process XForms postings. We know that we have XForms in the # following cases: # method eq 'POST' && content-type eq 'application/xml' # method eq 'POST' && content-type =~ /multipart\/related.+start=/ # There are more cases, actually, but for now, we don't support other # methods for XForm posts. # In a XForm POST, the QUERY_STRING is parsed normally. # If the content-type is 'application/xml', we just set the param # XForms:Model (referring to the xml syntax) param containing the # unparsed XML data. # In the case of multipart/related we set XForms:Model as above, but # the other parts are available as uploads with the Content-ID as the # the key. # See the URL below for XForms specs on this issue. # http://www.w3.org/TR/2006/REC-xforms-20060314/slice11.html#submit-options if _str(meth) == "POST" and os.environ.get("CONTENT_TYPE") is not None: if _str(os.environ.get("CONTENT_TYPE")) == "application/xml": [param_v] = perllib.list_of_n("XForms:Model", 1) [value_v] = perllib.list_of_n("", 1) self.add_parameter(param_v) if perllib.num(content_length) > 0: ( self.read_from_client(value_v, content_length, 0), (value_v := perllib.fetch_out_parameter(1)), )[0] self["param"].get(_str(param_v)).append(value_v) is_xforms = 1 elif _m := re.search( r"multipart/related.+boundary=\"?([^\";,]+)\"?.+start=\"?<?([^\">]+)>?\"?", _str(os.environ.get("CONTENT_TYPE")), ): [boundary, start] = (_m.group(1), _m.group(2)) [param_v] = perllib.list_of_n("XForms:Model", 1) self.add_parameter(param_v) [value_v] = perllib.list_of_n( self.read_multipart_related(start, boundary, content_length, 0), 1 ) self["param"].get(_str(param_v)).append(value_v) query_string_v = self._get_query_string_from_env() is_xforms = 1 # If initializer is defined, then read parameters # from it. if not is_xforms and initializer_v is not None: if perllib.isa(initializer_v, "CGI"): query_string_v = initializer_v.query_string() break if ( perllib.ref_scalar(initializer_v) and perllib.refs(initializer_v) == "HASH" ): for _d in sorted( list( ( initializer_v if initializer_v is not None else perllib.Hash() ).keys() ) ): self.param("-name", _d, "-value", initializer_v.get(_d)) break if fh is not None and (_str(fh) != ""): while line := perllib.readline_full(fh): line = line.rstrip("\n") if re.search(r"^=$", _str(line)): break lines_a.append(line) # massage back into standard format if re.search(r"=", f"{perllib.LIST_SEPARATOR.join(map(_str,lines_a))}"): query_string_v = "&".join(map(_str, lines_a)) else: query_string_v = "+".join(map(_str, lines_a)) break # last chance -- treat it as a string if perllib.refs(initializer_v) == "SCALAR": initializer_v = initializer_v query_string_v = initializer_v break # If method is GET, HEAD or DELETE, fetch the query from # the environment. if is_xforms or (_m := re.search(r"^(GET|HEAD|DELETE)$", _str(meth))): query_string_v = self._get_query_string_from_env() if is_xforms: self.param(meth + "DATA", self.param("XForms:Model", wantarray=True)) break if _str(meth) == "POST" or _str(meth) == "PUT" or _str(meth) == "PATCH": if perllib.num(content_length) > 0: if ( (CGI.PUTDATA_UPLOAD_v or self.get(".upload_hook")) and not is_xforms and ( _str(meth) == "POST" or _str(meth) == "PUT" or _str(meth) == "PATCH" ) and os.environ.get("CONTENT_TYPE") is not None and not ( re.search( r"^application/x-www-form-urlencoded", _str(os.environ.get("CONTENT_TYPE")), ) ) and not ( re.search( r"^multipart/form-data", _str(os.environ.get("CONTENT_TYPE")) ) ) ): postOrPut = _str(meth) + "DATA" # POSTDATA/PUTDATA self.read_postdata_putdata( postOrPut, content_length, os.environ.get("CONTENT_TYPE") ) meth = "" # to skip xform testing query_string_v = None else: ( self.read_from_client(query_string_v, content_length, 0), (query_string_v := perllib.fetch_out_parameter(1)), )[0] if CGI.APPEND_QUERY_STRING_v: # Some people want to have their cake and eat it too! # Set $APPEND_QUERY_STRING = 1 to have the contents of the query string # APPENDED to the POST data. if os.environ.get("QUERY_STRING") is not None: query_string_v = _str(query_string_v) + ( ("&" if len(_str(query_string_v)) else "") + _str(os.environ.get("QUERY_STRING")) ) break # If $meth is not of GET, POST, PUT or HEAD, assume we're # being debugged offline. # Check the command line and then the standard input for data. # We use the shellwords package in order to behave the way that # UN*X programmers expect. if CGI.DEBUG_v: cmdline_ret = read_from_cmdline() query_string_v = cmdline_ret.get("query_string") if cmdline_ret.get("subpath") is not None: self.path_info(cmdline_ret.get("subpath")) except LoopControl_METHOD as _l: if _l.args[0] == "break": break continue # YL: Begin Change for XML handler 10/19/2001 if ( not is_xforms and (_str(meth) == "POST" or _str(meth) == "PUT" or _str(meth) == "PATCH") and os.environ.get("CONTENT_TYPE") is not None and not ( re.search( r"^application/x-www-form-urlencoded", _str(os.environ.get("CONTENT_TYPE")) ) ) and not (re.search(r"^multipart/form-data", _str(os.environ.get("CONTENT_TYPE")))) ): [param_v] = perllib.list_of_n(_str(meth) + "DATA", 1) self.add_parameter(param_v) self["param"].get(_str(param_v)).append(query_string_v) query_string_v = None # YL: End Change for XML handler 10/19/2001 # We now have the query string in hand. We do slightly # different things for keyword lists and parameter lists. if query_string_v is not None and len(_str(query_string_v)): if re.search(r"[&=;]", _str(query_string_v)): self.parse_params(query_string_v) else: self.add_parameter("keywords") self["param"]["keywords"] = perllib.Array( [self.parse_keywordlist(query_string_v)] ) # Special case. Erase everything if there is a field named # .defaults. if self.param(".defaults"): self.delete_all() # hash containing our defined fieldnames self[".fieldnames"] = perllib.Hash() for _d in perllib.flatten([self.param(".cgifields", wantarray=True)]): self[".fieldnames"][_s0] = perllib.num(self[".fieldnames"].get(_s0 := _str(_d))) + 1 # Clear out our default submission button flag if present self.delete(".submit") self.delete(".cgifields") if initializer_v is None: return self.save_request() finally: perllib.INPUT_RECORD_SEPARATOR = _locals_stack.pop()
CGI.init = lambda *_args, **_kwargs: perllib.tie_call(init, _args, _kwargs)
[docs]def self_or_CGI(*_args): try: _locals_stack.append(perllib.WARNING) perllib.WARNING = 0 # prevent a warning if (0 < len(_args) and _args[0] is not None) and ( perllib.ref_scalar(_args[0])[0:3] == "CGI" or perllib.isa(_args[0], "CGI") ): return _args else: return perllib.Array([CGI.DefaultClass_v, _args]) finally: perllib.WARNING = _locals_stack.pop()
CGI.self_or_CGI = lambda *_args, **_kwargs: perllib.tie_call(self_or_CGI, _args, _kwargs) #### Method: default_dtd # Set or return the default_dtd global ####
[docs]def default_dtd(*_args): [self, param_v, param2] = perllib.list_of_n(self_or_CGI(*_args), 3) if param2 is not None and param_v is not None: CGI.DEFAULT_DTD_v = perllib.Array([param_v, param2]) elif param_v is not None: CGI.DEFAULT_DTD_v = param_v return CGI.DEFAULT_DTD_v
CGI.default_dtd = lambda *_args, **_kwargs: perllib.tie_call(default_dtd, _args, _kwargs)
[docs]def close_upload_files(*_args): [self, param_v] = perllib.list_of_n(self_or_CGI(*_args), 2) if param_v is not None: CGI.CLOSE_UPLOAD_FILES_v = param_v return CGI.CLOSE_UPLOAD_FILES_v
CGI.close_upload_files = lambda *_args, **_kwargs: perllib.tie_call( close_upload_files, _args, _kwargs ) #### Method: nph # Set or return the NPH global flag ####
[docs]def nph(*_args): [self, param_v] = perllib.list_of_n(self_or_CGI(*_args), 2) if param_v is not None: CGI.NPH_v = param_v return CGI.NPH_v
CGI.nph = lambda *_args, **_kwargs: perllib.tie_call(nph, _args, _kwargs) #### Method: nosticky # Set or return the NOSTICKY global flag ####
[docs]def nosticky(*_args): [self, param_v] = perllib.list_of_n(self_or_CGI(*_args), 2) if param_v is not None: CGI.NOSTICKY_v = param_v return CGI.NOSTICKY_v
CGI.nosticky = lambda *_args, **_kwargs: perllib.tie_call(nosticky, _args, _kwargs)
[docs]def user_name(*_args): [self] = perllib.list_of_n(self_or_CGI(*_args), 1) return self.http("from") or os.environ.get("REMOTE_IDENT") or os.environ.get("REMOTE_USER")
CGI.user_name = lambda *_args, **_kwargs: perllib.tie_call(user_name, _args, _kwargs) #### Method: https # Return the value of HTTPS, or # the value of an HTTPS variable, or # the list of variables ####
[docs]def https(*_args, wantarray=False): [self, parameter] = perllib.list_of_n(self_or_CGI(*_args), 2) if parameter is not None: parameter = _str(parameter).translate( str.maketrans("-abcdefghijklmnopqrstuvwxyz", "_ABCDEFGHIJKLMNOPQRSTUVWXYZ") ) if re.search(rf"^HTTPS(?:_|$)", _str(parameter)): return os.environ.get(_str(parameter)) return os.environ.get(f"HTTPS_{_bn(parameter)}") return ( ( list( filter( lambda _d: re.search(rf"^HTTPS(?:_|$)", _d), perllib.make_list(sorted(os.environ.keys())), ) ) ) if wantarray else os.environ.get("HTTPS") )
CGI.https = lambda *_args, **_kwargs: perllib.tie_call(https, _args, _kwargs)
[docs]def http(*_args): [self, parameter] = perllib.list_of_n(self_or_CGI(*_args), 2) if parameter is not None: parameter = _str(parameter).translate( str.maketrans("-abcdefghijklmnopqrstuvwxyz", "_ABCDEFGHIJKLMNOPQRSTUVWXYZ") ) if re.search(rf"^HTTP(?:_|$)", _str(parameter)): return os.environ.get(_str(parameter)) return os.environ.get(f"HTTP_{_bn(parameter)}") return list( filter( lambda _d: re.search(rf"^HTTP(?:_|$)", _d), perllib.make_list(sorted(os.environ.keys())), ) )
CGI.http = lambda *_args, **_kwargs: perllib.tie_call(http, _args, _kwargs) #### Method: virtual_host # Return the name of the virtual_host, which # is not always the same as the server ######
[docs]def virtual_host(*_args): vh = http("x_forwarded_host") or http("host") or server_name() vh = re.sub(r":\d+$", r"", _str(vh), count=1) # get rid of port number return vh
CGI.virtual_host = lambda *_args, **_kwargs: perllib.tie_call(virtual_host, _args, _kwargs)
[docs]def url(*_args): port = None protocol_v = None vh = None [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) [relative, absolute, full, path_info_v, query, base, rewrite] = perllib.list_of_n( rearrange( perllib.Array( [ "RELATIVE", "ABSOLUTE", "FULL", ["PATH", "PATH_INFO"], ["QUERY", "QUERY_STRING"], "BASE", "REWRITE", ] ), *p, ), 7, ) url_v = "" if base or not (relative or absolute): full = perllib.num(full) + 1 if rewrite is None: rewrite = perllib.num(rewrite) + 1 path = self.path_info() script_name_v = self.script_name() request_uri_v = self.request_uri() or "" query_str = (self.query_string()) if query else "" script_name_v = re.sub( re.compile(r"\?.*$", re.S), r"", _str(script_name_v), count=1 ) # remove query string request_uri_v = re.sub( re.compile(r"\?.*$", re.S), r"", _str(request_uri_v), count=1 ) # remove query string request_uri_v = unescape(request_uri_v) uri = request_uri_v if rewrite and request_uri_v else script_name_v if os.environ.get("PATH_INFO") is not None: # IIS sometimes sets PATH_INFO to the same value as SCRIPT_NAME so only sub it out # if SCRIPT_NAME isn't defined or isn't the same value as PATH_INFO if os.environ.get("SCRIPT_NAME") is None or _str(os.environ.get("PATH_INFO")) != _str( os.environ.get("SCRIPT_NAME") ): def _f2711(_m_): global _m _m = _m_ return _m.expand(r"") uri = re.sub( re.compile(rf"{perllib.quotemeta(os.environ.get('PATH_INFO',''))}$"), _f2711, _str(uri), count=1, ) # if we're not IIS then keep to spec, the relevant info is here: # https://tools.ietf.org/html/rfc3875#section-4.1.13, namely # "No PATH_INFO segment (see section 4.1.5) is included in the # SCRIPT_NAME value." (see GH #126, GH #152, GH #176) if not CGI.IIS_v: def _f2718(_m_): global _m _m = _m_ return _m.expand(r"") uri = re.sub( re.compile(rf"{perllib.quotemeta(os.environ.get('PATH_INFO',''))}$"), _f2718, _str(uri), count=1, ) if full: protocol_v = self.protocol() url_v = f"{_bn(protocol_v)}://" vh = http("x_forwarded_host") or http("host") or "" vh = re.sub( r"^.*,\s*", r"", _str(vh), count=1 ) # x_forwarded_host may be a comma-separated list (e.g. when the request has # passed through multiple reverse proxies. Take the last one. vh = re.sub( r":\d+$", r"", _str(vh), count=1 ) # some clients add the port number (incorrectly). Get rid of it. url_v = _str(url_v) + _str(vh or server_name()) port = self.virtual_port() # add the port to the url unless it's the protocol's default port if not ( (_str(protocol_v).lower() == "http" and perllib.num(port) == 80) or (_str(protocol_v).lower() == "https" and perllib.num(port) == 443) ): url_v = _str(url_v) + (":" + _str(port)) if base: return url_v url_v = _str(url_v) + _str(uri) elif relative: [url_v] = perllib.list_of_n( (_m := re.search(r"([^/]+)$", _str(uri)), _m.groups() if _m else [])[1], 1 ) elif absolute: url_v = uri if path_info_v and path is not None: url_v = _str(url_v) + _str(path) if query and _str(query_str) != "": url_v = _str(url_v) + f"?{_bn(query_str)}" url_v = url_v or "" def _f2750(_m_): global _m _m = _m_ return perllib.format_("%%%02X", ord(_m.group(1))) url_v = re.sub(re.compile(r"([^a-zA-Z0-9_.%;&?/\\:+=~-])"), _f2750, _str(url_v), count=0) return url_v
CGI.url = lambda *_args, **_kwargs: perllib.tie_call(url, _args, _kwargs) #### Method: cookie # Set or read a cookie from the specified name. # Cookie can then be passed to header(). # Usual rules apply to the stickiness of -value. # Parameters: # -name -> name for this cookie (optional) # -value -> value of this cookie (scalar, array or hash) # -path -> paths for which this cookie is valid (optional) # -domain -> internet domain in which this cookie is valid (optional) # -secure -> if true, cookie only passed through secure channel (optional) # -expires -> expiry date in format Wdy, DD-Mon-YYYY HH:MM:SS GMT (optional) ####
[docs]def referer(*_args): [self] = perllib.list_of_n(self_or_CGI(*_args), 1) return self.http("referer")
CGI.referer = lambda *_args, **_kwargs: perllib.tie_call(referer, _args, _kwargs) #### Method: raw_cookie # Returns the magic cookies for the session. # The cookies are not parsed or altered in any way, i.e. # cookies are returned exactly as given in the HTTP # headers. If a cookie name is given, only that cookie's # value is returned, otherwise the entire raw cookie # is returned. #### CGI.raw_cookie = lambda *_args, **_kwargs: perllib.tie_call(raw_cookie, _args, _kwargs) #### Method: user_agent # If called with no parameters, returns the user agent. # If called with one parameter, does a pattern match (case # insensitive) on the user agent. ####
[docs]def user_agent(*_args): [self, match] = perllib.list_of_n(self_or_CGI(*_args), 2) user_agent_v = self.http("user_agent") if not (match is not None and match and user_agent_v): return user_agent_v return (_m := re.search(re.compile(rf"{_bn(match)}", re.I), _str(user_agent_v)))
CGI.user_agent = lambda *_args, **_kwargs: perllib.tie_call(user_agent, _args, _kwargs)
[docs]def Accept(*_args): global _d [self, search] = perllib.list_of_n(self_or_CGI(*_args), 2) prefs = perllib.Hash() type_v = None pref = None pat = "" accept = perllib.Array( _str(self.http("accept")).split(",") if self.http("accept") is not None else perllib.Array() ) for _d in accept: [pref] = perllib.list_of_n( ((_m := re.search(r"q=(\d\.\d+|\d+)", _str(_d))), _m.groups() if _m else [])[1], 1 ) [type_v] = perllib.list_of_n( ((_m := re.search(r"(\S+/[^;]+)", _str(_d))), _m.groups() if _m else [])[1], 1 ) if not type_v: continue prefs[_str(type_v)] = pref or 1 if not search: return prefs.keys() # if a search type is provided, we may need to # perform a pattern matching operation. # The MIME types use a glob mechanism, which # is easily translated into a perl pattern match # First return the preference for directly supported # types: if prefs.get(_str(search)): return prefs.get(_str(search)) # Didn't get it, so try pattern matching. for _d in sorted(list(prefs.keys())): if not (re.search(r"\*", _str(_d))): # not a pattern match continue def _f2997(_m_): global _m _m = _m_ return _m.expand(r"\\\g<1>") pat = re.sub(re.compile(r"([^\w*])"), _f2997, _str(_d), count=0) # escape meta characters pat = re.sub(re.compile(r"\*"), r".*", pat, count=0) # turn it into a pattern if _m := re.search(_str(pat), _str(search)): return prefs.get(_str(_d))
CGI.Accept = lambda *_args, **_kwargs: perllib.tie_call(Accept, _args, _kwargs)
[docs]def comment(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_CGI(*_args), 1) p = perllib.Array(p) return f"<!-- {perllib.LIST_SEPARATOR.join(map(_str,p))} -->"
CGI.comment = lambda *_args, **_kwargs: perllib.tie_call(comment, _args, _kwargs)
[docs]def HtmlBot(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.end_html(*p)
CGI.HtmlBot = lambda *_args, **_kwargs: perllib.tie_call(HtmlBot, _args, _kwargs)
[docs]def HtmlTop(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.start_html(*p)
CGI.HtmlTop = lambda *_args, **_kwargs: perllib.tie_call(HtmlTop, _args, _kwargs)
[docs]def PrintHeader(*_args): [self] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 1) return self.header()
CGI.PrintHeader = lambda *_args, **_kwargs: perllib.tie_call(PrintHeader, _args, _kwargs) #### Method: keywords # Keywords acts a bit differently. Calling it in a list context # returns the list of keywords. # Calling it in a scalar context gives you the size of the list. ####
[docs]def keywords(*_args): [self, *values_] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) values_ = perllib.Array(values_) # If values is provided, then we set it. if values_: self["param"]["keywords"] = values_.copy() result = perllib.Array( self["param"].get("keywords") if self["param"].get("keywords") is not None else perllib.Array() ) return result
CGI.keywords = lambda *_args, **_kwargs: perllib.tie_call(keywords, _args, _kwargs) # These are some tie() interfaces for compatibility # with Steve Brenner's cgi-lib.pl routines #### Method: import_names # Import all parameters into the given namespace. # Assumes namespace 'Q' if not specified ####
[docs]def import_names(*_args): global _d, param_l [self, namespace, delete_v] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 3) if namespace is None: namespace = "Q" if perllib.fetch_perl_global(f"{_bn(namespace)}::" + "_h") == builtins.main.__dict__: raise Die("""Can't import names into "main"\n""") if delete_v or CGI.MOD_PERL_v or "FCGI_ROLE" in os.environ: # can anyone find an easier way to do this? for _d in sorted(list(perllib.fetch_perl_global(f"{_bn(namespace)}::" + "_h").keys())): try: _locals_stack.append(CGI.symbol_v) _locals_stack.append(CGI.symbol_a) _locals_stack.append(CGI.symbol_h) CGI.symbol_h = f"{_bn(namespace)}::{_bn(_d)}" CGI.symbol_v = None CGI.symbol_a = perllib.Array() CGI.symbol_h = perllib.Hash() finally: CGI.symbol_h = _locals_stack.pop() CGI.symbol_a = _locals_stack.pop() CGI.symbol_v = _locals_stack.pop() param_v = None value_a = perllib.Array() var = "" for param_l in perllib.flatten([self.param(wantarray=True)]): try: _locals_stack.append(CGI.symbol_v) _locals_stack.append(CGI.symbol_a) _locals_stack.append(CGI.symbol_h) # protect against silly names var = perllib.translate( perllib.maketrans_c( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", "_" ), complement=True, var=_str(param_l), ) def _f1170(_m_): global _m _m = _m_ return _m.expand(r"_") var = re.sub(re.compile(r"^(?=\d)"), _f1170, var, count=1) CGI.symbol_h = f"{_bn(namespace)}::{var}" value_a = perllib.Array(self.param(param_l, wantarray=True)) CGI.symbol_a = value_a.copy() CGI.symbol_v = value_a[0] finally: CGI.symbol_h = _locals_stack.pop() CGI.symbol_a = _locals_stack.pop() CGI.symbol_v = _locals_stack.pop()
CGI.import_names = lambda *_args, **_kwargs: perllib.tie_call(import_names, _args, _kwargs)
[docs]def delete(*_args): global _d [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) names = perllib.Array(rearrange(perllib.Array(["NAME"]), *p)) to_delete = perllib.Array(CGI.names_v[0] if perllib.refs(names[0]) == "ARRAY" else names) to_delete_h = perllib.Hash() for name_l in to_delete: self["param"].pop(_str(name_l), None) self[".fieldnames"].pop(_str(name_l), None) to_delete_h[_s0] = perllib.num(to_delete_h.get(_s0 := _str(name_l))) + 1 perllib.assign_hash( self, ".parameters", perllib.Array( list( filter( lambda _d: not _str(_d) in to_delete_h, perllib.make_list(self.param(wantarray=True)), ) ) ), ) return
CGI.delete = lambda *_args, **_kwargs: perllib.tie_call(delete, _args, _kwargs)
[docs]def element_tab(*_args): [self, new_value] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) self[".etab"] = self[".etab"] or 1 if new_value is not None: self[".etab"] = new_value tab = perllib.add_element(self, ".etab", 1) - 1 if not (CGI.TABINDEX_v or new_value is not None): return "" return f'tabindex="{_bn(tab)}" '
CGI.element_tab = lambda *_args, **_kwargs: perllib.tie_call(element_tab, _args, _kwargs) ##### # subroutine: read_postdata_putdata # # Unless file uploads are disabled # Reads BODY of POST/PUT request and stuffs it into tempfile # accessible as param POSTDATA/PUTDATA # # Also respects upload_hook # # based on subroutine read_multipart_related #####
[docs]def element_id(*_args): [self, new_value] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) if new_value is not None: self[".elid"] = new_value return perllib.format_("%010d", (perllib.add_element(self, ".elid", 1) - 1))
CGI.element_id = lambda *_args, **_kwargs: perllib.tie_call(element_id, _args, _kwargs)
[docs]def charset(*_args): [self, charset_v] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) if charset_v is not None: self[".charset"] = charset_v return self[".charset"]
CGI.charset = lambda *_args, **_kwargs: perllib.tie_call(charset, _args, _kwargs) def _tag_func(*_args): _args = list(_args) global _d attr_a = perllib.Array() result = perllib.Array() tag = "" untag = "" tagname = _args.pop(0) if _args else None [q, a, *rest] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 2) rest = perllib.Array(rest) [attr] = perllib.list_of_n("", 1) if perllib.ref_scalar(a) and perllib.refs(a) == "HASH": attr_a = perllib.Array(make_attributes(a, q.get("escape"), wantarray=True)) if attr_a: attr = f" {perllib.LIST_SEPARATOR.join(map(_str,attr_a))}" else: if a is not None: rest[0:0] = [a] tagname = _str(tagname).lower() if _m := re.search(re.compile(r"start_(\w+)", re.I), _str(tagname)): return f"<{_m.group(1)}{_bn(attr)}>" elif _m := re.search(re.compile(r"end_(\w+)", re.I), _str(tagname)): return f"</{_m.group(1)}>" else: if not rest: return ( f"<{_bn(tagname)}{_bn(attr)} />" if CGI.XHTML_v else f"<{_bn(tagname)}{_bn(attr)}>" ) [tag, untag] = (f"<{_bn(tagname)}{_bn(attr)}>", f"</{_bn(tagname)}>") result = perllib.Array( perllib.flatten( map( lambda _d: f"{tag}{_bn(_d)}{untag}", perllib.make_list( rest[0] if (perllib.refs(rest[0]) == "ARRAY") else f"{perllib.LIST_SEPARATOR.join(map(_str,rest))}" ), ) ) ) return f"{perllib.LIST_SEPARATOR.join(map(_str,result))}" CGI._tag_func = lambda *_args, **_kwargs: perllib.tie_call(_tag_func, _args, _kwargs)
[docs]def cgi_error(*_args): [self, err] = perllib.list_of_n(self_or_default(*_args, wantarray=True), 2) if err is not None: self[".cgi_error"] = err return self.get(".cgi_error")
CGI.cgi_error = lambda *_args, **_kwargs: perllib.tie_call(cgi_error, _args, _kwargs)
[docs]def put(*_args): [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) return self.print_(*p)
CGI.put = lambda *_args, **_kwargs: perllib.tie_call(put, _args, _kwargs) def _decode_utf8(*_args): [self, val] = perllib.list_of_n(_args, 2) if perllib.is_utf8(_str(val)): return val else: return perllib.decode("utf8", _str(val)) CGI._decode_utf8 = lambda *_args, **_kwargs: perllib.tie_call(_decode_utf8, _args, _kwargs)
[docs]def param(*_args, wantarray=False): global _d filename = None line = None package = None values_ = perllib.Array() [self, *p] = perllib.list_of_at_least_n(self_or_default(*_args, wantarray=True), 1) p = perllib.Array(p) if not p: return self.all_parameters(wantarray=wantarray) # list context can be dangerous so warn: # http://blog.gerv.net/2014.10/new-class-of-vulnerability-in-perl-web-applications if wantarray and perllib.num(CGI.LIST_CONTEXT_WARN_v) == 1: [package, filename, line] = perllib.list_of_n(perllib.caller(), 3) if _str(package) != "CGI": CGI.LIST_CONTEXT_WARN_v = perllib.num(CGI.LIST_CONTEXT_WARN_v) + 1 # only warn once perllib.perl_print( f"CGI::param called in list context from {_bn(filename)} line {_bn(line)}, this can lead to vulnerabilities. " + 'See the warning in "Fetching the value or values of a single named parameter"', file=sys.stderr, ) name = None value_v = None other = perllib.Array() # For compatibility between old calling style and use_named_parameters() style, # we have to special case for a single parameter present. if len(p) > 1: [name, value_v, *other] = perllib.list_of_at_least_n( rearrange(perllib.Array(["NAME", ["DEFAULT", "VALUE", "VALUES"]]), *p), 2 ) other = perllib.Array(other) values_ = perllib.Array() if _str(p[0])[0:1] == "-": values_ = perllib.Array( ( value_v if perllib.ref_scalar(value_v) and perllib.refs(value_v) == "ARRAY" else value_v ) if value_v is not None else perllib.Array() ) else: for _d in (value_v, other): if _d is not None: values_.append(_d) # If values is provided, then we set it. if values_ or value_v is not None: self.add_parameter(name) self["param"][_str(name)] = values_.copy() else: name = p[0] if not (name is not None and self["param"].get(_str(name))): return perllib.Array() if wantarray else None result = perllib.Array(self["param"].get(_str(name))) if ( CGI.PARAM_UTF8_v and _str(name) != "PUTDATA" and _str(name) != "POSTDATA" and _str(name) != "PATCHDATA" ): if not perllib.can(Encode, "decode"): # bring in these functions try: pass # SKIPPED: require Encode; 1; _eval_result449 = 1 raise EvalReturn except EvalReturn: pass except Exception: pass result = perllib.Array( perllib.flatten( map(lambda _d: _d if perllib.ref_scalar(_d) else self._decode_utf8(_d), result) ) ) return result if wantarray else result[0]
CGI.param = lambda *_args, **_kwargs: perllib.tie_call(param, _args, _kwargs)
[docs]def FETCH(*_args): if _str(_args[1]) == "CGI": return _args[0] if not (0 < len(_args) and _args[0] is not None): return None return "\0".join(map(_str, (_args[0].param(_args[1], wantarray=True))))
CGI.FETCH = lambda *_args, **_kwargs: perllib.tie_call(FETCH, _args, _kwargs) #### Method: param / multi_param # Returns the value(s)of a named parameter. # If invoked in a list context, returns the # entire list. Otherwise returns the first # member of the list. # If name is not provided, return a list of all # the known parameters names available. # If more than one argument is provided, the # second and subsequent arguments are used to # set the value of the parameter. # # note that calling param() in list context # will raise a warning about potential bad # things, hence the multi_param method ####
[docs]def multi_param(*_args): # we don't need to set $LIST_CONTEXT_WARN to 0 here # because param() will check the caller before warning list_of_params = perllib.Array(param(*_args, wantarray=True)) return list_of_params
CGI.multi_param = lambda *_args, **_kwargs: perllib.tie_call(multi_param, _args, _kwargs)
[docs]def upload_hook(*_args): _args = list(_args) self = None if perllib.ref_scalar(_args[0]) == "CODE": CGI.Q_v = self = perllib.method_call(CGI.DefaultClass_v, "new", *_args) else: self = _args.pop(0) if _args else None [hook, data_v, use_tempfile] = perllib.list_of_n(_args, 3) self[".upload_hook"] = hook self[".upload_data"] = data_v if use_tempfile is not None: self["use_tempfile"] = use_tempfile return self.get("use_tempfile")
CGI.upload_hook = lambda *_args, **_kwargs: perllib.tie_call(upload_hook, _args, _kwargs)
[docs]def r(*_args): _args = list(_args) self = _args.pop(0) if _args else None r_v = self.get(".r") if _args: self[".r"] = _args.pop(0) if _args else None return r_v
CGI.r = lambda *_args, **_kwargs: perllib.tie_call(r, _args, _kwargs)
[docs]def expand_tags(*_args): global _d [tag] = perllib.list_of_n(_args, 1) if _m := re.search(r"^(?:\*|start_|end_)(.+)", _str(tag)): return perllib.Array([f"start_{_m.group(1)}", f"end_{_m.group(1)}"]) r_a = perllib.Array() if not (CGI.EXPORT_TAGS_h.get(_str(tag))): return tag for _d in CGI.EXPORT_TAGS_h[_str(tag)]: r_a.extend(perllib.make_list(expand_tags(_d))) return r_a
CGI.expand_tags = lambda *_args, **_kwargs: perllib.tie_call(expand_tags, _args, _kwargs) #### Method: new # The new routine. This will check the current environment # for an existing query string, and initialize itself, if so. #### def _setup_symbols(*_args): _args = list(_args) global _d self = _args.pop(0) if _args else None # to avoid reexporting unwanted variables CGI.EXPORT_h = perllib.Hash() for _d in _args: try: if re.search(r"^[:-]any$", _str(_d)): perllib.perl_print( "CGI -any pragma has been REMOVED. You should audit your code for any use " + "of none supported / incorrectly spelled tags and remove them", file=sys.stderr, ) continue if re.search(r"^[:-]unique_headers$", _str(_d)): ( perllib.assign_global( "CGI", "HEADERS_ONCE_v", perllib.num(CGI.HEADERS_ONCE_v) + 1 ) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]nph$", _str(_d)): ( perllib.assign_global("CGI", "NPH_v", perllib.num(CGI.NPH_v) + 1) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]nosticky$", _str(_d)): ( perllib.assign_global("CGI", "NOSTICKY_v", perllib.num(CGI.NOSTICKY_v) + 1) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]no_?[Dd]ebug$", _str(_d)): perllib.assign_global("CGI", "DEBUG_v", 0), perllib.raise_( LoopControl("continue") ) if re.search(r"^[:-][Dd]ebug$", _str(_d)): perllib.assign_global("CGI", "DEBUG_v", 2), perllib.raise_( LoopControl("continue") ) if re.search(r"^[:-]newstyle_urls$", _str(_d)): ( perllib.assign_global( "CGI", "USE_PARAM_SEMICOLONS_v", perllib.num(CGI.USE_PARAM_SEMICOLONS_v) + 1, ) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-](?:putdata_upload|postdata_upload|patchdata_upload)$", _str(_d)): ( perllib.assign_global( "CGI", "PUTDATA_UPLOAD_v", perllib.num(CGI.PUTDATA_UPLOAD_v) + 1 ) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]utf8$", _str(_d)): ( perllib.assign_global( "CGI", "PARAM_UTF8_v", perllib.num(CGI.PARAM_UTF8_v) + 1 ) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]xhtml$", _str(_d)): ( perllib.assign_global("CGI", "XHTML_v", perllib.num(CGI.XHTML_v) + 1) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]no_?xhtml$", _str(_d)): perllib.assign_global("CGI", "XHTML_v", 0), perllib.raise_( LoopControl("continue") ) if re.search(r"^[:-]oldstyle_urls$", _str(_d)): perllib.assign_global("CGI", "USE_PARAM_SEMICOLONS_v", 0), perllib.raise_( LoopControl("continue") ) if re.search(r"^[:-]tabindex$", _str(_d)): ( perllib.assign_global("CGI", "TABINDEX_v", perllib.num(CGI.TABINDEX_v) + 1) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]close_upload_files$", _str(_d)): ( perllib.assign_global( "CGI", "CLOSE_UPLOAD_FILES_v", perllib.num(CGI.CLOSE_UPLOAD_FILES_v) + 1 ) - 1 ), perllib.raise_(LoopControl("continue")) if re.search(r"^[:-]no_undef_params$", _str(_d)): ( perllib.assign_global( "CGI", "NO_UNDEF_PARAMS_v", perllib.num(CGI.NO_UNDEF_PARAMS_v) + 1 ) - 1 ), perllib.raise_(LoopControl("continue")) for _d in expand_tags(_d): _d = perllib.translate( perllib.maketrans_c( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", "", delete=True, ), complement=True, var=_str(_d), ) # don't allow weird function names CGI.EXPORT_h[_s0] = perllib.num(CGI.EXPORT_h.get(_s0 := _str(_d))) + 1 except LoopControl as _l: if _l.args[0] == "break": break continue CGI.SAVED_SYMBOLS_a = _args.copy() return CGI.SAVED_SYMBOLS_a CGI._setup_symbols = lambda *_args, **_kwargs: perllib.tie_call(_setup_symbols, _args, _kwargs) # to import symbols into caller
[docs]def import_(*_args): _args = list(_args) self = _args.pop(0) if _args else None # This causes modules to clash. CGI.EXPORT_OK_h = perllib.Hash() CGI.EXPORT_h = perllib.Hash() perllib.method_call(self, "_setup_symbols", *_args) [callpack, callfile, callline] = perllib.list_of_n(perllib.caller(), 3) if _str(callpack) == "CGI::Fast": # fixes GH #11 (and GH #12 in CGI::Fast since # sub import was added to CGI::Fast in 9537f90 # so we need to move up a level to export the # routines to the namespace of whatever is using # CGI::Fast [callpack, callfile, callline] = perllib.list_of_n(perllib.caller(1), 3) # To allow overriding, search through the packages # Till we find one in which the correct subroutine is defined. packages = perllib.Array([self, perllib.fetch_perl_global(f"{_bn(self)}::ISA" + "_a")]) try: _locals_stack.append(CGI.sym_v) for CGI.sym_v in sorted(list(CGI.EXPORT_h.keys())): pck = None def_ = CGI.DefaultClass_v for pck_l in packages: if perllib.fetch_perl_global(f"{_bn(pck_l)}::{_bn(CGI.sym_v)}") is not None: def_ = pck_l break perllib.store_perl_global( f"{_bn(callpack)}::{_bn(CGI.sym_v)}", perllib.fetch_perl_global(f"{_bn(def_)}::{_bn(CGI.sym_v)}"), infer_suffix=True, ) finally: CGI.sym_v = _locals_stack.pop()
CGI.import_ = import_ def _set_binmode(*_args): global _d # rt #57524 - don't set binmode on filehandles if there are # already none default layers set on them default_layers = perllib.Hash( { "unix": 1, "perlio": 1, "stdio": 1, "crlf": 1, } ) for fh_l in ( sys.stdout, sys.stdin, sys.stderr, ): modes = perllib.Array( list( filter( lambda _d: not default_layers.get(_str(_d)), perllib.make_list(perllib.get_layers(fh_l)), ) ) ) if not modes: ( perllib.method_call(CGI.DefaultClass_v, "binmode", fh_l), (fh_l := perllib.fetch_out_parameter(1)), )[0] CGI._set_binmode = lambda *_args, **_kwargs: perllib.tie_call(_set_binmode, _args, _kwargs) # >>>>> Here are some globals that you might want to adjust <<<<<<
[docs]def initialize_globals(*_args): # Set this to 1 to generate XTML-compatible output CGI.XHTML_v = 1 # Change this to the preferred DTD to print in start_html() # or use default_dtd('text of DTD to use'); CGI.DEFAULT_DTD_v = perllib.Array( ["-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd"] ) # Set this to 1 to enable NOSTICKY scripts # or: # 1) use CGI '-nosticky'; # 2) $CGI::NOSTICKY = 1; CGI.NOSTICKY_v = 0 # Set this to 1 to enable NPH scripts # or: # 1) use CGI qw(-nph) # 2) CGI::nph(1) # 3) print header(-nph=>1) CGI.NPH_v = 0 # Set this to 1 to enable debugging from @ARGV # Set to 2 to enable debugging from STDIN CGI.DEBUG_v = 1 # Set this to 1 to generate automatic tab indexes CGI.TABINDEX_v = 0 # Set this to 1 to cause files uploaded in multipart documents # to be closed, instead of caching the file handle # or: # 1) use CGI qw(:close_upload_files) # 2) $CGI::close_upload_files(1); # Uploads with many files run out of file handles. # Also, for performance, since the file is already on disk, # it can just be renamed, instead of read and written. CGI.CLOSE_UPLOAD_FILES_v = 0 # Automatically determined -- don't change CGI.EBCDIC_v = 0 # Change this to 1 to suppress redundant HTTP headers CGI.HEADERS_ONCE_v = 0 # separate the name=value pairs by semicolons rather than ampersands CGI.USE_PARAM_SEMICOLONS_v = 1 # Do not include undefined params parsed from query string # use CGI qw(-no_undef_params); CGI.NO_UNDEF_PARAMS_v = 0 # return everything as utf-8 CGI.PARAM_UTF8_v = 0 # make param('PUTDATA') act like file upload CGI.PUTDATA_UPLOAD_v = 0 # Add QUERY_STRING to POST request CGI.APPEND_QUERY_STRING_v = 0 # Other globals that you shouldn't worry about. CGI.Q_v = None CGI.BEEN_THERE_v = 0 CGI.DTD_PUBLIC_IDENTIFIER_v = "" CGI.QUERY_PARAM_a = perllib.Array() CGI.QUERY_PARAM_h = perllib.Hash() CGI.EXPORT_h = perllib.Hash() CGI.QUERY_CHARSET_v = None CGI.QUERY_FIELDNAMES_h = perllib.Hash() CGI.QUERY_TMPFILES_h = perllib.Hash() # prevent complaints by mod_perl return 1
CGI.initialize_globals = lambda *_args, **_kwargs: perllib.tie_call( initialize_globals, _args, _kwargs ) # ------------------ START OF THE LIBRARY ------------ # make mod_perlhappy def _reset_globals(*_args): return initialize_globals() CGI._reset_globals = lambda *_args, **_kwargs: perllib.tie_call(_reset_globals, _args, _kwargs) def new(*_args): old = None r_v = None [package, interface, boundary, length] = perllib.list_of_n(_args, 4) CGI.MultipartBuffer.FILLUNIT_v = CGI.MultipartBuffer.INITIAL_FILLUNIT_v ( perllib.method_call(CGI.DefaultClass_v, "binmode", CGI.MultipartBuffer.IN_v), perllib.assign_global("CGI.MultipartBuffer", "IN_v", perllib.fetch_out_parameter(1)), )[ 0 ] # if $CGI::needs_binmode; # just do it always # If the user types garbage into the file upload field, # then Netscape passes NOTHING to the server (not good). # We may hang on this read in that case. So we implement # a read timeout. If nothing is ready to read # by then, we return. # Netscape seems to be a little bit unreliable # about providing boundary strings. boundary_read = 0 if boundary: # Under the MIME spec, the boundary consists of the # characters "--" PLUS the Boundary string # BUG: IE 3.01 on the Macintosh uses just the boundary -- not # the two extra hyphens. We do a special case here on the user-agent!!!! if not CGI.user_agent("MSIE\s+3\.0[12];\s*Mac|DreamPassport"): boundary = f"--{_bn(boundary)}" else: # otherwise we find it ourselves old = None [old, perllib.INPUT_RECORD_SEPARATOR] = ( perllib.INPUT_RECORD_SEPARATOR, CGI.MultipartBuffer.CRLF_v, ) # read a CRLF-delimited line boundary = perllib.readline_full( sys.stdin ) # BUG: This won't work correctly under mod_perl length = perllib.num(length) - len(_str(boundary)) boundary = boundary.rstrip("\n") # remove the CRLF perllib.INPUT_RECORD_SEPARATOR = old # restore old line separator boundary_read += 1 self = perllib.Hash( { "LENGTH": length, "CHUNKED": not length, "BOUNDARY": boundary, "INTERFACE": interface, "BUFFER": "", } ) if len(_str(boundary)) > perllib.num(CGI.MultipartBuffer.FILLUNIT_v): CGI.MultipartBuffer.FILLUNIT_v = len(_str(boundary)) retval = perllib.bless(self, perllib.ref_scalar(package) or package) # Read the preamble and the topmost (boundary) line plus the CRLF. if not boundary_read: while self.read(0): pass if self.eof(): raise Die("Malformed multipart POST: data truncated\n") return retval CGI.MultipartBuffer.new = types.MethodType(new, CGI.MultipartBuffer) CGI.read_multipart_related = lambda *_args, **_kwargs: perllib.tie_call( read_multipart_related, _args, _kwargs )
[docs]def read_multipart(*_args): global CRLF_v, _d value_v = None [self, boundary, length] = perllib.list_of_n(_args, 3) [buffer] = perllib.list_of_n(self.new_MultipartBuffer(boundary, length), 1) if not buffer: return header_h = perllib.Hash() body = None filenumber = 0 while not buffer.eof(): header_h = perllib.Hash(buffer.readHeader(wantarray=True)) if not header_h: self.cgi_error("400 Bad request (malformed multipart POST)") return header_h["Content-Disposition"] = ( header_h["Content-Disposition"] or "" ) # quench uninit variable warning param_v = _mp_value_parse(header_h.get("Content-Disposition"), "name") param_v = _str(param_v) + _str(CGI.TAINTED_v) # See RFC 1867, 2183, 2045 # NB: File content will be loaded into memory should # content-disposition parsing fail. [filename] = perllib.list_of_n( ( _m := re.search( re.compile(r""" filename=(("[^"]*")|([a-z\d!#'\*\+,\.^_`\{\}\|~]*))""", re.I), _str(header_h.get("Content-Disposition")), ), _m.groups() if _m else [], )[1], 1, ) filename = filename or "" # quench uninit variable warning def _f3367(_m_): global _m _m = _m_ return _m.expand(r"\g<1>") filename = re.sub(re.compile(r'^"([^"]*)"$'), _f3367, _str(filename), count=1) # Test for Opera's multiple upload feature [multipart] = perllib.list_of_n( 1 if ( header_h.get("Content-Type") is not None and (re.search(r"multipart/mixed", _str(header_h.get("Content-Type")))) ) else 0, 1, ) # add this parameter to our list self.add_parameter(param_v) # If no filename specified, then just read the data and assign it # to our parameter list. if (filename is None or _str(filename) == "") and not multipart: [value_v] = perllib.list_of_n(buffer.readBody(), 1) value_v = _str(value_v) + _str(CGI.TAINTED_v) self["param"].get(_str(param_v)).append(value_v) continue # UPLOADS for _ in range(1): try: _locals_stack.append(perllib.OUTPUT_RECORD_SEPARATOR) # If we get here, then we are dealing with a potentially large # uploaded form. Save the data to a temporary file, then open # the file for reading. # skip the file if uploads disabled if CGI.DISABLE_UPLOADS_v: while perllib.assign_global("CGI", "data_v", buffer.read()) is not None: pass break # set the filename to some recognizable value if (filename is None or _str(filename) == "") and multipart: filename = "multipart/mixed" tmp_dir = ( ( os.environ.get("TEMP") or os.environ.get("TMP") or ( (_str(os.environ.get("WINDIR")) + _str(CGI.SL_v) + "TEMP") if os.environ.get("WINDIR") else None ) ) if _str(CGI.OS_v) == "WINDOWS" else None ) # File::Temp defaults to TMPDIR import CGI.File.Temp as _CGI_File_Temp filehandle = CGI.File.Temp.new( "UNLINK", CGI.UNLINK_TMP_FILES_v, "DIR", tmp_dir, ) filehandle._mp_filename(filename) if CGI.needs_binmode_v and perllib.fileno(filehandle) is not None: ( perllib.method_call(CGI.DefaultClass_v, "binmode", filehandle), (filehandle := perllib.fetch_out_parameter(1)), )[0] # if this is an multipart/mixed attachment, save the header # together with the body for later parsing with an external # MIME parser module if multipart: for _d in sorted(list(header_h.keys())): perllib.perl_print( f"{_bn(_d)}: {header_h.get(_str(_d),'')}{_bn(CGI.CRLF_v)}", end="", file=filehandle, ) perllib.perl_print(f"{_bn(CGI.CRLF_v)}", end="", file=filehandle) data_v = None [perllib.OUTPUT_RECORD_SEPARATOR] = perllib.list_of_n("", 1) totalbytes = 0 while (data_v := buffer.read()) is not None: if self.get(".upload_hook") is not None: totalbytes += len(_str(data_v)) perllib.get_subref(self.get(".upload_hook"))( filename, data_v, totalbytes, self.get(".upload_data") ) if self.get("use_tempfile"): perllib.perl_print(data_v, end="", file=filehandle) # back up to beginning of file perllib.seek(filehandle, 0, 0) ## Close the filehandle if requested this allows a multipart MIME ## upload to contain many files, and we won't die due to too many ## open file handles. The user can access the files using the hash ## below. if CGI.CLOSE_UPLOAD_FILES_v: perllib.close_(filehandle) if CGI.needs_binmode_v: ( perllib.method_call(CGI.DefaultClass_v, "binmode", filehandle), (filehandle := perllib.fetch_out_parameter(1)), )[0] # Save some information about the uploaded file where we can get # at it later. # Use the typeglob + filename as the key, as this is guaranteed to be # unique for each filehandle. Don't use the file descriptor as # this will be re-used for each filehandle if the # close_upload_files feature is used. self[".tmpfiles"][_str(filehandle) + _str(filehandle)] = perllib.Hash( { "hndl": filehandle, "name": filehandle.filename(), "info": header_h.copy(), } ) self["param"].get(_str(param_v)).append(filehandle) except LoopControl_UPLOADS as _l: if _l.args[0] == "break": break continue finally: perllib.OUTPUT_RECORD_SEPARATOR = _locals_stack.pop()
CGI.read_multipart = lambda *_args, **_kwargs: perllib.tie_call(read_multipart, _args, _kwargs) CGI.cookie = lambda *_args, **_kwargs: perllib.tie_call(cookie, _args, _kwargs)
[docs]def TIEHASH(*_args): _args = list(_args) class_ = _args.pop(0) if _args else None arg = _args[0] if perllib.ref_scalar(arg) and perllib.isa(arg, "CGI"): return perllib.add_tie_methods(arg) return perllib.add_tie_methods( perllib.assign_global("CGI", "Q_v", CGI.Q_v or class_.new(*_args)) )
CGI.TIEHASH = types.MethodType(TIEHASH, CGI) # These are some tie() interfaces for compatibility # with Steve Brenner's cgi-lib.pl routines
[docs]def ReadParse(*_args): pkg = perllib.Array() try: _locals_stack.append(CGI.in_h) CGI.in_h = perllib.Hash() CGI.in_ = None if _args: CGI.in_ = _args[0] else: pkg = perllib.caller_s() CGI.in_ = perllib.fetch_perl_global(f"{_bn(pkg)}::in") CGI.in_h = CGI.TIEHASH() return len(CGI.in_h.keys()) finally: CGI.in_h = _locals_stack.pop()
CGI.ReadParse = lambda *_args, **_kwargs: perllib.tie_call(ReadParse, _args, _kwargs)
[docs]def Vars(*_args, wantarray=False): _args = list(_args) q = _args.pop(0) if _args else None in_h = None in_h = CGI.TIEHASH(q) if wantarray: return in_h return in_h
CGI.Vars = lambda *_args, **_kwargs: perllib.tie_call(Vars, _args, _kwargs)
[docs]def new_MultipartBuffer(*_args): [self, boundary, length] = perllib.list_of_n(_args, 3) return CGI.MultipartBuffer.new(self, boundary, length)
CGI.new_MultipartBuffer = lambda *_args, **_kwargs: perllib.tie_call( new_MultipartBuffer, _args, _kwargs )
[docs]def read_postdata_putdata(*_args): buf = "" len_ = None read_v = None unit = "" [self, postOrPut, content_length, content_type_v] = perllib.list_of_n(_args, 4) header_h = perllib.Hash( { "Content-Type": content_type_v, } ) param_v = postOrPut # add this parameter to our list self.add_parameter(param_v) # UPLOADS for _ in range(1): try: _locals_stack.append(perllib.OUTPUT_RECORD_SEPARATOR) # If we get here, then we are dealing with a potentially large # uploaded form. Save the data to a temporary file, then open # the file for reading. # skip the file if uploads disabled if CGI.DISABLE_UPLOADS_v: buf = None unit = CGI.MultipartBuffer.INITIAL_FILLUNIT_v len_ = content_length while perllib.num(len_) > 0: read_v = ( self.read_from_client(buf, unit, 0), (buf := perllib.fetch_out_parameter(1)), )[0] len_ = perllib.num(len_) - perllib.num(read_v) break # SHOULD PROBABLY SKIP THIS IF NOT $self->{'use_tempfile'} # BUT THE REST OF CGI.PM DOESN'T, SO WHATEVER tmp_dir = ( ( os.environ.get("TEMP") or os.environ.get("TMP") or ( (_str(os.environ.get("WINDIR")) + _str(CGI.SL_v) + "TEMP") if os.environ.get("WINDIR") else None ) ) if _str(CGI.OS_v) == "WINDOWS" else None ) # File::Temp defaults to TMPDIR import CGI.File.Temp as _CGI_File_Temp filehandle = CGI.File.Temp.new( "UNLINK", CGI.UNLINK_TMP_FILES_v, "DIR", tmp_dir, ) filehandle._mp_filename(postOrPut) if CGI.needs_binmode_v and perllib.fileno(filehandle) is not None: ( perllib.method_call(CGI.DefaultClass_v, "binmode", filehandle), (filehandle := perllib.fetch_out_parameter(1)), )[0] data_v = None [perllib.OUTPUT_RECORD_SEPARATOR] = perllib.list_of_n("", 1) totalbytes = 0 unit = CGI.MultipartBuffer.INITIAL_FILLUNIT_v len_ = content_length unit = len_ ZERO_LOOP_COUNTER = 0 while perllib.num(len_) > 0: bytesRead = ( self.read_from_client(data_v, unit, 0), (data_v := perllib.fetch_out_parameter(1)), )[0] len_ = perllib.num(len_) - perllib.num(bytesRead) # An apparent bug in the Apache server causes the read() # to return zero bytes repeatedly without blocking if the # remote user aborts during a file transfer. I don't know how # they manage this, but the workaround is to abort if we get # more than SPIN_LOOP_MAX consecutive zero reads. if perllib.num(bytesRead) <= 0: if ((ZERO_LOOP_COUNTER := ZERO_LOOP_COUNTER + 1) - 1) >= perllib.num( CGI.SPIN_LOOP_MAX_v ): raise Die( "CGI.pm: Server closed socket during read_postdata_putdata (client aborted?).\n" ) else: ZERO_LOOP_COUNTER = 0 if self.get(".upload_hook") is not None: totalbytes += len(_str(data_v)) perllib.get_subref(self[".upload_hook"])( param_v, data_v, totalbytes, self.get(".upload_data") ) if self.get("use_tempfile"): perllib.perl_print(data_v, end="", file=filehandle) data_v = None # back up to beginning of file perllib.seek(filehandle, 0, 0) ## Close the filehandle if requested this allows a multipart MIME ## upload to contain many files, and we won't die due to too many ## open file handles. The user can access the files using the hash ## below. if CGI.CLOSE_UPLOAD_FILES_v: perllib.close_(filehandle) if CGI.needs_binmode_v: ( perllib.method_call(CGI.DefaultClass_v, "binmode", filehandle), (filehandle := perllib.fetch_out_parameter(1)), )[0] # Save some information about the uploaded file where we can get # at it later. # Use the typeglob + filename as the key, as this is guaranteed to be # unique for each filehandle. Don't use the file descriptor as # this will be re-used for each filehandle if the # close_upload_files feature is used. self[".tmpfiles"][_str(filehandle) + _str(filehandle)] = perllib.Hash( { "hndl": filehandle, "name": filehandle.filename(), "info": header_h.copy(), } ) self["param"].get(_str(param_v)).append(filehandle) except LoopControl_UPLOADS as _l: if _l.args[0] == "break": break continue finally: perllib.OUTPUT_RECORD_SEPARATOR = _locals_stack.pop() return
CGI.read_postdata_putdata = lambda *_args, **_kwargs: perllib.tie_call( read_postdata_putdata, _args, _kwargs ) CGI.APPEND_QUERY_STRING_v = perllib.init_global("CGI", "APPEND_QUERY_STRING_v", "") CGI.CGI_v = perllib.init_global("CGI", "CGI_v", "") CGI.CLOSE_UPLOAD_FILES_v = perllib.init_global("CGI", "CLOSE_UPLOAD_FILES_v", None) CGI.COOKIE_CACHE_v = perllib.init_global("CGI", "COOKIE_CACHE_v", 0) CGI.CRLF_v = perllib.init_global("CGI", "CRLF_v", None) CGI.DEBUG_v = perllib.init_global("CGI", "DEBUG_v", None) CGI.DEFAULT_DTD_v = perllib.init_global("CGI", "DEFAULT_DTD_v", None) CGI.DISABLE_UPLOADS_v = perllib.init_global("CGI", "DISABLE_UPLOADS_v", None) CGI.DTD_PUBLIC_IDENTIFIER_v = perllib.init_global("CGI", "DTD_PUBLIC_IDENTIFIER_v", None) CGI.DefaultClass_v = perllib.init_global("CGI", "DefaultClass_v", None) CGI.EBCDIC_v = perllib.init_global("CGI", "EBCDIC_v", None) CGI.ENCODE_ENTITIES_v = perllib.init_global("CGI", "ENCODE_ENTITIES_v", "") CGI.EXPORT_OK_h = perllib.init_global("CGI", "EXPORT_OK_h", perllib.Hash()) CGI.EXPORT_TAGS_h = perllib.init_global("CGI", "EXPORT_TAGS_h", perllib.Hash()) CGI.EXPORT_h = perllib.init_global("CGI", "EXPORT_h", perllib.Hash()) CGI.HEADERS_ONCE_v = perllib.init_global("CGI", "HEADERS_ONCE_v", None) CGI.IIS_v = perllib.init_global("CGI", "IIS_v", None) CGI.LIST_CONTEXT_WARN_v = perllib.init_global("CGI", "LIST_CONTEXT_WARN_v", 0) CGI.MOD_PERL_v = perllib.init_global("CGI", "MOD_PERL_v", None) CGI.MultipartBuffer.CRLF_v = perllib.init_global("CGI.MultipartBuffer", "CRLF_v", "") CGI.MultipartBuffer.FILLUNIT_v = perllib.init_global("CGI.MultipartBuffer", "FILLUNIT_v", "") CGI.MultipartBuffer.INITIAL_FILLUNIT_v = perllib.init_global( "CGI.MultipartBuffer", "INITIAL_FILLUNIT_v", None ) CGI.MultipartBuffer.IN_v = perllib.init_global("CGI.MultipartBuffer", "IN_v", "") CGI.MultipartBuffer.SPIN_LOOP_MAX_v = perllib.init_global( "CGI.MultipartBuffer", "SPIN_LOOP_MAX_v", 0 ) CGI.MultipartBuffer._DEBUG_v = perllib.init_global("CGI.MultipartBuffer", "_DEBUG_v", None) CGI.NOSTICKY_v = perllib.init_global("CGI", "NOSTICKY_v", None) CGI.NO_UNDEF_PARAMS_v = perllib.init_global("CGI", "NO_UNDEF_PARAMS_v", None) CGI.NPH_v = perllib.init_global("CGI", "NPH_v", None) CGI.OS_v = perllib.init_global("CGI", "OS_v", None) CGI.PARAM_UTF8_v = perllib.init_global("CGI", "PARAM_UTF8_v", None) CGI.PERLEX_v = perllib.init_global("CGI", "PERLEX_v", None) CGI.POST_MAX_v = perllib.init_global("CGI", "POST_MAX_v", 0) CGI.PUTDATA_UPLOAD_v = perllib.init_global("CGI", "PUTDATA_UPLOAD_v", None) CGI.QUERY_CHARSET_v = perllib.init_global("CGI", "QUERY_CHARSET_v", None) CGI.QUERY_FIELDNAMES_h = perllib.init_global("CGI", "QUERY_FIELDNAMES_h", perllib.Hash()) CGI.QUERY_PARAM_a = perllib.init_global("CGI", "QUERY_PARAM_a", perllib.Array()) CGI.QUERY_PARAM_h = perllib.init_global("CGI", "QUERY_PARAM_h", perllib.Hash()) CGI.QUERY_TMPFILES_h = perllib.init_global("CGI", "QUERY_TMPFILES_h", perllib.Hash()) CGI.Q_v = perllib.init_global("CGI", "Q_v", None) CGI.SAVED_SYMBOLS_a = perllib.init_global("CGI", "SAVED_SYMBOLS_a", perllib.Array()) CGI.SL_v = perllib.init_global("CGI", "SL_v", perllib.Hash()) CGI.SPIN_LOOP_MAX_v = perllib.init_global("CGI", "SPIN_LOOP_MAX_v", "") CGI.TABINDEX_v = perllib.init_global("CGI", "TABINDEX_v", None) CGI.TAINTED_v = perllib.init_global("CGI", "TAINTED_v", None) CGI.UNLINK_TMP_FILES_v = perllib.init_global("CGI", "UNLINK_TMP_FILES_v", None) CGI.USE_PARAM_SEMICOLONS_v = perllib.init_global("CGI", "USE_PARAM_SEMICOLONS_v", None) CGI.VERSION_v = perllib.init_global("CGI", "VERSION_v", "") CGI.XHTML_v = perllib.init_global("CGI", "XHTML_v", None) CGI._XHTML_DTD_v = perllib.init_global("CGI", "_XHTML_DTD_v", "") CGI.data_v = perllib.init_global("CGI", "data_v", None) CGI.in_h = perllib.init_global("CGI", "in_h", perllib.Hash()) CGI.lines_a = perllib.init_global("CGI", "lines_a", perllib.Array()) CGI.names_v = perllib.init_global("CGI", "names_v", perllib.Array()) CGI.needs_binmode_v = perllib.init_global("CGI", "needs_binmode_v", perllib.Array()) CGI.novals_v = perllib.init_global("CGI", "novals_v", "") CGI.selected_v = perllib.init_global("CGI", "selected_v", None) CGI.sym_v = perllib.init_global("CGI", "sym_v", None) CGI.symbol = perllib.init_global("CGI", "symbol", None) CGI.symbol_a = perllib.init_global("CGI", "symbol_a", perllib.Array()) CGI.symbol_h = perllib.init_global("CGI", "symbol_h", perllib.Hash()) CGI.symbol_v = perllib.init_global("CGI", "symbol_v", "") CGI.type_v = perllib.init_global("CGI", "type_v", None) CRLF_v = "" MultipartBuffer.CRLF_v = perllib.init_global("MultipartBuffer", "CRLF_v", 0) MultipartBuffer.INITIAL_FILLUNIT_v = perllib.init_global( "MultipartBuffer", "INITIAL_FILLUNIT_v", 0 ) MultipartBuffer.SPIN_LOOP_MAX_v = perllib.init_global("MultipartBuffer", "SPIN_LOOP_MAX_v", 0) MultipartBuffer.TIMEOUT_v = perllib.init_global("MultipartBuffer", "TIMEOUT_v", 0) _args = perllib.Array() _d = None src_l = "" sym_v = None sys.argv = perllib.Array(sys.argv) builtins.__PACKAGE__ = "CGI" # SKIPPED: require 5.008001; # SKIPPED: use Carp 'croak'; appease_cpants_kwalitee = """ use strict; use warnings; #""" CGI.VERSION_v = "4.54" CGI.ascii2ebcdic = ascii2ebcdic CGI.ebcdic2ascii = ebcdic2ascii CGI.escape = escape CGI.expires = expires CGI.make_attributes = make_attributes CGI.rearrange = rearrange CGI.rearrange_header = rearrange_header CGI.unescape = unescape CGI._XHTML_DTD_v = perllib.Array( [ "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", ] ) for _ in range(1): try: _locals_stack.append(perllib.WARNING) perllib.WARNING = 0 CGI.TAINTED_v = f"{sys.argv[0]}{sys.executable}"[0:0] finally: perllib.WARNING = _locals_stack.pop() CGI.MOD_PERL_v = 0 # no mod_perl by default # global settings CGI.POST_MAX_v = -1 # no limit to uploaded files CGI.DISABLE_UPLOADS_v = 0 CGI.UNLINK_TMP_FILES_v = 1 CGI.LIST_CONTEXT_WARN_v = 1 CGI.ENCODE_ENTITIES_v = """&<>"'""" CGI.ALLOW_DELETE_CONTENT_v = 0 CGI.COOKIE_CACHE_v = 0 # backcompat: cache was broken for years CGI.SAVED_SYMBOLS_a = perllib.Array() initialize_globals() # FIGURE OUT THE OS WE'RE RUNNING UNDER # Some systems support the $^O variable. If not # available then require() the Config library if not CGI.OS_v: if not (perllib.assign_global("CGI", "OS_v", perllib.os_name())): import Config as _Config CGI.OS_v = Config.Config_h.get("osname") if re.search(re.compile(r"^MSWin", re.I), _str(CGI.OS_v)): CGI.OS_v = "WINDOWS" elif re.search(re.compile(r"^VMS", re.I), _str(CGI.OS_v)): CGI.OS_v = "VMS" elif re.search(re.compile(r"^dos", re.I), _str(CGI.OS_v)): CGI.OS_v = "DOS" elif re.search(re.compile(r"^MacOS", re.I), _str(CGI.OS_v)): CGI.OS_v = "MACINTOSH" elif re.search(re.compile(r"^os2", re.I), _str(CGI.OS_v)): CGI.OS_v = "OS2" elif re.search(re.compile(r"^epoc", re.I), _str(CGI.OS_v)): CGI.OS_v = "EPOC" elif re.search(re.compile(r"^cygwin", re.I), _str(CGI.OS_v)): CGI.OS_v = "CYGWIN" elif re.search(re.compile(r"^NetWare", re.I), _str(CGI.OS_v)): CGI.OS_v = "NETWARE" else: CGI.OS_v = "UNIX" # Some OS logic. Binary mode enabled on DOS, NT and VMS CGI.needs_binmode_v = ( _m := re.search(r"^(WINDOWS|DOS|OS2|MSWin|CYGWIN|NETWARE)", _str(CGI.OS_v)), _pb(_m), )[1] # This is the default class for the CGI object to use when all else fails. if CGI.DefaultClass_v is None: CGI.DefaultClass_v = "CGI" # The path separator is a slash, backslash or semicolon, depending # on the platform. CGI.SL_v = { "UNIX": "/", "OS2": "\\", "EPOC": "/", "CYGWIN": "/", "NETWARE": "/", "WINDOWS": "\\", "DOS": "\\", "MACINTOSH": ":", "VMS": "/", }[CGI.OS_v] # This no longer seems to be necessary # Turn on NPH scripts by default when running under IIS server! # $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/; if os.environ.get("SERVER_SOFTWARE") is not None and ( re.search(r"IIS", _str(os.environ.get("SERVER_SOFTWARE"))) ): CGI.IIS_v = perllib.num(CGI.IIS_v) + 1 # Turn on special checking for ActiveState's PerlEx if os.environ.get("GATEWAY_INTERFACE") is not None and ( re.search(r"^CGI-PerlEx", _str(os.environ.get("GATEWAY_INTERFACE"))) ): CGI.PERLEX_v = perllib.num(CGI.PERLEX_v) + 1 # Turn on special checking for Doug MacEachern's modperl # PerlEx::DBI tries to fool DBI by setting MOD_PERL if "MOD_PERL" in os.environ and not CGI.PERLEX_v: # mod_perl handlers may run system() on scripts using CGI.pm; # Make sure so we don't get fooled by inherited $ENV{MOD_PERL} if ( "MOD_PERL_API_VERSION" in os.environ and perllib.num(os.environ.get("MOD_PERL_API_VERSION")) == 2 ): CGI.MOD_PERL_v = 2 import Apache2.Response as _Apache2_Response import Apache2.RequestRec as _Apache2_RequestRec import Apache2.RequestUtil as _Apache2_RequestUtil import Apache2.RequestIO as _Apache2_RequestIO import APR.Pool as _APR_Pool else: CGI.MOD_PERL_v = 1 import Apache as _Apache # Define the CRLF sequence. I can't use a simple "\r\n" because the meaning # of "\n" is different on different OS's (sometimes it generates CRLF, sometimes LF # and sometimes CR). The most popular VMS web server # doesn't accept CRLF -- instead it wants a LR. EBCDIC machines don't # use ASCII, so \015\012 means something different. I find this all # really annoying. CGI.EBCDIC_v = _pb("\t" != "\011") if _str(CGI.OS_v) == "VMS": CGI.CRLF_v = "\n" elif CGI.EBCDIC_v: CGI.CRLF_v = "\r\n" else: CGI.CRLF_v = "\015\012" if CGI.needs_binmode_v: _set_binmode() CGI.EXPORT_TAGS_h = perllib.Hash( { ":html2": [ "h1", "h2", "h3", "h4", "h5", "h6", *"p br hr ol ul li dl dt dd menu code var strong em tt u i b blockquote pre img a address cite samp dfn html head base body Link nextid title meta kbd start_html end_html input Select option comment charset escapeHTML".split(), ], ":html3": "div table caption th td TR Tr sup Sub strike applet Param nobr embed basefont style span layer ilayer font frameset frame script small big Area Map".split(), ":html4": "abbr acronym bdo col colgroup del fieldset iframe ins label legend noframes noscript object optgroup Q thead tbody tfoot".split(), ":form": "textfield textarea filefield password_field hidden checkbox checkbox_group submit reset defaults radio_group popup_menu button autoEscape scrolling_list image_button start_form end_form start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART".split(), ":cgi": "param multi_param upload path_info path_translated request_uri url self_url script_name cookie Dump raw_cookie request_method query_string Accept user_agent remote_host content_type remote_addr referer server_name server_software server_port server_protocol virtual_port virtual_host remote_ident auth_type http append save_parameters restore_parameters param_fetch remote_user user_name header redirect import_names put Delete Delete_all url_param cgi_error env_query_string".split(), ":netscape": "blink fontsize center".split(), ":ssl": "https".split(), ":cgi-lib": "ReadParse PrintHeader HtmlTop HtmlBot SplitParam Vars".split(), ":push": "multipart_init multipart_start multipart_end multipart_final".split(), # bulk export/import ":html": ":html2 :html3 :html4 :netscape".split(), ":standard": ":html2 :html3 :html4 :form :cgi :ssl".split(), ":all": ":html2 :html3 :html4 :netscape :form :cgi :ssl :push".split(), } )
[docs]def new(*_args): old = None r_v = None [class_, *initializer] = perllib.list_of_at_least_n(_args, 1) initializer = perllib.Array(initializer) self = perllib.Hash() self = perllib.bless(self, perllib.ref_scalar(class_) or class_ or CGI.DefaultClass_v) # always use a tempfile self["use_tempfile"] = 1 if perllib.ref_scalar(initializer[0]) and ( perllib.isa(initializer[0], "Apache") or perllib.isa(initializer[0], "Apache2::RequestRec") ): self.r(initializer.pop(0) if initializer else None) if perllib.ref_scalar(initializer[0]) and (perllib.isa(initializer[0], "CODE")): self.upload_hook( (initializer.pop(0) if initializer else None), (initializer.pop(0) if initializer else None), ) if len(initializer) > 0: self["use_tempfile"] = initializer.pop(0) if initializer else None if CGI.MOD_PERL_v: if perllib.num(CGI.MOD_PERL_v) == 1: if not self.r(): self.r(Apache.request(Apache)) r_v = self.r() r_v.register_cleanup(CGI._reset_globals) if CGI.SAVED_SYMBOLS_a: self._setup_symbols(*CGI.SAVED_SYMBOLS_a) else: # XXX: once we have the new API # will do a real PerlOptions -SetupEnv check if not self.r(): self.r(Apache2.RequestUtil.request(Apache2.RequestUtil)) r_v = self.r() if not ("REQUEST_METHOD" in os.environ): r_v.subprocess_env() perllib.method_call(r_v.pool(), "cleanup_register", CGI._reset_globals) if CGI.SAVED_SYMBOLS_a: self._setup_symbols(*CGI.SAVED_SYMBOLS_a) CGI.NPH_v = None if CGI.PERLEX_v: self._reset_globals() self.init(*initializer) return self
CGI.new = types.MethodType(new, CGI) for tag_l in _all_html_tags(): def _f880(tag_l): def _f880template(*_args): nonlocal tag_l return _tag_func(tag_l, *_args) return _f880template setattr(CGI, tag_l, _f880(tag_l)) # start_html and end_html already exist as custom functions if tag_l == "html": continue for start_end in "start end".split(): start_end_function = f"{start_end}_{tag_l}" def _f887(start_end_function): def _f887template(*_args): nonlocal start_end_function return _tag_func(start_end_function, *_args) return _f887template setattr(CGI, start_end_function, _f887(start_end_function)) builtins.__PACKAGE__ = "CGI.MultipartBuffer" CGI.MultipartBuffer._DEBUG_v = 0 # how many bytes to read at a time. We use # a 4K buffer by default. MultipartBuffer.INITIAL_FILLUNIT_v = MultipartBuffer.INITIAL_FILLUNIT_v or 1024 * 4 MultipartBuffer.TIMEOUT_v = MultipartBuffer.TIMEOUT_v or 240 * 60 # 4 hour timeout for big files MultipartBuffer.SPIN_LOOP_MAX_v = ( MultipartBuffer.SPIN_LOOP_MAX_v or 2000 ) # bug fix for some Netscape servers MultipartBuffer.CRLF_v = MultipartBuffer.CRLF_v or CGI.CRLF_v CGI.MultipartBuffer.INITIAL_FILLUNIT_v = MultipartBuffer.INITIAL_FILLUNIT_v CGI.MultipartBuffer.TIMEOUT_v = MultipartBuffer.TIMEOUT_v CGI.MultipartBuffer.SPIN_LOOP_MAX_v = MultipartBuffer.SPIN_LOOP_MAX_v CGI.MultipartBuffer.CRLF_v = MultipartBuffer.CRLF_v builtins.__PACKAGE__ = "CGI" # We get a whole bunch of warnings about "possibly uninitialized variables" # when running with the -w switch. Touch them all once to get rid of the # warnings. This is ugly and I hate it. if perllib.WARNING: CGI.CGI_v = "" CGI.CGI_v = f""" {_bn(CGI.VERSION_v)}; {_bn(CGI.MultipartBuffer.SPIN_LOOP_MAX_v)}; {_bn(CGI.MultipartBuffer.CRLF_v)}; {_bn(CGI.MultipartBuffer.TIMEOUT_v)}; {_bn(CGI.MultipartBuffer.INITIAL_FILLUNIT_v)}; """