def _handle(self, source, dest, to_backend, on_between_handle, **kwargs): # https://github.com/memcached/memcached/blob/master/doc/protocol.txt # Sending the query buffer = self._get_data(source) if not buffer: self._abort_handling(to_backend, dest) return # sending the first packet dest.sendall(buffer) on_between_handle() # finding the command we sent. cmd = RE_MEMCACHE_COMMAND.search(buffer) if cmd is None: # wat ? self._abort_handling(to_backend, dest) return # looking at the command cmd = cmd.groups()[0] buffer_size = self.option('buffer') cmd_parts = cmd.split() mcmd = cmd_parts[0] if mcmd in ('set', 'add', 'replace', 'append'): cmd_size = len(cmd) + len(CRLF) data_size = int(cmd_parts[-1]) total_size = cmd_size + data_size # grabbing more data if needed left_to_read = total_size - len(buffer) + len(CRLF) if left_to_read > 0: for chunk in chunked(left_to_read, buffer_size): data = source.recv(chunk) buffer += data dest.sendall(data) # Receiving the response now buffer = self._get_data(dest, buffer_size) source.sendall(buffer) if buffer.startswith('VALUE'): # we're getting back a value. EOW = 'END' + CRLF else: EOW = CRLF while not buffer.endswith(EOW): data = self._get_data(dest, buffer_size) buffer += data source.sendall(data) # we're done return True # keeping connected
def _handle(self, source, dest, to_backend): buffer_size = self.option("buffer") # Getting the HTTP query data = self._get_data(source) if not data: self._abort_handling(to_backend, dest) return False # sending it to the backend dest.sendall(data) # Receiving the response buffer = self._get_data(dest, buffer_size) source.sendall(buffer) # Reading the HTTP Headers while EOH not in buffer: data = self._get_data(dest, buffer_size) buffer += data source.sendall(data) # keep alive header ? keep_alive = RE_KEEPALIVE.search(buffer) is not None # content-length header - to see if we need to suck more # data. match = RE_LEN.search(buffer) if match: resp_len = int(match.group(1)) left_to_read = resp_len - len(buffer) if left_to_read > 0: for chunk in chunked(left_to_read, buffer_size): data = self._get_data(dest, chunk) buffer += data source.sendall(data) else: # embarrassing... # just sucking until recv() returns '' while True: data = self._get_data(dest, buffer_size) if data == "": break source.sendall(data) # do we close the client ? if not keep_alive and not self.option("keep_alive"): source.close() source._closed = True if not self.option("reuse_socket") and not self.option("keep_alive"): dest.close() dest._closed = True # we're done return keep_alive or self.option("keep_alive")
def _handle(self, source, dest, to_backend, on_between_handle): """ see http://redis.io/topics/protocol """ # grabbing data bytepos, buffer = self._find(source, '', CRLF, dest) on_between_handle() if bytepos == -1: return False num_args = int(buffer[1:bytepos]) for arg in range(num_args): # next CRLF buffer = buffer[bytepos + len(CRLF):] bytepos, buffer = self._find(source, buffer, CRLF, dest) # reading the number of bytes num_bytes = int(buffer[1:bytepos]) data_start = bytepos + len(CRLF) # reading the data (next CRLF) buffer = buffer[data_start:] __, buffer = self._find(source, buffer, CRLF, dest) data = buffer[:num_bytes] bytepos = num_bytes # Getting the answer back and sending it over. buffer = self._get_data(dest) source.sendall(buffer) if buffer[0] in ('+', '-', ':'): # simple reply, we're good return False # disconnect mode ? buffer_size = self.option('buffer') bytepos, buffer = self._find(dest, buffer, CRLF, source) if buffer[0] == '$': # bulk reply size = int(buffer[1:bytepos]) left_to_read = (size - len(buffer) + len(buffer[:bytepos]) + len(CRLF) * 2) if left_to_read > 0: for chunk in chunked(left_to_read, buffer_size): data = self._get_data(dest, chunk) buffer += data source.sendall(data) return False # disconnect mode ? if buffer[0] == '*': # multi-bulk reply raise NotImplementedError() raise NotImplementedError()
def handle(self, client_sock, address): client_sock.setblocking(0) dest = None try: # getting the query data = get_data(client_sock) if not data: return # finding out what backend we want data = data.split('\r\n') PATH = data[0].split() elmts = PATH[1].split('/') try: port = int(elmts[1]) except ValueError: client_sock.sendall(http_error(404, 'Not Found')) return NEW_PATH = '/'.join(elmts[0:1] + elmts[2:]) data[0] = ' '.join(PATH[0:1] + [NEW_PATH] + PATH[2:]) try: dest = create_connection((self.host, port)) except error: client_sock.sendall(http_error(503, '%d not responding' % port)) return # sending it to the backend dest.sendall('\r\n'.join(data)) # Receiving the response buffer = get_data(dest) client_sock.sendall(buffer) # Reading the HTTP Headers while EOH not in buffer: data = get_data(dest) buffer += data client_sock.sendall(data) # content-length header - to see if we need to suck more # data. match = RE_LEN.search(buffer) if match: resp_len = int(match.group(1)) left_to_read = resp_len - len(buffer) if left_to_read > 0: for chunk in chunked(left_to_read, 1024): data = get_data(dest, chunk) buffer += data client_sock.sendall(data) else: # embarrassing... # just sucking until recv() returns '' while True: data = get_data(dest) if data == '': break client_sock.sendall(data) finally: client_sock.close() if dest is not None: dest.close()
def test_chunked(self): self.assertEqual(sum(list(chunked(7634, 2049))), 7634)