Exemple #1
0
    def readLocalContent(self, code, reason, data={}):
        filename = os.path.normpath(os.path.join(self.location, reason))
        if not filename.startswith(self.location + os.path.sep):
            filename = ''

        if os.path.isfile(filename):
            try:
                with open(filename) as fd:
                    body = fd.read() % data

                # NOTE: we are always returning an HTTP/1.1 response
                content = 'close', http(code, body)
            except IOError:
                self.log.debug('local file is missing for %s: %s' %
                               (str(reason), str(filename)))
                # NOTE: we are always returning an HTTP/1.1 response
                content = 'close', http(
                    501, 'could not serve missing file  %s' % str(reason))
        else:
            self.log.debug('local file is missing for %s: %s' %
                           (str(reason), str(filename)))
            # NOTE: we are always returning an HTTP/1.1 response
            content = 'close', http(
                501, 'could not serve missing file  %s' % str(reason))

        return content
Exemple #2
0
    def doHTTPOptions(self, client_id, peer, message):
        # NOTE: we are always returning an HTTP/1.1 response
        method = message.request.method

        if message.headers.get('max-forwards', ''):
            max_forwards = message.headers.get(
                'max-forwards', 'Max-Forwards: -1')[-1].split(':')[-1].strip()
            max_forward = int(max_forwards) if max_forwards.isdigit() else None

            if max_forward is None:
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'ERROR', 'INVALID MAX FORWARDS')
                return Respond.http(client_id,
                                    http('400', 'INVALID MAX-FORWARDS\n'))

            elif max_forward == 0:
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'PERMIT', method)
                return Respond.http(client_id, http('200', ''))

            message.headers.set('max-forwards',
                                'Max-Forwards: %d' % (max_forward - 1))

        return Respond.download(client_id, message.headerhost, message.port,
                                message.upgrade, message.content_length,
                                self.transparent(message, peer))
Exemple #3
0
    def parseHTTP(self, client_id, peer, http_header):
        message = HTTP(self.configuration, http_header, peer)

        if not message.parse(self._transparent):
            try:
                version = message.request.version
            except AttributeError:
                version = '1.0'

            if message.reply_string:
                response = Respond.http(
                    client_id,
                    http(
                        str(message.reply_code),
                        '%s<br/>\n<!--\n\n<![CDATA[%s]]>\n\n-->\n' %
                        (message.reply_string, http_header.replace(
                            '\t', '\\t').replace('\r', '\\r').replace(
                                '\n', '\\n\n')), version))
            else:
                response = Respond.http(
                    client_id, http(str(message.reply_code), '', version))

            message = None

        elif message.reply_code:
            response = Respond.http(
                client_id,
                http(str(message.reply_code), self.reply_string,
                     message.request.version))
            message = None

        else:
            response = None

        return message, response
Exemple #4
0
    def doHTTPOptions(self, client_id, peer, message):
        # NOTE: we are always returning an HTTP/1.1 response
        method = message.request.method

        header = message.headers.get('max-forwards', '')
        if header:
            value = header[-1].split(':')[-1].strip()
            if not value.isdigit():
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'ERROR', 'INVALID MAX FORWARDS')
                return Respond.http(client_id,
                                    http('400', 'INVALID MAX-FORWARDS\n'))

            max_forward = int(value)
            if max_forward == 0:
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'PERMIT', method)
                return Respond.http(client_id, http('200', ''))

            message.headers.set('max-forwards',
                                'Max-Forwards: %d' % (max_forward - 1))

        return Respond.download(client_id, message.headerhost, message.port,
                                message.upgrade, message.content_length,
                                message)
