2

Предположим, я создаю ключ из пользовательского ввода websafe URLВ Google App Engine, как проверить правильность ввода ключа, созданного urlsafe?

key = ndb.Key(urlsafe=some_user_input) 

Как я могу проверить, если some_user_input действует?

Мой текущий эксперимент показывает, что приведенное выше высказывание выдает исключение ProtocolBufferDecodeError (Unable to merge from string.), если some_user_input недействителен, но ничего не может найти об этом из API. Может ли кто-нибудь подтвердить это, и указать мне лучший способ проверки достоверности ввода пользователя вместо того, чтобы перехватывать исключение?

Большое спасибо!

ответ

9

Если вы пытаетесь построить ключ с недопустимым параметром urlsafe

key = ndb.Key(urlsafe='bogus123') 

вы получите ошибку, как

Traceback (most recent call last): 
    File "/opt/google/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle 
    handler = _config_handle.add_wsgi_middleware(self._LoadHandler()) 
    File "/opt/google/google_appengine/google/appengine/runtime/wsgi.py", line 299, in _LoadHandler 
    handler, path, err = LoadObject(self._handler) 
    File "/opt/google/google_appengine/google/appengine/runtime/wsgi.py", line 85, in LoadObject 
    obj = __import__(path[0]) 
    File "/home/tim/git/teledap-appengine/main.py", line 10, in <module> 
    from src.tim import handlers as handlers_ 
    File "/home/tim/git/teledap-appengine/src/tim/handlers.py", line 42, in <module> 
    class ResetHandler(BaseHandler): 
    File "/home/tim/git/teledap-appengine/src/tim/handlers.py", line 47, in ResetHandler 
    key = ndb.Key(urlsafe='bogus123') 
    File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 212, in __new__ 
    self.__reference = _ConstructReference(cls, **kwargs) 
    File "/opt/google/google_appengine/google/appengine/ext/ndb/utils.py", line 142, in positional_wrapper 
    return wrapped(*args, **kwds) 
    File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 642, in _ConstructReference 
    reference = _ReferenceFromSerialized(serialized) 
    File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 773, in _ReferenceFromSerialized 
    return entity_pb.Reference(serialized) 
    File "/opt/google/google_appengine/google/appengine/datastore/entity_pb.py", line 1710, in __init__ 
    if contents is not None: self.MergeFromString(contents) 
    File "/opt/google/google_appengine/google/net/proto/ProtocolBuffer.py", line 152, in MergeFromString 
    self.MergePartialFromString(s) 
    File "/opt/google/google_appengine/google/net/proto/ProtocolBuffer.py", line 168, in MergePartialFromString 
    self.TryMerge(d) 
    File "/opt/google/google_appengine/google/appengine/datastore/entity_pb.py", line 1839, in TryMerge 
    d.skipData(tt) 
    File "/opt/google/google_appengine/google/net/proto/ProtocolBuffer.py", line 677, in skipData 
    raise ProtocolBufferDecodeError, "corrupted" 
ProtocolBufferDecodeError: corrupted 

Интересно здесь находятся вне

File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 773, in _ReferenceFromSerialized 
    return entity_pb.Reference(serialized) 

, который является последний код, выполненный в key.py module:

def _ReferenceFromSerialized(serialized): 
    """Construct a Reference from a serialized Reference.""" 
    if not isinstance(serialized, basestring): 
    raise TypeError('serialized must be a string; received %r' % serialized) 
    elif isinstance(serialized, unicode): 
    serialized = serialized.encode('utf8') 
    return entity_pb.Reference(serialized) 

serialized здесь, будучи расшифрованной строкой urlsafe, вы можете прочитать об этом по ссылке на исходный код.

еще один интересный один последний один:

File "/opt/google/google_appengine/google/appengine/datastore/entity_pb.py", line 1839, in TryMerge 

в entity_pb.py module, который выглядит как этот

def TryMerge(self, d): 
    while d.avail() > 0: 
     tt = d.getVarInt32() 
     if tt == 106: 
     self.set_app(d.getPrefixedString()) 
     continue 
     if tt == 114: 
     length = d.getVarInt32() 
     tmp = ProtocolBuffer.Decoder(d.buffer(), d.pos(), d.pos() + length) 
     d.skip(length) 
     self.mutable_path().TryMerge(tmp) 
     continue 
     if tt == 162: 
     self.set_name_space(d.getPrefixedString()) 
     continue 


     if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError 
     d.skipData(tt) 

который где фактическая попытка «слить вклад в Key» является сделал.


Вы можете увидеть в исходном коде, что в процессе построения ключа от параметра urlsafe не много может пойти не так. Сначала он проверяет, является ли вход строкой, а если нет, то TypeError поднят, если он есть, но он не является «действительным», действительно поднят ProtocolBufferDecodeError.


Мой текущий эксперимент показывает, что оператор будет бросать ProtocolBufferDecodeError (Невозможно слить из строки.) Исключение, если some_user_input является недействительным, но не смог найти ничего об этом от API. Может кто-то прокомментировать это?

Подтвержденный - мы теперь знаем, что также может быть поднят TypeError.

и указать мне лучший способ проверки правильности ввода пользователем вместо того, чтобы ловить исключение?

Это отличный способ проверить правильность!Почему сами чеки, если они уже сделаны appengine? Фрагмент кода может выглядеть так (не рабочий код, просто пример)

def get(self): 
    # first, fetch the user_input from somewhere 

    try: 
    key = ndb.Key(urlsafe=user_input) 
    except TypeError: 
    return 'Sorry, only string is allowed as urlsafe input' 
    except ProtocolBufferDecodeError: 
    return 'Sorry, the urlsafe string seems to be invalid' 
+0

Большое спасибо за ваш ответ и все указатели на исходный код @Tim! Теперь все имеет смысл. Единственное, что меня сейчас немного волнует, - это «ПротоколBufferDecodeError», который не публикован. Я боюсь, что это будет означать использование не документированного API, и Google может изменить эти внутренние функции, например. тип исключения, в будущем без нарушения контракта спецификации. –

+0

@YingXiong его реализация [здесь] (https://code.google.com/p/googleappengine/source/browse/trunk/python/google/net/proto/ProtocolBuffer.py), и это довольно широко используется в appengine, поэтому не ожидайте, что он скоро изменится. Если вы беспокоитесь о том, что не поймаете исключение, вы всегда можете добавить «исключение», которое улавливает все другие исключения, поэтому, если возникает ошибка, которая не является «TypeError» или «ProtocolBufferDecodeError», она все еще поймана –

Смежные вопросы