X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/chopwood/blobdiff_plain/acd737d82202ac7874a03568b72f9b680244bfb9..76ee7d4f64bc1f20013f44c8045cd708ef0b9641:/cgi.py diff --git a/cgi.py b/cgi.py index b25d2d2..6006062 100644 --- a/cgi.py +++ b/cgi.py @@ -115,7 +115,7 @@ class HTTPOutput (O.FileOutput): """ Print a header, if none has yet been printed. - Keyword arguments can be passed to emit HTTP headers: see `http_header' + Keyword arguments can be passed to emit HTTP headers: see `http_headers' for the formatting rules. """ if me.headerp: return @@ -123,6 +123,8 @@ class HTTPOutput (O.FileOutput): for h in O.http_headers(content_type = content_type, **kw): me.writeln(h) me.writeln('') + if METHOD == 'HEAD': + HEADER_DONE() def cookie(name, value, **kw): """ @@ -238,6 +240,29 @@ class FormatHTML (F.SimpleFormatOperation): else: return htmlescape(arg) FORMATOPS['H'] = FormatHTML +class FormatWrap (F.BaseFormatOperation): + """ + ~<...~@>: wrap enclosed material in another formatting control string. + + The argument is a formatting control. The enclosed material is split into + pieces separated by `~;' markers. The formatting control is performed, and + passed the list of pieces (as compiled formatting operations) in the + keyword argument `wrapped'. + """ + def __init__(me, *args): + super(FormatWrap, me).__init__(*args) + pieces = [] + while True: + piece, delim = F.collect_subformat('>;') + pieces.append(piece) + if delim.char == '>': break + me.pieces = pieces + def _format(me, atp, colonp): + op = F.compile(me.getarg.get()) + with F.FORMAT.bind(argmap = dict(F.FORMAT.argmap, wrapped = me.pieces)): + op.format() +FORMATOPS['<'] = FormatWrap + def format_tmpl(control, **kw): with F.COMPILE.bind(opmaps = [FORMATOPS, F.BASEOPS]): with tmplkw(**kw): @@ -288,12 +313,14 @@ def cgi_errors(hook = None): ### CGI input. ## Lots of global variables to be filled in by `cgiparse'. +METHOD = None COOKIE = {} SPECIAL = {} PARAM = [] PARAMDICT = {} PATH = [] SSLP = False +HEADER_DONE = lambda: None ## Regular expressions for splitting apart query and cookie strings. R_QSPLIT = RX.compile('[;&]') @@ -354,34 +381,35 @@ def cgiparse(): True if the client connection is carried over SSL or TLS. """ - global SSLP + global METHOD, SSLP def getenv(var): try: return ENV[var] except KeyError: raise U.ExpectedError, (500, "No `%s' supplied" % var) ## Yes, we want the request method. - method = getenv('REQUEST_METHOD') + METHOD = getenv('REQUEST_METHOD') ## Acquire the query string. - if method == 'GET': + if METHOD in ['GET', 'HEAD']: q = getenv('QUERY_STRING') - elif method == 'POST': + elif METHOD == 'POST': ## We must read the query string from stdin. n = getenv('CONTENT_LENGTH') if not n.isdigit(): raise U.ExpectedError, (500, "Invalid CONTENT_LENGTH") n = int(n, 10) - if getenv('CONTENT_TYPE') != 'application/x-www-form-urlencoded': + ct = getenv('CONTENT_TYPE') + if ct != 'application/x-www-form-urlencoded': raise U.ExpectedError, (500, "Unexpected content type `%s'" % ct) q = SYS.stdin.read(n) if len(q) != n: raise U.ExpectedError, (500, "Failed to read correct length") else: - raise U.ExpectedError, (500, "Unexpected request method `%s'" % method) + raise U.ExpectedError, (500, "Unexpected request method `%s'" % METHOD) ## Populate the `SPECIAL', `PARAM' and `PARAMDICT' tables. seen = set() @@ -441,6 +469,8 @@ class Subcommand (SC.Subcommand): the list of path elements is non-empty. """ + global HEADER_DONE + ## We're going to make a pass over the supplied parameters, and we'll ## check them off against the formal parameters as we go; so we'll need ## to be able to look them up. We'll also keep track of the ones we've