Exemple #5
0
	def getLocalContent(self, code, name):
		filename = os.path.normpath(os.path.join(self.location, name))
		if not filename.startswith(self.location + os.path.sep):
			filename = ''

		if os.path.isfile(filename):
			try:
				stat = os.stat(filename)
			except IOError:
				# NOTE: we are always returning an HTTP/1.1 response
				content = 'close', http(501, 'local file is inaccessible %s' % str(filename))
			else:
				if filename in self._header :
					cache_time, header = self._header[filename]
				else:
					cache_time, header = None, None

				if cache_time is None or cache_time < stat.st_mtime:
					header = file_header(code, stat.st_size, filename)
					self._header[filename] = stat.st_size, header

				content = 'file', (header, filename)
		else:
			self.log.debug('local file is missing for %s: %s' % (str(name), str(filename)))
			# NOTE: we are always returning an HTTP/1.1 response
			content = 'close', http(501, 'could not serve missing file %s' % str(filename))

		return content
Exemple #6
0
    def getLocalContent(self, code, name):
        filename = os.path.normpath(os.path.join(self.location, name))
        if not filename.startswith(self.location + os.path.sep):
            filename = ''

        if os.path.isfile(filename):
            try:
                stat = os.stat(filename)
            except IOError:
                # NOTE: we are always returning an HTTP/1.1 response
                content = 'close', http(
                    501, 'local file is inaccessible %s' % str(filename))
            else:
                if filename in self._header:
                    cache_time, header = self._header[filename]
                else:
                    cache_time, header = None, None

                if cache_time is None or cache_time < stat.st_mtime:
                    header = file_header(code, stat.st_size, filename)
                    self._header[filename] = stat.st_size, header

                content = 'file', (header, filename)
        else:
            self.log.debug('local file is missing for %s: %s' %
                           (str(name), str(filename)))
            # NOTE: we are always returning an HTTP/1.1 response
            content = 'close', http(
                501, 'could not serve missing file %s' % str(filename))

        return content
Exemple #7
0
	def doHTTPOptions (self, client_id, peer, message):
		# NOTE: we are always returning an HTTP/1.1 response
		method = message.request.method

		if message.headers.get('max-forwards',''):
			max_forwards = message.headers.get('max-forwards','Max-Forwards: -1')[-1].split(':')[-1].strip()
			max_forward = int(max_forwards) if max_forwards.isdigit() else None

			if max_forward is None:
				response = Respond.http(client_id, http('400', 'INVALID MAX-FORWARDS\n'))
				self.usage.logRequest(client_id, peer, method, message.url, 'ERROR', 'INVALID MAX FORWARDS')

			elif max_forward == 0:
				response = Respond.http(client_id, http('200', ''))
				self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', method)

			else:
				response = None

			message.headers.set('max-forwards','Max-Forwards: %d' % (max_forward-1))

		if response is None:
			response = Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, message)

		return response
Exemple #8
0
    def doHTTPConnect(self, client_id, peer, message, http_header, source):
        method = message.request.method

        if not self.configuration.http.allow_connect or message.port not in self.configuration.security.connect:
            # NOTE: we are always returning an HTTP/1.1 response
            response = Respond.http(client_id,
                                    http('501', 'CONNECT NOT ALLOWED\n'))
            self.usage.logRequest(client_id, peer, method, message.url, 'DENY',
                                  'CONNECT NOT ALLOWED')

        elif self.enabled:
            request_string = self.createChildRequest(
                peer, message, http_header) if message else None
            status = self.writeChild(
                request_string) if request_string else None

            if status is True:
                response = Respond.defer(client_id, message)

            else:
                response = None

        else:
            response = Respond.connect(client_id, message.host, message.port,
                                       message)
            self.usage.logRequest(client_id, peer, method, message.url,
                                  'PERMIT', message.host)

        return response
