mercurial/hgweb/request.py
author Gregory Szorc <gregory.szorc@gmail.com>
Thu, 08 Mar 2018 11:21:46 -0800
changeset 36809 3c15b84ab66c
parent 36808 0031e972ded2
child 36811 cfb9ef24968c
permissions -rw-r--r--
hgweb: teach WSGI parser about query strings Currently, req.form uses cgi.parse() to populate form data. Depending on the request, form data can come from POST multipart/form-data, application/x-www-form-urlencoded, or the URL query string. Putting all these things into one data structure makes it difficult to reason about how exactly parameters got to the request. It can lead to wonkiness such as pulling parameters from both the URL and POST data. This commit teaches our WSGI request parser about argument data in query strings. We populate fields containing the query string data and only the query string data so it can't be confused with POST data. Differential Revision: https://phab.mercurial-scm.org/D2737
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2391
d351a3be3371 Fixing up comment headers for split up code.
Eric Hopper <hopper@omnifarious.org>
parents: 2355
diff changeset
     1
# hgweb/request.py - An http request from either CGI or the standalone server.
131
c9d51742471c moving hgweb to mercurial subdir
jake@edge2.net
parents:
diff changeset
     2
#
238
3b92f8fe47ae hgweb.py: kill #! line, clean up copyright notice
mpm@selenic.com
parents: 222
diff changeset
     3
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2859
345bac2bc4ec update copyrights.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2535
diff changeset
     4
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
131
c9d51742471c moving hgweb to mercurial subdir
jake@edge2.net
parents:
diff changeset
     5
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7742
diff changeset
     6
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 10261
diff changeset
     7
# GNU General Public License version 2 or any later version.
131
c9d51742471c moving hgweb to mercurial subdir
jake@edge2.net
parents:
diff changeset
     8
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
     9
from __future__ import absolute_import
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    10
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    11
import cgi
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    12
import errno
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    13
import socket
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    14
#import wsgiref.validate
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    15
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    16
from .common import (
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    17
    ErrorResponse,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    18
    HTTP_NOT_MODIFIED,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    19
    statusmessage,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    20
)
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    21
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    22
from ..thirdparty import (
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    23
    attr,
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    24
)
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    25
from .. import (
34514
528b21b853aa request: coerce content-type to native str
Augie Fackler <augie@google.com>
parents: 34513
diff changeset
    26
    pycompat,
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    27
    util,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26846
diff changeset
    28
)
138
c77a679e9cfa Revamped templated hgweb
mpm@selenic.com
parents: 137
diff changeset
    29
