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
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
def parseHTTP (self, client_id, peer, http_header): message = HTTP(self.configuration, http_header, peer) message.parse(self._transparent) return message
return message, 'http', headers, comment # QUICK and DIRTY, let do a intercept using the CONNECT syntax if headers.startswith('CONNECT'): _ = headers.replace('\r\n', '\n').split('\n\n', 1) if _[1] and not _[1].strip(): headers = _[0] elif _[1]: # is not an empty string connect = _[0] headers = _[1] request = Request(connect.split('\n')[0] + '\n').parse() if not request: return message, 'file', 'internal_error.html', '' h = HTTP(self.configuration, headers, message.client) if not h.parse(self._transparent) or h.reply_code: return message, 'file', 'internal_error.html', '' # The trick to not have to extend ICAP h.host = request.host h.port = request.port return h, 'permit', None, comment # Parsing the request from the ICAP server h = HTTP(self.configuration, headers, message.client) if not h.parse(self._transparent) or h.reply_code: return message, 'file', 'internal_error.html', comment return h, 'permit', None, comment
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))
return message, 'file', 'internal_error.html', '' if headers.startswith('HTTP/') and (headers.split() + [''])[1].isdigit(): return message, 'http', headers, comment # QUICK and DIRTY, let do a intercept using the CONNECT syntax if headers.startswith('CONNECT'): _ = headers.replace('\r\n','\n').split('\n\n',1) if _[1]: # is not an empty string connect = _[0] headers = _[1] request = Request(connect.split('\n')[0]).parse() if not request: return message, 'file', 'internal_error.html', '' h = HTTP(self.configuration,headers,message.client) if not h.parse(self._transparent) or h.reply_code: return message, 'file', 'internal_error.html', '' # The trick to not have to extend ICAP h.host = request.host h.port = request.port return h,'permit',None,comment # Parsing the request from the ICAP server h = HTTP(self.configuration,headers,message.client) if not h.parse(self._transparent) or h.reply_code: return message, 'file', 'internal_error.html', comment return h, 'permit', None, comment
def parseHTTP (self, client_id, accept_addr, accept_port, peer, http_header): message = HTTP(self.configuration, http_header, peer) message.parse(self._transparent) return message