def write(self, data, binary=False, frame=None): """ Write data to the WebSocket. ========== ======== ============ Arguments Default Description ========== ======== ============ data A string of data to write to the WebSocket. Unicode will be converted automatically. binary False If this is True, the data will be written as a binary frame, rather than text frame. ========== ======== ============ """ if self._connection is None: log.warning("Attempted to write to closed %r." % self) return if not self.connected: log.warning("Attempted to write to disconnected %r." % self) return if binary and self.version == 0: raise ValueError("Attempted to send binary data to old-version WebSocket.") if isinstance(data, unicode): data = data.encode('utf-8') elif not isinstance(data, str): raise ValueError("Only strings may be written to WebSockets.") if not binary and '\xFF' in data: raise ValueError("Invalid character 0xFF in data to be sent.") if not self.version: self._connection.write("\x00%s\xFF" % data) else: if frame is None: if binary: frame = 2 else: frame = 1 self._connection.write(chr(0x80 | frame)) if len(data) > 125: if len(data) > 65535: self._connection.write(chr(127)) self._connection.write(STRUCT_Q.pack(len(data))) else: self._connection.write(chr(126)) self._connection.write(STRUCT_H.pack(len(data))) else: self._connection.write(chr(len(data))) self._connection.write(data)
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 _finish_handshake(self, key3): self._connection.read_delimiter = None request = self._request headers = self._headers del self._headers del self._request if request.scheme == 'https': scheme = 'wss' else: scheme = 'ws' request.send_status(101) headers.update({ 'Upgrade': 'WebSocket', 'Connection': 'Upgrade', 'Sec-WebSocket-Origin': request.headers['Origin'], 'Sec-WebSocket-Location': '%s://%s%s' % ( scheme, request.host, request.uri) }) request.send_headers(headers) try: request.send(challenge_response( request.headers, key3)) except ValueError: log.warning("Malformed WebSocket challenge to %r." % self) self.close(False) return # Move on. self._expect_frame = True # Finish up. self.connected = True self._connection.on_read = self._con_old_read self._safely_call(self.on_connect, *self._arguments) del self._arguments
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