Недавно в одном разговоре вспомнилась забавная история, которую и захотелось рассказать.
История случилась несколько месяцев назад, когда мы в Intervale
проводили интеграцию с Maxima Telecom в рамках проекта vmet.ro (он же
wi-fi.ru).
В этом проекте Intervale предоставлял открытый rest-based api (для платежей,
рекарринга и пр.), а Maxima Telecom являлся клиентом. В качестве транспорта
использовался http-протокол. По api запросы должны были содержать
специальный заголовок типа X-ABC-Custom (точное название заголовка на
всякий случай не раскрываю); значение в этом заголовке было одним из
факторов для выбора стратегии обработки (анонимный запрос,
аутентифицированный пользователь, доверенный клиент и т.п.).
Коллегам из МТ было выслано детальное описание api в doc-документе, интеграция началась вполне успешно.
И вот однажды, при интеграционном тестировании какой-то части
функционала на стороне Maxima Telecom стали получать ошибку аутентификации, и
после некоторых попыток задали вопрос нам. Специалист по разворачиванию,
администрированию и поддержке системы посмотрел логи, но найти причину
не смог, и переадресовал реквест в разработку. И т. к. сразу не было
понятно, в каком программном компоненте системы есть баг, то запрос ещё
после некоторых блужданий попал ко мне.
Начал я опять-таки с логов. Исключений или сообщений об ошибках не было,
значит, скорее всего, проблема возникала в штатном режиме (конечно, если
ошибка не терялась где-то, но это маловероятно). Отказ (и его код,
содержание) полностью соответствовал сценарию "анонимный пользователь
пытается выполнить операцию, которая может быть выполнена только
аутентифицированным пользователем" и порядку обработки этого сценария в
системном security gate'е. Но по тем же логам видно, что на вход
поступал запрос верного формата. Ок, проблемный компонент вроде был обнаружен.
Но прежде, чем лезть в код или искать автора его автора, надо было ещё раз проверить валидность входных данных.
Нашёл в логах пример подобной операции, которая проходила ранее (и параллельно с проблемных запросом)
успешно, и принялся сравнивать с примером неуспешной операции. Сравнивать построчно, проверяя поля, заголовки, значения и пр. Вроде, всё совпадает, но одна строка в логе показалась чуть-чуть длиннее
другой, и это насторожило. Путём постепенного отсекания было найдено расхождение:
X-ABC-Custom
и
X–ABC–Custom
X–ABC–Custom
Разница заметна? Ну, только если приглядеться. И заключалась разница в длине тире: запрос с более коротким обрабатывался
успешно, а с более длинным - нет. Причём разница была совсем небольшой,
классические en dash и em dash из MS Word.
Наш компонент получал на вход запрос и проверял, а есть
ли у него заголовок с коротким en dash (ожидаемый заголовок был задан в виде
строки в java-коде); а в запросе оказывался заголовок с длинным em
dash, проверка не проходила, запрос расценивался как анонимный.
Проверили - действительно, дело в этом.
Похоже на то, что при написании документации техническим писателем в его
документе MS Word одно тире оказалось заменённым на другое (причём не везде, а
только в некоторых примерах), и этого никто не заметил. А коллеги из Maxima Telecom использовали старую добрую
практику copy + paste и тупо вставили значения из примеров, получив в
одном случае успех, а в другом фэйл.
Кто ответственный за баг-то? ))
Комментариев нет:
Отправить комментарий