Exemple #9
0
	def doHTTP (self, client_id, peer, http_header, source, tainted):
		message, response = self.parseHTTP(client_id, peer, http_header)

		if response is None and source == 'web':
			response = Respond.monitor(client_id, message.request.path)
			message = None

		if message is not None:
			method = message.request.method

			if method in ('GET', 'PUT', 'POST','HEAD','DELETE','PATCH'):
				response = self.doHTTPRequest(client_id, peer, message, http_header, source, tainted)

			elif method == 'CONNECT':
				response = self.doHTTPConnect(client_id, peer, message)

			elif method in ('OPTIONS','TRACE'):
				response = self.doHTTPOptions(client_id, peer, message)

			elif method in (
			'BCOPY', 'BDELETE', 'BMOVE', 'BPROPFIND', 'BPROPPATCH', 'COPY', 'DELETE','LOCK', 'MKCOL', 'MOVE',
			'NOTIFY', 'POLL', 'PROPFIND', 'PROPPATCH', 'SEARCH', 'SUBSCRIBE', 'UNLOCK', 'UNSUBSCRIBE', 'X-MS-ENUMATTS'):
				response = Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, self.transparent(message, peer))
				self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', method)

			elif message.request in self.configuration.http.extensions:
				response = Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, self.transparent(message, peer))
				self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', message.request)

			else:
				# NOTE: we are always returning an HTTP/1.1 respons
				response = Respond.http(client_id, http('405', ''))  # METHOD NOT ALLOWED
				self.usage.logRequest(client_id, peer, method, message.url, 'DENY', method)

		return response
Exemple #10
0
    def doHTTPConnect(self, client_id, peer, message, http_header, source,
                      tainted):
        method = message.request.method

        if not self.configuration.http.allow_connect or message.port not in self.configuration.security.connect:
            # NOTE: we are always returning an HTTP/1.1 response
            response = Respond.http(client_id,
                                    http('501', 'CONNECT NOT ALLOWED\n'))
            self.usage.logRequest(client_id, peer, method, message.url, 'DENY',
                                  'CONNECT NOT ALLOWED')

        elif self.enabled:
            classification = self.classify(message, http_header, tainted)

            if classification[1] == 'permit':
                response = Respond.connect(client_id, message.host,
                                           message.port, message)

            else:
                (operation, destination), response = self.request(
                    client_id, *(classification + (peer, http_header, source)))

        else:
            response = Respond.connect(client_id, message.host, message.port,
                                       message)

        return response
Exemple #11
0
    def doHTTP(self, client_id, peer, http_header, source):
        message = self.parseHTTP(client_id, peer, http_header)
        response = self.validateHTTP(client_id, message)

        if message.validated:
            message = self.addHeaders(message, peer)
            method = message.request.method

            if method in ("GET", "PUT", "POST", "HEAD", "DELETE", "PATCH"):
                response = self.doHTTPRequest(client_id, peer, message, http_header, source)

            elif method == "CONNECT":
                response = self.doHTTPConnect(client_id, peer, message, http_header, source)

            elif method in ("OPTIONS", "TRACE"):
                response = self.doHTTPOptions(client_id, peer, message)

            elif method in (
                "BCOPY",
                "BDELETE",
                "BMOVE",
                "BPROPFIND",
                "BPROPPATCH",
                "COPY",
                "DELETE",
                "LOCK",
                "MKCOL",
                "MOVE",
                "NOTIFY",
                "POLL",
                "PROPFIND",
                "PROPPATCH",
                "SEARCH",
                "SUBSCRIBE",
                "UNLOCK",
                "UNSUBSCRIBE",
                "X-MS-ENUMATTS",
            ):
                response = Respond.download(
                    client_id, message.headerhost, message.port, message.upgrade, message.content_length, message
                )
                self.usage.logRequest(client_id, peer, method, message.url, "PERMIT", method)

            elif message.request in self.configuration.http.extensions:
                response = Respond.download(
                    client_id, message.headerhost, message.port, message.upgrade, message.content_length, message
                )
                self.usage.logRequest(client_id, peer, method, message.url, "PERMIT", message.request)

            else:
                # NOTE: we are always returning an HTTP/1.1 response
                response = Respond.http(client_id, http("405", ""))  # METHOD NOT ALLOWED
                self.usage.logRequest(client_id, peer, method, message.url, "DENY", method)

        elif response is None:
            response = Respond.hangup(client_id)

        return response