6774
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    30
shortcuts = {
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    31
    'cl': [('cmd', ['changelog']), ('rev', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    32
    'sl': [('cmd', ['shortlog']), ('rev', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    33
    'cs': [('cmd', ['changeset']), ('node', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    34
    'f': [('cmd', ['file']), ('filenode', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    35
    'fl': [('cmd', ['filelog']), ('filenode', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    36
    'fd': [('cmd', ['filediff']), ('node', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    37
    'fa': [('cmd', ['annotate']), ('filenode', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    38
    'mf': [('cmd', ['manifest']), ('manifest', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    39
    'ca': [('cmd', ['archive']), ('node', None)],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    40
    'tags': [('cmd', ['tags'])],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    41
    'tip': [('cmd', ['changeset']), ('node', ['tip'])],
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    42
    'static': [('cmd', ['static']), ('file', None)]
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    43
}
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    44
10261
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
    45
def normalize(form):
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
    46
    # first expand the shortcuts
34513
34fcb0f66837 request: use trivial iterator over dictionary keys
Augie Fackler <augie@google.com>
parents: 34512
diff changeset
    47
    for k in shortcuts:
6774
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    48
        if k in form:
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    49
            for name, value in shortcuts[k]:
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    50
                if value is None:
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    51
                    value = form[k]
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    52
                form[name] = value
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    53
            del form[k]
10261
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
    54
    # And strip the values
36713
2442927cdd96 hgweb: convert req.form to bytes for all keys and values
Augie Fackler <augie@google.com>
parents: 36258
diff changeset
    55
    bytesform = {}
10261
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
    56
    for k, v in form.iteritems():
36713
2442927cdd96 hgweb: convert req.form to bytes for all keys and values
Augie Fackler <augie@google.com>
parents: 36258
diff changeset
    57
        bytesform[pycompat.bytesurl(k)] = [
2442927cdd96 hgweb: convert req.form to bytes for all keys and values
Augie Fackler <augie@google.com>
parents: 36258
diff changeset
    58
            pycompat.bytesurl(i.strip()) for i in v]
2442927cdd96 hgweb: convert req.form to bytes for all keys and values
Augie Fackler <augie@google.com>
parents: 36258
diff changeset
    59
    return bytesform
6774
0dbb56e90a71 hgweb: move shortcut expansion to request instantiation
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6212
diff changeset
    60
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    61
@attr.s(frozen=True)
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    62
class parsedrequest(object):
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    63
    """Represents a parsed WSGI request / static HTTP request parameters."""
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    64
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    65
    # Full URL for this request.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    66
    url = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    67
    # URL without any path components. Just <proto>://<host><port>.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    68
    baseurl = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    69
    # Advertised URL. Like ``url`` and ``baseurl`` but uses SERVER_NAME instead
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    70
    # of HTTP: Host header for hostname. This is likely what clients used.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    71
    advertisedurl = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    72
    advertisedbaseurl = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    73
    # WSGI application path.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    74
    apppath = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    75
    # List of path parts to be used for dispatch.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    76
    dispatchparts = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    77
    # URL path component (no query string) used for dispatch.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    78
    dispatchpath = attr.ib()
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    79
    # Raw query string (part after "?" in URL).
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    80
    querystring = attr.ib()
36809
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
    81
    # List of 2-tuples of query string arguments.
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
    82
    querystringlist = attr.ib()
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
    83
    # Dict of query string arguments. Values are lists with at least 1 item.
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
    84
    querystringdict = attr.ib()
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    85
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    86
def parserequestfromenv(env):
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    87
    """Parse URL components from environment variables.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    88
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    89
    WSGI defines request attributes via environment variables. This function
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    90
    parses the environment variables into a data structure.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    91
    """
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    92
    # PEP-0333 defines the WSGI spec and is a useful reference for this code.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    93
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    94
    # We first validate that the incoming object conforms with the WSGI spec.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    95
    # We only want to be dealing with spec-conforming WSGI implementations.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    96
    # TODO enable this once we fix internal violations.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    97
    #wsgiref.validate.check_environ(env)
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    98
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
    99
    # PEP-0333 states that environment keys and values are native strings
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   100
    # (bytes on Python 2 and str on Python 3). The code points for the Unicode
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   101
    # strings on Python 3 must be between \00000-\000FF. We deal with bytes
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   102
    # in Mercurial, so mass convert string keys and values to bytes.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   103
    if pycompat.ispy3:
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   104
        env = {k.encode('latin-1'): v for k, v in env.iteritems()}
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   105
        env = {k: v.encode('latin-1') if isinstance(v, str) else v
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   106
               for k, v in env.iteritems()}
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   107
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   108
    # https://www.python.org/dev/peps/pep-0333/#environ-variables defines
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   109
    # the environment variables.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   110
    # https://www.python.org/dev/peps/pep-0333/#url-reconstruction defines
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   111
    # how URLs are reconstructed.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   112
    fullurl = env['wsgi.url_scheme'] + '://'
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   113
    advertisedfullurl = fullurl
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   114
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   115
    def addport(s):
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   116
        if env['wsgi.url_scheme'] == 'https':
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   117
            if env['SERVER_PORT'] != '443':
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   118
                s += ':' + env['SERVER_PORT']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   119
        else:
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   120
            if env['SERVER_PORT'] != '80':
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   121
                s += ':' + env['SERVER_PORT']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   122
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   123
        return s
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   124
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   125
    if env.get('HTTP_HOST'):
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   126
        fullurl += env['HTTP_HOST']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   127
    else:
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   128
        fullurl += env['SERVER_NAME']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   129
        fullurl = addport(fullurl)
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   130
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   131
    advertisedfullurl += env['SERVER_NAME']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   132
    advertisedfullurl = addport(advertisedfullurl)
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   133
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   134
    baseurl = fullurl
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   135
    advertisedbaseurl = advertisedfullurl
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   136
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   137
    fullurl += util.urlreq.quote(env.get('SCRIPT_NAME', ''))
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   138
    advertisedfullurl += util.urlreq.quote(env.get('SCRIPT_NAME', ''))
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   139
    fullurl += util.urlreq.quote(env.get('PATH_INFO', ''))
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   140
    advertisedfullurl += util.urlreq.quote(env.get('PATH_INFO', ''))
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   141
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   142
    if env.get('QUERY_STRING'):
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   143
        fullurl += '?' + env['QUERY_STRING']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   144
        advertisedfullurl += '?' + env['QUERY_STRING']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   145
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   146
    # When dispatching requests, we look at the URL components (PATH_INFO
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   147
    # and QUERY_STRING) after the application root (SCRIPT_NAME). But hgwebdir
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   148
    # has the concept of "virtual" repositories. This is defined via REPO_NAME.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   149
    # If REPO_NAME is defined, we append it to SCRIPT_NAME to form a new app
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   150
    # root. We also exclude its path components from PATH_INFO when resolving
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   151
    # the dispatch path.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   152
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   153
    apppath = env['SCRIPT_NAME']
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   154
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   155
    if env.get('REPO_NAME'):
36808
0031e972ded2 hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36806
diff changeset
   156
        if not apppath.endswith('/'):
0031e972ded2 hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36806
diff changeset
   157
            apppath += '/'
0031e972ded2 hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36806
diff changeset
   158
0031e972ded2 hgweb: use the parsed application path directly
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36806
diff changeset
   159
        apppath += env.get('REPO_NAME')
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   160
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   161
    if 'PATH_INFO' in env:
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   162
        dispatchparts = env['PATH_INFO'].strip('/').split('/')
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   163
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   164
        # Strip out repo parts.
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   165
        repoparts = env.get('REPO_NAME', '').split('/')
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   166
        if dispatchparts[:len(repoparts)] == repoparts:
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   167
            dispatchparts = dispatchparts[len(repoparts):]
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   168
    else:
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   169
        dispatchparts = []
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   170
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   171
    dispatchpath = '/'.join(dispatchparts)
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   172
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   173
    querystring = env.get('QUERY_STRING', '')
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   174
36809
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   175
    # We store as a list so we have ordering information. We also store as
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   176
    # a dict to facilitate fast lookup.
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   177
    querystringlist = util.urlreq.parseqsl(querystring, keep_blank_values=True)
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   178
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   179
    querystringdict = {}
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   180
    for k, v in querystringlist:
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   181
        if k in querystringdict:
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   182
            querystringdict[k].append(v)
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   183
        else:
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   184
            querystringdict[k] = [v]
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   185
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   186
    return parsedrequest(url=fullurl, baseurl=baseurl,
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   187
                         advertisedurl=advertisedfullurl,
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   188
                         advertisedbaseurl=advertisedbaseurl,
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   189
                         apppath=apppath,
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   190
                         dispatchparts=dispatchparts, dispatchpath=dispatchpath,
36809
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   191
                         querystring=querystring,
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   192
                         querystringlist=querystringlist,
3c15b84ab66c hgweb: teach WSGI parser about query strings
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36808
diff changeset
   193
                         querystringdict=querystringdict)
36806
69b2d0900cd7 hgweb: parse WSGI request into a data structure
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36713
diff changeset
   194
5566
d74fc8dec2b4 Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5563
diff changeset
   195
class wsgirequest(object):
26132
9df8c729e2e7 hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
   196
    """Higher-level API for a WSGI request.
9df8c729e2e7 hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
   197
9df8c729e2e7 hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
   198
    WSGI applications are invoked with 2 arguments. They are used to
9df8c729e2e7 hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
   199
    instantiate instances of this class, which provides higher-level APIs
9df8c729e2e7 hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
   200
    for obtaining request parameters, writing HTTP output, etc.
9df8c729e2e7 hgweb: add some documentation
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
   201
    """
5566
d74fc8dec2b4 Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5563
diff changeset
   202
    def __init__(self, wsgienv, start_response):
34512
482d6f6dba91 hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   203
        version = wsgienv[r'wsgi.version']
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2859
diff changeset
   204
        if (version < (1, 0)) or (version >= (2, 0)):
4633
ff7253a0d1da Cleanup of whitespace, indentation and line continuation.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4250
diff changeset
   205
            raise RuntimeError("Unknown and unsupported WSGI version %d.%d"
2506
d0db3462d568 This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents: 2466
diff changeset
   206
                               % version)
34512
482d6f6dba91 hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   207
        self.inp = wsgienv[r'wsgi.input']
482d6f6dba91 hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   208
        self.err = wsgienv[r'wsgi.errors']
482d6f6dba91 hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   209
        self.threaded = wsgienv[r'wsgi.multithread']
482d6f6dba91 hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   210
        self.multiprocess = wsgienv[r'wsgi.multiprocess']
482d6f6dba91 hgweb: when constructing or adding to a wsgi environ dict, use native strs
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   211
        self.run_once = wsgienv[r'wsgi.run_once']
2506
d0db3462d568 This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents: 2466
diff changeset
   212
        self.env = wsgienv
10261
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
   213
        self.form = normalize(cgi.parse(self.inp,
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
   214
                                        self.env,
5eae671c0b57 hgweb: request: strip() form values
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9694
diff changeset
   215
                                        keep_blank_values=1))
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   216
        self._start_response = start_response
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5930
diff changeset
   217
        self.server_write = None
2506
d0db3462d568 This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents: 2466
diff changeset
   218
        self.headers = []
d0db3462d568 This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents: 2466
diff changeset
   219
d0db3462d568 This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents: 2466
diff changeset
   220
    def __iter__(self):
d0db3462d568 This patch make several WSGI related alterations.
Eric Hopper <hopper@omnifarious.org>
parents: 2466
diff changeset
   221
        return iter([])
131
c9d51742471c moving hgweb to mercurial subdir
jake@edge2.net
parents:
diff changeset
   222
2464
09b1c9ef317c push over http: server support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2434
diff changeset
   223
    def read(self, count=-1):
09b1c9ef317c push over http: server support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2434
diff changeset
   224
        return self.inp.read(count)
09b1c9ef317c push over http: server support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2434
diff changeset
   225
7180
a42d27bc809d hgweb: be sure to drain request data even in early error conditions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6774
diff changeset
   226
    def drain(self):
a42d27bc809d hgweb: be sure to drain request data even in early error conditions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6774
diff changeset
   227
        '''need to read all data from request, httplib is half-duplex'''
13600
bcc59cb3714d hgweb: pmezard thinks one default is enough
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 13598
diff changeset
   228
        length = int(self.env.get('CONTENT_LENGTH') or 0)
7180
a42d27bc809d hgweb: be sure to drain request data even in early error conditions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6774
diff changeset
   229
        for s in util.filechunkiter(self.inp, limit=length):
a42d27bc809d hgweb: be sure to drain request data even in early error conditions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6774
diff changeset
   230
            pass
a42d27bc809d hgweb: be sure to drain request data even in early error conditions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6774
diff changeset
   231
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18351
diff changeset
   232
    def respond(self, status, type, filename=None, body=None):
34514
528b21b853aa request: coerce content-type to native str
Augie Fackler <augie@google.com>
parents: 34513
diff changeset
   233
        if not isinstance(type, str):
528b21b853aa request: coerce content-type to native str
Augie Fackler <augie@google.com>
parents: 34513
diff changeset
   234
            type = pycompat.sysstr(type)
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   235
        if self._start_response is not None:
34722
95be8928d6b2 hgweb: fill in content-type and content-length as native strings
Augie Fackler <augie@google.com>
parents: 34514
diff changeset
   236
            self.headers.append((r'Content-Type', type))
18348
764a758780b6 hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents: 18347
diff changeset
   237
            if filename:
26846
7c1b4840c2cd hgweb: replace some str.split() calls by str.partition() or str.rpartition()
Anton Shestakov <av6@dwimlabs.net>
parents: 26200
diff changeset
   238
                filename = (filename.rpartition('/')[-1]
18348
764a758780b6 hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents: 18347
diff changeset
   239
                            .replace('\\', '\\\\').replace('"', '\\"'))
764a758780b6 hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents: 18347
diff changeset
   240
                self.headers.append(('Content-Disposition',
764a758780b6 hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents: 18347
diff changeset
   241
                                     'inline; filename="%s"' % filename))
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18351
diff changeset
   242
            if body is not None:
34722
95be8928d6b2 hgweb: fill in content-type and content-length as native strings
Augie Fackler <augie@google.com>
parents: 34514
diff changeset
   243
                self.headers.append((r'Content-Length', str(len(body))))
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   244
5926
15ef6b9c1f2f hgweb: be sure to send a valid content-type for raw files
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5922
diff changeset
   245
            for k, v in self.headers:
15ef6b9c1f2f hgweb: be sure to send a valid content-type for raw files
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5922
diff changeset
   246
                if not isinstance(v, str):
18348
764a758780b6 hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents: 18347
diff changeset
   247
                    raise TypeError('header value must be string: %r' % (v,))
5926
15ef6b9c1f2f hgweb: be sure to send a valid content-type for raw files
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5922
diff changeset
   248
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   249
            if isinstance(status, ErrorResponse):
18348
764a758780b6 hgweb: simplify wsgirequest header handling
Mads Kiilerich <mads@kiilerich.com>
parents: 18347
diff changeset
   250
                self.headers.extend(status.headers)
12739
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   251
                if status.code == HTTP_NOT_MODIFIED:
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   252
                    # RFC 2616 Section 10.3.5: 304 Not Modified has cases where
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   253
                    # it MUST NOT include any headers other than these and no
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   254
                    # body
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   255
                    self.headers = [(k, v) for (k, v) in self.headers if
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   256
                                    k in ('Date', 'ETag', 'Expires',
8dcd3203a261 hgweb: don't send a body or illegal headers during 304 response
Augie Fackler <durin42@gmail.com>
parents: 10263
diff changeset
   257
                                          'Cache-Control', 'Vary')]
36255
a0a004b29a51 hgweb: correctly bytes-ify status, not string-ify
Augie Fackler <augie@google.com>
parents: 34722
diff changeset
   258
                status = statusmessage(status.code, pycompat.bytestr(status))
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5930
diff changeset
   259
            elif status == 200:
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5930
diff changeset
   260
                status = '200 Script output follows'
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   261
            elif isinstance(status, int):
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   262
                status = statusmessage(status)
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   263
36258
af0a19d8812b py3: get bytes-repr of network errors portably
Augie Fackler <augie@google.com>
parents: 36255
diff changeset
   264
            self.server_write = self._start_response(
af0a19d8812b py3: get bytes-repr of network errors portably
Augie Fackler <augie@google.com>
parents: 36255
diff changeset
   265
                pycompat.sysstr(status), self.headers)
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   266
            self._start_response = None
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   267
            self.headers = []
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18351
diff changeset
   268
        if body is not None:
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18351
diff changeset
   269
            self.write(body)
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18351
diff changeset
   270
            self.server_write = None
5888
956afc025c0f hgweb: separate out start_response() calling
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5887
diff changeset
   271
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5930
diff changeset
   272
    def write(self, thing):
18351
3fbdbeab38cc hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents: 18350
diff changeset
   273
        if thing:
3fbdbeab38cc hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents: 18350
diff changeset
   274
            try:
3fbdbeab38cc hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents: 18350
diff changeset
   275
                self.server_write(thing)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 18352
diff changeset
   276
            except socket.error as inst:
18351
3fbdbeab38cc hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents: 18350
diff changeset
   277
                if inst[0] != errno.ECONNRESET:
3fbdbeab38cc hgweb: don't pass empty response chunks on
Mads Kiilerich <mads@kiilerich.com>
parents: 18350
diff changeset
   278
                    raise
1159
b6f5a947e62e Change use of global sys.stdout, sys.stdin os.environ to a hgrequest object.
Vincent Wagelaar <vincent@ricardis.tudelft.nl>
parents: 1143
diff changeset
   279
4246
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   280
    def writelines(self, lines):
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   281
        for line in lines:
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   282
            self.write(line)
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   283
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   284
    def flush(self):
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   285
        return None
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   286
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   287
    def close(self):
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   288
        return None
cc81c512a531 avoid _wsgioutputfile <-> _wsgirequest circular reference
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3673
diff changeset
   289
5566
d74fc8dec2b4 Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5563
diff changeset
   290
def wsgiapplication(app_maker):
5887
41a3fce17625 hgweb: return iterable, add deprecation note
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5886
diff changeset
   291
    '''For compatibility with old CGI scripts. A plain hgweb() or hgwebdir()
41a3fce17625 hgweb: return iterable, add deprecation note
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5886
diff changeset
   292
    can and should now be used as a WSGI application.'''
5760
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5566
diff changeset
   293
    application = app_maker()
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5566
diff changeset
   294
    def run_wsgi(env, respond):
5887
41a3fce17625 hgweb: return iterable, add deprecation note
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5886
diff changeset
   295
        return application(env, respond)
5760
0145f9afb0e7 Removed tabs and trailing whitespace in python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5566
diff changeset
   296
    return run_wsgi