This file is indexed.

/usr/share/pyshared/zope/server/http/httptask.py is in python-zope.server 3.8.6-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""HTTP Task

An HTTP task that can execute an HTTP request with the help of the channel and
the server it belongs to.
"""
import socket
import time

from zope.server.http.http_date import build_http_date
from zope.publisher.interfaces.http import IHeaderOutput
from zope.server.interfaces import ITask

from zope.interface import implements

rename_headers = {
    'CONTENT_LENGTH' : 'CONTENT_LENGTH',
    'CONTENT_TYPE'   : 'CONTENT_TYPE',
    'CONNECTION'     : 'CONNECTION_TYPE',
    }

class HTTPTask(object):
    """An HTTP task accepts a request and writes to a channel.

       Subclass this and override the execute() method.
    """

    implements(ITask, IHeaderOutput)  #, IOutputStream

    instream = None
    close_on_finish = 1
    status = '200'
    reason = 'OK'
    wrote_header = 0
    accumulated_headers = None
    bytes_written = 0
    auth_user_name = ''
    cgi_env = None

    def __init__(self, channel, request_data):
        self.channel = channel
        self.request_data = request_data
        self.response_headers = {}
        version = request_data.version
        if version not in ('1.0', '1.1'):
            # fall back to a version we support.
            version = '1.0'
        self.version = version

    def service(self):
        """See zope.server.interfaces.ITask"""
        try:
            try:
                self.start()
                self.channel.server.executeRequest(self)
                self.finish()
            except socket.error:
                self.close_on_finish = 1
                if self.channel.adj.log_socket_errors:
                    raise
        finally:
            if self.close_on_finish:
                self.channel.close_when_done()

    def cancel(self):
        """See zope.server.interfaces.ITask"""
        self.channel.close_when_done()

    def defer(self):
        """See zope.server.interfaces.ITask"""
        pass

    def setResponseStatus(self, status, reason):
        """See zope.publisher.interfaces.http.IHeaderOutput"""
        self.status = status
        self.reason = reason

    def setResponseHeaders(self, mapping):
        """See zope.publisher.interfaces.http.IHeaderOutput"""
        self.response_headers.update(mapping)

    def appendResponseHeaders(self, lst):
        """See zope.publisher.interfaces.http.IHeaderOutput"""
        accum = self.accumulated_headers
        if accum is None:
            self.accumulated_headers = accum = []
        accum.extend(lst)

    def wroteResponseHeader(self):
        """See zope.publisher.interfaces.http.IHeaderOutput"""
        return self.wrote_header

    def setAuthUserName(self, name):
        """See zope.publisher.interfaces.http.IHeaderOutput"""
        self.auth_user_name = name

    def prepareResponseHeaders(self):
        version = self.version
        # Figure out whether the connection should be closed.
        connection = self.request_data.headers.get('CONNECTION', '').lower()
        close_it = 0
        response_headers = self.response_headers
        accumulated_headers = self.accumulated_headers
        if accumulated_headers is None:
            accumulated_headers = []

        if version == '1.0':
            if connection == 'keep-alive':
                if not ('Content-Length' in response_headers):
                    close_it = 1
                else:
                    response_headers['Connection'] = 'Keep-Alive'
            else:
                close_it = 1
        elif version == '1.1':
            if 'connection: close' in (header.lower() for header in
                accumulated_headers):
                close_it = 1
            if connection == 'close':
                close_it = 1
            elif 'Transfer-Encoding' in response_headers:
                if not response_headers['Transfer-Encoding'] == 'chunked':
                    close_it = 1
            elif self.status == '304':
                # Replying with headers only.
                pass
            elif not ('Content-Length' in response_headers):
                # accumulated_headers is a simple list, we need to cut off
                # the value of content-length manually
                if 'content-length' not in (header[:14].lower() for header in
                    accumulated_headers):
                    close_it = 1
            # under HTTP 1.1 keep-alive is default, no need to set the header
        else:
            # Close if unrecognized HTTP version.
            close_it = 1

        self.close_on_finish = close_it
        if close_it:
            self.response_headers['Connection'] = 'close'

        # Set the Server and Date field, if not yet specified. This is needed
        # if the server is used as a proxy.
        if 'server' not in (header[:6].lower() for header in
                            accumulated_headers):
            self.response_headers['Server'] = self.channel.server.SERVER_IDENT
        else:
            self.response_headers['Via'] = self.channel.server.SERVER_IDENT
        if 'date' not in (header[:4].lower() for header in
                            accumulated_headers):
            self.response_headers['Date'] = build_http_date(self.start_time)


    def buildResponseHeader(self):
        self.prepareResponseHeaders()
        first_line = 'HTTP/%s %s %s' % (self.version, self.status, self.reason)
        lines = [first_line] + ['%s: %s' % hv
                                for hv in self.response_headers.items()]
        accum = self.accumulated_headers
        if accum is not None:
            lines.extend(accum)
        res = '%s\r\n\r\n' % '\r\n'.join(lines)
        return res

    def getCGIEnvironment(self):
        """Returns a CGI-like environment."""
        env = self.cgi_env
        if env is not None:
            # Return the cached copy.
            return env

        request_data = self.request_data
        path = request_data.path
        channel = self.channel
        server = channel.server

        while path and path.startswith('/'):
            path = path[1:]

        env = {}
        env['REQUEST_METHOD'] = request_data.command.upper()
        env['SERVER_PORT'] = str(server.port)
        env['SERVER_NAME'] = server.server_name
        env['SERVER_SOFTWARE'] = server.SERVER_IDENT
        env['SERVER_PROTOCOL'] = "HTTP/%s" % self.version
        env['CHANNEL_CREATION_TIME'] = channel.creation_time
        env['SCRIPT_NAME']=''
        env['PATH_INFO']='/' + path
        query = request_data.query
        if query:
            env['QUERY_STRING'] = query
        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
        addr = channel.addr[0]
        env['REMOTE_ADDR'] = addr

        # If the server has a resolver, try to get the
        # remote host from the resolver's cache.
        resolver = getattr(server, 'resolver', None)
        if resolver is not None:
            dns_cache = resolver.cache
            if addr in dns_cache:
                remote_host = dns_cache[addr][2]
                if remote_host is not None:
                    env['REMOTE_HOST'] = remote_host

        env_has = env.has_key

        for key, value in request_data.headers.items():
            value = value.strip()
            mykey = rename_headers.get(key, None)
            if mykey is None:
                mykey = 'HTTP_%s' % key
            if not env_has(mykey):
                env[mykey] = value

        self.cgi_env = env
        return env

    def start(self):
        now = time.time()
        self.start_time = now

    def finish(self):
        if not self.wrote_header:
            self.write('')
        hit_log = self.channel.server.hit_log
        if hit_log is not None:
            hit_log.log(self)

    def write(self, data):
        channel = self.channel
        if not self.wrote_header:
            rh = self.buildResponseHeader()
            channel.write(rh)
            self.bytes_written += len(rh)
            self.wrote_header = 1
        if data:
            self.bytes_written += channel.write(data)

    def flush(self):
        self.channel.flush()