Exemple #12
0
	def validateHTTP (self, client_id, message):
		if message.reply_code:
			try:
				version = message.request.version
			except AttributeError:
				version = '1.0'

			if message.reply_string:
				clean_header = message.raw.replace('\t','\\t').replace('\r','\\r').replace('\n','\\n\n')
				content = '%s<br/>\n<!--\n\n<![CDATA[%s]]>\n\n-->\n' % (message.reply_string, clean_header)
				response = Respond.http(client_id, http(str(message.reply_code), content, version))
			else:
				response = Respond.http(client_id, http(str(message.reply_code),'',version))

		else:
			response = None

		return response
Exemple #13
0
    def validateHTTP(self, client_id, message):
        if message.reply_code:
            try:
                version = message.request.version
            except AttributeError:
                version = "1.0"

            if message.reply_string:
                clean_header = message.raw.replace("\t", "\\t").replace("\r", "\\r").replace("\n", "\\n\n")
                content = "%s<br/>\n<!--\n\n<![CDATA[%s]]>\n\n-->\n" % (message.reply_string, clean_header)
                response = Respond.http(client_id, http(str(message.reply_code), content, version))
            else:
                response = Respond.http(client_id, http(str(message.reply_code), "", version))

        else:
            response = None

        return response
Exemple #14
0
	def validateHTTP (self, client_id, message):
		if message.reply_code:
			try:
				version = message.request.version
			except AttributeError:
				version = '1.0'

			if message.reply_string:
				clean_header = message.raw.replace('\t','\\t').replace('\r','\\r').replace('\n','\\n\n')
				content = '%s<br/>\n<!--\n\n<![CDATA[%s]]>\n\n-->\n' % (message.reply_string, clean_header)
				response = Respond.http(client_id, http(str(message.reply_code), content, version))
			else:
				response = Respond.http(client_id, http(str(message.reply_code),'',version))

		else:
			response = None

		return response
Exemple #15
0
	def doHTTPOptions (self, client_id, accept_addr, accept_port, peer, message):
		# NOTE: we are always returning an HTTP/1.1 response
		method = message.request.method

		header = message.headers.get('max-forwards', '')
		if header:
			value = header[-1].split(':')[-1].strip()
			if not value.isdigit():
				self.usage.logRequest(client_id, accept_addr, accept_port, peer, method, message.url, 'ERROR', 'INVALID MAX FORWARDS')
				return Respond.http(client_id, http('400', 'INVALID MAX-FORWARDS\n'))

			max_forward = int(value)
			if max_forward == 0:
				self.usage.logRequest(client_id, accept_addr, accept_port, peer, method, message.url, 'PERMIT', method)
				return Respond.http(client_id, http('200', ''))

			message.headers.set('max-forwards','Max-Forwards: %d' % (max_forward-1))

		return Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, message)
Exemple #16
0
    def doHTTPOptions(self, client_id, peer, message):
        # NOTE: we are always returning an HTTP/1.1 response
        method = message.request.method

        header = message.headers.get("max-forwards", "")
        if header:
            value = header[-1].split(":")[-1].strip()
            if not value.isdigit():
                self.usage.logRequest(client_id, peer, method, message.url, "ERROR", "INVALID MAX FORWARDS")
                return Respond.http(client_id, http("400", "INVALID MAX-FORWARDS\n"))

            max_forward = int(value)
            if max_forward == 0:
                self.usage.logRequest(client_id, peer, method, message.url, "PERMIT", method)
                return Respond.http(client_id, http("200", ""))

            message.headers.set("max-forwards", "Max-Forwards: %d" % (max_forward - 1))

        return Respond.download(
            client_id, message.headerhost, message.port, message.upgrade, message.content_length, message
        )
