mercurial/hgweb/wsgicgi.py
author Mads Kiilerich <madski@unity3d.com>
Wed, 31 Dec 2014 14:46:02 +0100
branchstable
changeset 23695 997a96cf6344
parent 18552 e8efcc8ff5c0
child 27046 37fcfe52c68c
permissions -rw-r--r--
largefiles: mark lfile as added in lfdirstate when the standin is added This is an alternative solution to the problem addressed by f72d73937853. This implementation has the advantage that it doesn't mark clean largefiles as normallookup. We can thus avoid repeated rehashing of all largefiles when f72d73937853 is backed out. This implementation use the existing 'lfmr' actions that 23fe278bde43 introduced for handling another part of the same cases.

# hgweb/wsgicgi.py - CGI->WSGI translator
#
# Copyright 2006 Eric Hopper <hopper@omnifarious.org>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
#
# This was originally copied from the public domain code at
# http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side

import os, sys
from mercurial import util
from mercurial.hgweb import common

def launch(application):
    util.setbinary(sys.stdin)
    util.setbinary(sys.stdout)

    environ = dict(os.environ.iteritems())
    environ.setdefault('PATH_INFO', '')
    if environ.get('SERVER_SOFTWARE', '').startswith('Microsoft-IIS'):
        # IIS includes script_name in PATH_INFO
        scriptname = environ['SCRIPT_NAME']
        if environ['PATH_INFO'].startswith(scriptname):
            environ['PATH_INFO'] = environ['PATH_INFO'][len(scriptname):]

    stdin = sys.stdin
    if environ.get('HTTP_EXPECT', '').lower() == '100-continue':
        stdin = common.continuereader(stdin, sys.stdout.write)

    environ['wsgi.input'] = stdin
    environ['wsgi.errors'] = sys.stderr
    environ['wsgi.version'] = (1, 0)
    environ['wsgi.multithread'] = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once'] = True

    if environ.get('HTTPS', 'off').lower() in ('on', '1', 'yes'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'

    headers_set = []
    headers_sent = []
    out = sys.stdout

    def write(data):
        if not headers_set:
            raise AssertionError("write() before start_response()")

        elif not headers_sent:
            # Before the first output, send the stored headers
            status, response_headers = headers_sent[:] = headers_set
            out.write('Status: %s\r\n' % status)
            for header in response_headers:
                out.write('%s: %s\r\n' % header)
            out.write('\r\n')

        out.write(data)
        out.flush()

    def start_response(status, response_headers, exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0](exc_info[1], exc_info[2])
            finally:
                exc_info = None     # avoid dangling circular ref
        elif headers_set:
            raise AssertionError("Headers already set!")

        headers_set[:] = [status, response_headers]
        return write

    content = application(environ, start_response)
    try:
        for chunk in content:
            write(chunk)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        getattr(content, 'close', lambda : None)()