def _check_key(key, allow_unicode_keys, key_prefix=b''): """Checks key and add key_prefix.""" if allow_unicode_keys: if isinstance(key, six.text_type): key = key.encode('utf8') elif isinstance(key, VALID_STRING_TYPES): try: if isinstance(key, bytes): key = key.decode().encode('ascii') else: key = key.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): raise MemcacheIllegalInputError("Non-ASCII key: %r" % key) key = key_prefix + key parts = key.split() if len(key) > 250: raise MemcacheIllegalInputError("Key is too long: %r" % key) # second statement catches leading or trailing whitespace elif len(parts) > 1 or parts[0] != key: raise MemcacheIllegalInputError("Key contains whitespace: %r" % key) elif b'\00' in key: raise MemcacheIllegalInputError("Key contains null: %r" % key) return key
def set(self, key, value, expire=0, noreply=True): if isinstance(key, six.text_type): raise MemcacheIllegalInputError(key) if isinstance(value, six.text_type): raise MemcacheIllegalInputError(value) if isinstance(key, six.string_types): try: key = key.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): raise MemcacheIllegalInputError if isinstance(value, six.string_types): try: value = value.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): raise MemcacheIllegalInputError flags = 0 if self.serializer: value, flags = self.serializer(key, value) if expire: expire += time.time() self._contents[key] = expire, value, flags return True
def _check_cas(self, cas): """Check that a value is a valid input for 'cas' -- either an int or a string containing only 0-9 The value will be (re)encoded so that we can accept strings or bytes. """ # convert non-binary values to binary if isinstance(cas, (six.integer_types, six.string_types)): try: cas = six.text_type(cas).encode(self.encoding) except UnicodeEncodeError: raise MemcacheIllegalInputError( 'non-ASCII cas value: %r' % cas) elif not isinstance(cas, six.binary_type): raise MemcacheIllegalInputError( 'cas must be integer, string, or bytes, got bad value: %r' % cas ) if not cas.isdigit(): raise MemcacheIllegalInputError( 'cas must only contain values in 0-9, got bad value: %r' % cas ) return cas
def _check_key(key, key_prefix=b''): """Checks key and add key_prefix.""" if isinstance(key, six.text_type): try: key = key.encode('ascii') except UnicodeEncodeError: raise MemcacheIllegalInputError("No ascii key: %r" % (key, )) key = key_prefix + key if b' ' in key: raise MemcacheIllegalInputError("Key contains spaces: %r" % (key, )) if len(key) > 250: raise MemcacheIllegalInputError("Key is too long: %r" % (key, )) return key
def _check_key(key, key_prefix=b''): """Checks key and add key_prefix.""" if isinstance(key, VALID_STRING_TYPES): try: key = key.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): raise MemcacheIllegalInputError("Non-ASCII key: '%r'" % (key, )) key = key_prefix + key if b' ' in key or b'\n' in key: raise MemcacheIllegalInputError( "Key contains space and/or newline: '%r'" % (key, )) if len(key) > 250: raise MemcacheIllegalInputError("Key is too long: '%r'" % (key, )) return key
def set(self, key, value, expire=0, noreply=True): if isinstance(key, six.text_type): raise MemcacheIllegalInputError(key) if isinstance(value, six.text_type): raise MemcacheIllegalInputError(value) was_serialized = False if self.serializer: value = self.serializer(key, value) if expire: expire += time.time() self._contents[key] = expire, value, was_serialized return True
def _check_integer(self, value, name): """Check that a value is an integer and encode it as a binary string""" if not isinstance(value, six.integer_types): # includes "long" on py2 raise MemcacheIllegalInputError( '%s must be integer, got bad value: %r' % (name, value)) return six.text_type(value).encode(self.encoding)
def _check_key(key, allow_unicode_keys, key_prefix=b''): """Checks key and add key_prefix.""" if allow_unicode_keys: if isinstance(key, six.text_type): key = key.encode('utf8') elif isinstance(key, VALID_STRING_TYPES): try: key = key.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): raise MemcacheIllegalInputError("Non-ASCII key: '%r'" % (key,)) key = key_prefix + key if len(key) > 250: raise MemcacheIllegalInputError("Key is too long: '%r'" % (key,)) for c in bytearray(key): if c == ord(b' '): raise MemcacheIllegalInputError( "Key contains space: '%r'" % (key,) ) elif c == ord(b'\n'): raise MemcacheIllegalInputError( "Key contains newline: '%r'" % (key,) ) elif c == ord(b'\00'): raise MemcacheIllegalInputError( "Key contains null character: '%r'" % (key,) ) elif c == ord(b'\r'): raise MemcacheIllegalInputError( "Key contains carriage return: '%r'" % (key,) ) return key
def _store_cmd(self, name, key, expire, noreply, data, cas=None): key = self.check_key(key) if not self.sock: self._connect() if self.serializer: data, flags = self.serializer(key, data) else: flags = 0 if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode('ascii') except UnicodeEncodeError as e: raise MemcacheIllegalInputError(str(e)) extra = b'' if cas is not None: extra += b' ' + cas if noreply: extra += b' noreply' cmd = (name + b' ' + key + b' ' + six.text_type(flags).encode('ascii') + b' ' + six.text_type(expire).encode('ascii') + b' ' + six.text_type(len(data)).encode('ascii') + extra + b'\r\n' + data + b'\r\n') try: self.sock.sendall(cmd) if noreply: return True buf = b'' buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': return True if line == b'NOT_STORED': return False if line == b'NOT_FOUND': return None if line == b'EXISTS': return False else: raise MemcacheUnknownError(line[:32]) except Exception: self.close() raise
def get(self, key, default=None): if isinstance(key, six.text_type): raise MemcacheIllegalInputError(key) if key not in self._contents: return default expire, value, was_serialized = self._contents[key] if expire and expire < time.time(): del self._contents[key] return default if self.deserializer: return self.deserializer(key, value, 2 if was_serialized else 1) return value
def get(self, key, default=None): if isinstance(key, six.text_type): raise MemcacheIllegalInputError(key) if isinstance(key, six.string_types): try: key = key.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): raise MemcacheIllegalInputError if key not in self._contents: return default expire, value, flags = self._contents[key] if expire and expire < time.time(): del self._contents[key] return default if self.deserializer: return self.deserializer(key, value, flags) return value
def _store_cmd(self, name, values, expire, noreply, flags=None, cas=None): cmds = [] keys = [] extra = b'' if cas is not None: extra += b' ' + cas if noreply: extra += b' noreply' expire = six.text_type(expire).encode(self.encoding) for key, data in six.iteritems(values): # must be able to reliably map responses back to the original order keys.append(key) key = self.check_key(key) if self.serializer: data, serializer_flags = self.serializer(key, data) # Use the serializer's flags when 'flags' haven't been specified # If 'flags' is specified, ignore the serializer_flags generated # from serializer, otherwise use serializer_flags. if flags is None: flags = serializer_flags # If no 'flags' or 'serializer' passed in, default flags to 0 if flags is None: flags = 0 if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode(self.encoding) except UnicodeEncodeError as e: raise MemcacheIllegalInputError( "Data values must be binary-safe: %s" % e) cmds.append(name + b' ' + key + b' ' + six.text_type(flags).encode(self.encoding) + b' ' + expire + b' ' + six.text_type(len(data)).encode(self.encoding) + extra + b'\r\n' + data + b'\r\n') if self.sock is None: self._connect() try: self.sock.sendall(b''.join(cmds)) if noreply: return {k: True for k in keys} results = {} buf = b'' for key in keys: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': results[key] = True if line == b'NOT_STORED': results[key] = False if line == b'NOT_FOUND': results[key] = None if line == b'EXISTS': results[key] = False else: raise MemcacheUnknownError(line[:32]) return results except Exception: self.close() raise
def _store_cmd(self, name, values, expire, noreply, flags=None, cas=None): cmds = [] keys = [] extra = b'' if cas is not None: cas = self._check_cas(cas) extra += b' ' + cas if noreply: extra += b' noreply' expire = self._check_integer(expire, "expire") for key, data in six.iteritems(values): # must be able to reliably map responses back to the original order keys.append(key) key = self.check_key(key) data, data_flags = self.serde.serialize(key, data) # If 'flags' was explicitly provided, it overrides the value # returned by the serializer. if flags is not None: data_flags = flags if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode(self.encoding) except UnicodeEncodeError as e: raise MemcacheIllegalInputError( "Data values must be binary-safe: %s" % e) cmds.append(name + b' ' + key + b' ' + six.text_type(data_flags).encode(self.encoding) + b' ' + expire + b' ' + six.text_type(len(data)).encode(self.encoding) + extra + b'\r\n' + data + b'\r\n') if self.sock is None: self._connect() try: self.sock.sendall(b''.join(cmds)) if noreply: return {k: True for k in keys} results = {} buf = b'' for key in keys: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': results[key] = True if line == b'NOT_STORED': results[key] = False if line == b'NOT_FOUND': results[key] = None if line == b'EXISTS': results[key] = False else: raise MemcacheUnknownError(line[:32]) return results except Exception: self.close() raise
def _store_cmd(self, name, values, expire, noreply, cas=None): cmds = [] keys = [] extra = b'' if cas is not None: extra += b' ' + cas if noreply: extra += b' noreply' expire = six.text_type(expire).encode('ascii') for key, data in six.iteritems(values): # must be able to reliably map responses back to the original order keys.append(key) key = self.check_key(key) if self.serializer: data, flags = self.serializer(key, data) else: flags = 0 if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode('ascii') except UnicodeEncodeError as e: raise MemcacheIllegalInputError(str(e)) cmds.append(name + b' ' + key + b' ' + six.text_type(flags).encode('ascii') + b' ' + expire + b' ' + six.text_type(len(data)).encode('ascii') + extra + b'\r\n' + data + b'\r\n') if not self.sock: self._connect() try: self.sock.sendall(b''.join(cmds)) if noreply: return {k: True for k in keys} results = {} buf = b'' for key in keys: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': results[key] = True if line == b'NOT_STORED': results[key] = False if line == b'NOT_FOUND': results[key] = None if line == b'EXISTS': results[key] = False else: raise MemcacheUnknownError(line[:32]) return results except Exception: self.close() raise