Exemple #17
0
	def readLocalContent(self, code, reason, data={}):
		filename = os.path.normpath(os.path.join(self.location, reason))
		if not filename.startswith(self.location + os.path.sep):
			filename = ''

		if os.path.isfile(filename):
			try:
				with open(filename) as fd:
					body = fd.read() % data

				# NOTE: we are always returning an HTTP/1.1 response
				content = 'close', http(code, body)
			except IOError:
				self.log.debug('local file is missing for %s: %s' % (str(reason), str(filename)))
				# NOTE: we are always returning an HTTP/1.1 response
				content = 'close', http(501, 'could not serve missing file  %s' % str(reason))
		else:
			self.log.debug('local file is missing for %s: %s' % (str(reason), str(filename)))
				# NOTE: we are always returning an HTTP/1.1 response
			content = 'close', http(501, 'could not serve missing file  %s' % str(reason))

		return content
Exemple #18
0
    def doHTTP(self, client_id, peer, http_header, source, tainted):
        message, response = self.parseHTTP(client_id, peer, http_header)

        if response is None and source == 'web':
            response = Respond.monitor(client_id, message.request.path)
            message = None

        if message is not None:
            method = message.request.method

            if method in ('GET', 'PUT', 'POST', 'HEAD', 'DELETE', 'PATCH'):
                response = self.doHTTPRequest(client_id, peer, message,
                                              http_header, source, tainted)

            elif method == 'CONNECT':
                response = self.doHTTPConnect(client_id, peer, message,
                                              http_header, source, tainted)
                response = response or self.doHTTPRequest(
                    client_id, peer, message, http_header, source, tainted)

            elif method in ('OPTIONS', 'TRACE'):
                response = self.doHTTPOptions(client_id, peer, message)

            elif method in ('BCOPY', 'BDELETE', 'BMOVE', 'BPROPFIND',
                            'BPROPPATCH', 'COPY', 'DELETE', 'LOCK', 'MKCOL',
                            'MOVE', 'NOTIFY', 'POLL', 'PROPFIND', 'PROPPATCH',
                            'SEARCH', 'SUBSCRIBE', 'UNLOCK', 'UNSUBSCRIBE',
                            'X-MS-ENUMATTS'):
                response = Respond.download(client_id, message.headerhost,
                                            message.port, message.upgrade,
                                            message.content_length,
                                            self.transparent(message, peer))
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'PERMIT', method)

            elif message.request in self.configuration.http.extensions:
                response = Respond.download(client_id, message.headerhost,
                                            message.port, message.upgrade,
                                            message.content_length,
                                            self.transparent(message, peer))
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'PERMIT', message.request)

            else:
                # NOTE: we are always returning an HTTP/1.1 respons
                response = Respond.http(client_id,
                                        http('405', ''))  # METHOD NOT ALLOWED
                self.usage.logRequest(client_id, peer, method, message.url,
                                      'DENY', method)

        return response
Exemple #19
0
	def parseHTTP (self, client_id, peer, http_header):
		message = HTTP(self.configuration, http_header, peer)

		if not message.parse(self._transparent):
			try:
				version = message.request.version
			except AttributeError:
				version = '1.0'

			if message.reply_string:
				response = Respond.http(client_id, http(str(message.reply_code), '%s<br/>\n<!--\n\n<![CDATA[%s]]>\n\n-->\n' % (message.reply_string,http_header.replace('\t','\\t').replace('\r','\\r').replace('\n','\\n\n')),version))
			else:
				response = Respond.http(client_id, http(str(message.reply_code),'',version))

			message = None

		elif message.reply_code:
			response = Respond.http(client_id, http(str(message.reply_code), self.reply_string, message.request.version))
			message = None

		else:
			response = None

		return message, response
