def on_overflow_error(self, exception): """ Placeholder. Called when an internal buffer on the WebSocket has exceeded its size limit. By default, logs the exception and closes the WebSocket. ========== ============ Argument Description ========== ============ exception The exception that was raised. ========== ============ """ log.exception(exception) self.close(reason=1009)
def _read_request_body(self, data): """ Read a request body from the socket, parse it, and then call the request handler for the current request. """ request = self.current_request request.body = data try: content_type = request.headers.get('Content-Type', '') if request.method in ('POST', 'PUT'): if content_type.startswith( 'application/x-www-form-urlencoded'): post = request.post for key, val in parse_qsl(data, False): if key in post: if isinstance(post[key], list): post[key].append(val) else: post[key] = [post[key], val] else: post[key] = val elif content_type.startswith('multipart/form-data'): for field in content_type.split(';'): key, _, value = field.strip().partition('=') if key == 'boundary' and value: parse_multipart(request, value, data) break else: log.warning('Invalid multipart/form-data.') except BadRequest as err: log.info('Bad request from %r: %s', self.remote_address, err) request.send_response(err.message, err.code) self.close() return try: self.server.request_handler(request) except Exception: log.exception('Error handling HTTP request.') if request._started: self.close(False) else: request.send_response("500 Internal Server Error", 500) self.close()
def _read_request_body(self, data): """ Read a request body from the socket, parse it, and then call the request handler for the current request. """ request = self.current_request request.body = data try: content_type = request.headers.get('Content-Type', '') if request.method in ('POST','PUT'): if content_type.startswith('application/x-www-form-urlencoded'): post = request.post for key, val in parse_qsl(data, False): if key in post: if isinstance(post[key], list): post[key].append(val) else: post[key] = [post[key], val] else: post[key] = val elif content_type.startswith('multipart/form-data'): for field in content_type.split(';'): key, _, value = field.strip().partition('=') if key == 'boundary' and value: parse_multipart(request, value, data) break else: log.warning('Invalid multipart/form-data.') except BadRequest as err: log.info('Bad request from %r: %s', self.remote_address, err) request.send_response(err.message, err.code) self.close() return try: self.server.request_handler(request) except Exception: log.exception('Error handling HTTP request.') if request._started: self.close(False) else: request.send_response("500 Internal Server Error", 500) self.close()
def _safely_call(self, thing_to_call, *args, **kwargs): """ Safely execute a callable. The callable is wrapped in a try block and executed. If an exception is raised it is logged. ============== ============ Argument Description ============== ============ thing_to_call The callable to execute. *args The positional arguments to be passed to the callable. **kwargs The keyword arguments to be passed to the callable. ============== ============ """ try: return thing_to_call(*args, **kwargs) except Exception: log.exception("Exception raised on %r." % self)
def _read_header(self, data): """ Read the headers of an HTTP request from the socket, and the request body if necessary, into a new HTTPRequest instance. Then, assuming that the headers are valid, call the server's request handler. """ try: initial_line, _, data = data.partition(CRLF) try: method, url, protocol = WHITESPACE.split( initial_line) #.split(' ') except ValueError: raise BadRequest('Invalid HTTP request line.') if not protocol.startswith('HTTP/'): raise BadRequest('Invalid HTTP protocol version.', code='505 HTTP Version Not Supported') # Parse the headers. if data: headers = read_headers(data) else: headers = {} # If we're secure, we're HTTPs. if self.ssl_enabled: scheme = 'https' else: scheme = 'http' # Construct an HTTPRequest object. self.current_request = request = HTTPRequest( self, method, url, protocol, headers, scheme) # If we have a Content-Length header, read the request body. length = headers.get('Content-Length') if length: if not isinstance(length, int): raise BadRequest( 'Provided Content-Length (%r) is invalid.' % length) elif length > self.server.max_request: raise BadRequest( ('Provided Content-Length (%d) larger than server ' 'limit %d.') % (length, self.server.max_request), code='413 Request Entity Too Large') if headers.get('Expect', '').lower() == '100-continue': self.write("%s 100 (Continue)%s" % (protocol, DOUBLE_CRLF)) # Await a request body. self.on_read = self._read_request_body self.read_delimiter = length return except BadRequest as err: log.info('Bad request from %r: %s', self.remote_address, err) self.write('HTTP/1.1 %s%s' % (err.code, CRLF)) if err.message: self.write('Content-Type: text/html%s' % CRLF) self.write('Content-Length: %d%s' % (len(err.message), DOUBLE_CRLF)) self.write(err.message) else: self.write(CRLF) self.close() return except Exception as err: log.info('Exception handling request from %r: %s', self.remote_address, err) self.write('HTTP/1.1 500 Internal Server Error%s' % CRLF) self.write('Content-Length: 0%s' % DOUBLE_CRLF) self.close() return try: # Call the request handler. self.server.request_handler(request) except Exception: log.exception('Error handling HTTP request.') if request._started: self.close(False) else: request.send_response("500 Internal Server Error", 500) self.close()
def _read_header(self, data): """ Read the headers of an HTTP request from the socket, and the request body if necessary, into a new HTTPRequest instance. Then, assuming that the headers are valid, call the server's request handler. """ try: initial_line, _, data = data.partition(CRLF) try: method, uri, protocol = WHITESPACE.split(initial_line) #.split(' ') except ValueError: raise BadRequest('Invalid HTTP request line.') if not protocol.startswith('HTTP/'): raise BadRequest('Invalid HTTP protocol version.', code='505 HTTP Version Not Supported') # Parse the headers. if data: headers = read_headers(data) else: headers = {} # If we're secure, we're HTTPs. if self.ssl_enabled: scheme = 'https' else: scheme = 'http' # Construct an HTTPRequest object. self.current_request = request = HTTPRequest(self, method, uri, protocol, headers, scheme) # If we have a Content-Length header, read the request body. length = headers.get('Content-Length') if length: if not isinstance(length, int): raise BadRequest( 'Provided Content-Length (%r) is invalid.' % length ) elif length > self.server.max_request: raise BadRequest(( 'Provided Content-Length (%d) larger than server ' 'limit %d.' ) % (length, self.server.max_request), code='413 Request Entity Too Large') if headers.get('Expect','').lower() == '100-continue': self.write("%s 100 (Continue)%s" % ( protocol, DOUBLE_CRLF)) # Await a request body. self.on_read = self._read_request_body self.read_delimiter = length return except BadRequest as err: log.info('Bad request from %r: %s', self.remote_address, err) self.write('HTTP/1.1 %s%s' % (err.code, CRLF)) if err.message: self.write('Content-Type: text/html%s' % CRLF) self.write('Content-Length: %d%s' % (len(err.message), DOUBLE_CRLF)) self.write(err.message) else: self.write(CRLF) self.close() return except Exception as err: log.info('Exception handling request from %r: %s', self.remote_address, err) self.write('HTTP/1.1 500 Internal Server Error%s' % CRLF) self.write('Content-Length: 0%s' % DOUBLE_CRLF) self.close() return try: # Call the request handler. self.server.request_handler(request) except Exception: log.exception('Error handling HTTP request.') if request._started: self.close(False) else: request.send_response("500 Internal Server Error", 500) self.close()
def _process_read_buffer(self): """ Process the read_buffer. This is only used when the ReadDelimiter isn't EntireMessage. """ while self._read_buffer: delimiter = self._read_delimiter if delimiter is None or delimiter is EntireMessage: data = self._read_buffer self._read_buffer = u"" self._safely_call(self.on_read, data) elif isinstance(delimiter, (int, long)): if len(self._read_buffer) < delimiter: break data = self._read_buffer[:delimiter] self._read_buffer = self._read_buffer[delimiter:] self._safely_call(self.on_read, data) elif isinstance(delimiter, basestring): mark = self._read_buffer.find(delimiter) if mark == -1: break data = self._read_buffer[:mark] self._read_buffer = self._read_buffer[mark + len(delimiter):] self._safely_call(self.on_read, data) elif isinstance(delimiter, Struct): if len(self._read_buffer) < delimiter.size: break data = self._read_buffer[:delimiter.size] self._read_buffer = self._read_buffer[delimiter.size:] # Safely unpack it. This should *probably* never error. try: data = delimiter.unpack(data) except struct.error: log.exception("Unable to unpack data on %r." % self) self.close(False) break # Unlike most on_read calls, this one sends every variable of # the parsed data as its own argument. self._safely_call(self.on_read, *data) elif isinstance(delimiter, RegexType): # Depending on regex_search, we could do this two ways. if self.regex_search: match = delimiter.search(self._read_buffer) if not match: break data = self._read_buffer[:match.start()] self._read_buffer = self._read_buffer[match.end():] else: # Require the match to be at the beginning. data = delimiter.match(self._read_buffer) if not data: break self._read_buffer = self._read_buffer[data.end():] # Send either the string or the match object. self._safely_call(self.on_read, data) else: log.warning("Invalid read_delimiter on %r." % self) break if self._connection is None or not self.connected: break