Exemple #20
0
	def doHTTPConnect (self, client_id, peer, message):
		method = message.request.method

		if not self.configuration.http.allow_connect or message.port not in self.configuration.security.connect:
			# NOTE: we are always returning an HTTP/1.1 response
			response = Respond.http(client_id, http('501', 'CONNECT NOT ALLOWED\n'))
			self.usage.logRequest(client_id, peer, method, message.url, 'DENY', 'CONNECT NOT ALLOWED')

		elif self.enabled:
			classification = self.classify(message, http_header, tainted)
			(operation, destination), response = self.connect(client_id, *(classification + (peer, http_header, source)))

			if operation is not None:
				self.usage.logRequest(client_id, peer, method, message.url, operation, destination)

		else:
			response = Respond.connect(client_id, message.host, message.port, message)
			self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', message.host)

		return response
Exemple #21
0
	def doHTTPConnect (self, client_id, peer, message, http_header, source):
		method = message.request.method

		if not self.configuration.http.allow_connect or message.port not in self.configuration.security.connect:
			# NOTE: we are always returning an HTTP/1.1 response
			response = Respond.http(client_id, http('501', 'CONNECT NOT ALLOWED\n'))
			self.usage.logRequest(client_id, peer, method, message.url, 'DENY', 'CONNECT NOT ALLOWED')

		elif self.enabled:
			request_string = self.createChildRequest(peer, message, http_header) if message else None
			status = self.writeChild(request_string) if request_string else None

			if status is True:
				response = Respond.defer(client_id, message)

			else:
				response = None

		else:
			response = Respond.connect(client_id, message.host, message.port, message)
			self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', message.host)

		return response
Exemple #22
0
	def doHTTP (self, client_id, accept_addr, accept_port, peer, http_header, source):
		message = self.parseHTTP(client_id, accept_addr, accept_port, peer, http_header)
		response = self.validateHTTP(client_id, message)

		if message.validated:
			message = self.addHeaders(message, peer)
			method = message.request.method

			if method in ('GET', 'PUT', 'POST','HEAD','DELETE','PATCH'):
				response = self.doHTTPRequest(client_id, accept_addr, accept_port, peer, message, http_header, source)

			elif method == 'CONNECT':
				response = self.doHTTPConnect(client_id, accept_addr, accept_port, peer, message, http_header, source)

			elif method in ('OPTIONS','TRACE'):
				response = self.doHTTPOptions(client_id, accept_addr, accept_port, peer, message)

			elif method in (
			'BCOPY', 'BDELETE', 'BMOVE', 'BPROPFIND', 'BPROPPATCH', 'COPY', 'DELETE','LOCK', 'MKCOL', 'MOVE',
			'NOTIFY', 'POLL', 'PROPFIND', 'PROPPATCH', 'SEARCH', 'SUBSCRIBE', 'UNLOCK', 'UNSUBSCRIBE', 'X-MS-ENUMATTS'):
				response = Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, message)
				self.usage.logRequest(client_id, accept_addr, accept_port, peer, method, message.url, 'PERMIT', method)

			elif message.request in self.configuration.http.extensions:
				response = Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, message)
				self.usage.logRequest(client_id, accept_addr, accept_port, peer, method, message.url, 'PERMIT', message.request)

			else:
				# NOTE: we are always returning an HTTP/1.1 response
				response = Respond.http(client_id, http('405', ''))  # METHOD NOT ALLOWED
				self.usage.logRequest(client_id, accept_addr, accept_port, peer, method, message.url, 'DENY', method)

		elif response is None:
			response = Respond.hangup(client_id)

		return response
Exemple #23
0
                        'url': url,
                        'host': host,
                        'client_ip': client_ip,
                        'protocol': protocol,
                        'comment': comment
                    })
                length = 0

            elif command == 'monitor':
                path = args

                downloader = None
                newdownloader = False
                request = ''
                # NOTE: we are always returning an HTTP/1.1 response
                content = ('close', http('200', self.page.html(path)))
                length = 0

            elif command == 'close':
                downloader = None
                newdownloader = False
                request = ''
                content = ('close', None)
                length = 0

            else:
                downloader = None
                newdownloader = False
                request = ''
                content = None
                length = 0
Exemple #24
0
                request = ""
                content = self.readLocalContent(
                    code,
                    reason,
                    {"url": url, "host": host, "client_ip": client_ip, "protocol": protocol, "comment": comment},
                )
                length = 0

            elif command == "monitor":
                path = args

                downloader = None
                newdownloader = False
                request = ""
                # NOTE: we are always returning an HTTP/1.1 response
                content = ("close", http("200", self.page.html(path)))
                length = 0

            elif command == "close":
                downloader = None
                newdownloader = False
                request = ""
                content = ("close", None)
                length = 0

            else:
                downloader = None
                newdownloader = False
                request = ""
                content = None
                length = 0
Exemple #25
0
					raise ParsingError()

				downloader = None
				newdownloader = False
				request = ''
				content = self.readLocalContent(code, reason, {'url':url, 'host':host, 'client_ip':client_ip, 'protocol':protocol, 'comment':comment})
				length = 0

			elif command == 'monitor':
				path = args

				downloader = None
				newdownloader = False
				request = ''
				# NOTE: we are always returning an HTTP/1.1 response
				content = ('close', http('200', self.page.html(path)))
				length = 0

			elif command == 'close':
				downloader = None
				newdownloader = False
				request = ''
				content = ('close', None)
				length = 0

			else:
				downloader = None
				newdownloader = False
				request = ''
				content = None
				length = 0
Exemple #26
0
	def run (self):
		while self.running:
			try:
				# The timeout is really caused by the SIGALARM sent on the main thread every second
				# BUT ONLY IF the timeout is present in this call
				data = self.request_box.get(timeout=2)
			except Empty:
				if self.enabled:
					if not self.process or self.process.poll() is not None:
						if self.running:
							self.log.error('stopping the worker as the forked process exited !')
						self.running = False
				continue
			except ValueError:
				self.log.error('Problem reading from request_box')
				continue

			try:
				client_id, peer, header, source, tainted = data
			except TypeError:
				self.log.alert('Received invalid message: %s' % data)
				continue

			if self.enabled:
				if not self.process or self.process.poll() is not None:
					if self.running:
						self.log.error('cleanly stopping the worker, as the forked process died on us !')
					self.running = False
					if source != 'nop':
						self.respond(Respond.requeue(client_id, peer, header, source))
					break

			if source == 'nop':
				continue  # /break

			if not self.running:
				self.log.warning('Consumed a message before we knew we should stop.')

			# This code does nothing ATM, as self.stats_timestamp is always null
			stats_timestamp = self.stats_timestamp
			if stats_timestamp:
				# Is this actually atomic as I am guessing?
				# There's a race condition here if not. We're unlikely to hit it though, unless
				# the classifier can take a long time
				self.stats_timestamp = None if stats_timestamp == self.stats_timestamp else self.stats_timestamp

				# we still have work to do after this so don't continue
				stats = self._stats()
				self.respond(Respond.stats(self.wid, stats))

			message = HTTP(self.configuration,header,peer)
			if not message.parse(self._transparent):
				try:
					version = message.request.version
				except AttributeError:
					version = '1.0'
				if message.reply_string:
					self.respond(Respond.http(client_id, http(str(message.reply_code), '%s<br/>\n<!--\n\n<![CDATA[%s]]>\n\n-->\n' % (message.reply_string,header.replace('\t','\\t').replace('\r','\\r').replace('\n','\\n\n')),version)))
				else:
					self.respond(Respond.http(client_id, http(str(message.reply_code),'',version)))
				continue
			if message.reply_code:
				self.respond(Respond.http(client_id, http(str(message.reply_code), self.reply_string, message.request.version)))
				continue

			method = message.request.method

			if source == 'web':
				self.respond(Respond.monitor(client_id, message.request.path))
				continue

			# classify and return the filtered page
			if method in ('GET', 'PUT', 'POST','HEAD','DELETE','PATCH'):
				if not self.enabled:
					self.respond(Respond.download(client_id, message.host, message.port, message.upgrade, message.content_length, self.transparent(message, peer)))
					self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', message.host)
					continue

				(operation, destination), response = self.request(client_id, *(self.classify (message,header,tainted) + (peer, header, source)))
				self.respond(response)
				if operation is not None:
					self.usage.logRequest(client_id, peer, method, message.url, operation, destination)
				continue


			# someone want to use us as https prox, peery
			if method == 'CONNECT':
				# we do allow connect
				if not self.configuration.http.allow_connect or message.port not in self.configuration.security.connect:
					# NOTE: we are always returning an HTTP/1.1 response
					self.respond(Respond.http(client_id, http('501', 'CONNECT NOT ALLOWED\n')))
					self.usage.logRequest(client_id, peer, method, message.url, 'DENY', 'CONNECT NOT ALLOWED')
					pass

				if not self.enabled:
					self.respond(Respond.connect(client_id, message.host, message.port, http))
					continue

				(operation, destination), response = self.connect(client_id, *(self.classify(message,header,tainted)+(peer,header,source)))
				self.respond(response)
				if operation is not None:
					self.usage.logRequest(client_id, peer, method, message.url, operation, destination)
				continue

			if method in ('OPTIONS','TRACE'):
				if message.headers.get('max-forwards',''):
					max_forwards = message.headers.get('max-forwards','Max-Forwards: -1')[-1].split(':')[-1].strip()
					if not max_forwards.isdigit():
						# NOTE: we are always returning an HTTP/1.1 response
						self.respond(Respond.http(client_id, http('400', 'INVALID MAX-FORWARDS\n')))
						self.usage.logRequest(client_id, peer, method, message.url, 'ERROR', 'INVALID MAX FORWARDS')
						continue
					max_forward = int(max_forwards)
					if max_forward < 0 :
						# NOTE: we are always returning an HTTP/1.1 response
						self.respond(Respond.http(client_id, http('400', 'INVALID MAX-FORWARDS\n')))
						self.usage.logRequest(client_id, peer, method, message.url, 'ERROR', 'INVALID MAX FORWARDS')
						continue
					if max_forward == 0:
						if method == 'OPTIONS':
							# NOTE: we are always returning an HTTP/1.1 response
							self.respond(Respond.http(client_id, http('200', '')))
							self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', 'OPTIONS')
							continue
						if method == 'TRACE':
							# NOTE: we are always returning an HTTP/1.1 response
							self.respond(Respond.http(client_id, http('200', header)))
							self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', 'TRACE')
							continue
						raise RuntimeError('should never reach here')
					message.headers.set('max-forwards','Max-Forwards: %d' % (max_forward-1))
				# Carefull, in the case of OPTIONS message.host is NOT message.headerhost
				self.respond(Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, self.transparent(message, peer)))
				self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', message.headerhost)
				continue

			# WEBDAV
			if method in (
			  'BCOPY', 'BDELETE', 'BMOVE', 'BPROPFIND', 'BPROPPATCH', 'COPY', 'DELETE','LOCK', 'MKCOL', 'MOVE',
			  'NOTIFY', 'POLL', 'PROPFIND', 'PROPPATCH', 'SEARCH', 'SUBSCRIBE', 'UNLOCK', 'UNSUBSCRIBE', 'X-MS-ENUMATTS'):
				self.respond(Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, self.transparent(message, peer)))
				self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', method)
				continue

			if message.request in self.configuration.http.extensions:
				self.respond(Respond.download(client_id, message.headerhost, message.port, message.upgrade, message.content_length, self.transparent(message, peer)))
				self.usage.logRequest(client_id, peer, method, message.url, 'PERMIT', message.request)
				continue

			# NOTE: we are always returning an HTTP/1.1 response
			self.respond(Respond.http(client_id, http('405', '')))  # METHOD NOT ALLOWED
			self.usage.logRequest(client_id, peer, method, message.url, 'DENY', method)
			continue

		self.respond(Respond.hangup(self.wid))