1. C++ / Говнокод #26452

    +4

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    static bool ShouldIgnoreHeaderForCacheReuse(AtomicString header_name) {
      // FIXME: This list of headers that don't affect cache policy almost certainly
      // isn't complete.
      DEFINE_STATIC_LOCAL(
          HashSet<AtomicString>, headers,
          ({"Cache-Control", "If-Modified-Since", "If-None-Match", "Origin",
            "Pragma", "Purpose", "Referer", "User-Agent"}));
      return headers.Contains(header_name);
    }

    https://chromium.googlesource.com/chromium/src/+/refs/heads/master/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc

    Вот есть такая крутая фича под названием «preload»: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content.
    Tl;dr: указываем «<link rel="preload" href="/comments.html" [...]>» в начале index.html, после чего браузер начнёт загружать comments.html в фоновом режиме. В «NGK» «Ангуляр» загружает этот самый comments.html для отрисовки главной страницы, поэтому предварительная загрузка (до того, как загрузится, собственно, «Ангуляр») может сэкономить несколько десятков миллисекунд. Ура.

    Но нельзя так просто взять и сделать что-то без пердолинга! Чтобы браузер смог использовать предварительно загруженный документ, необходимо, чтобы все заголовки, за исключением представленных в коде, в обоих запросах (из preload и из «Ангуляра») совпадали, что, конечно же, не лишено смысла. Поэтому, если просто взять и включить предварительную загрузку, «Хром» выдаст печальное «A preload for 'https://gcode.space/comments.html' is found, but is not used because the request headers do not match».

    Окей, повозившись с CORS, наш инженерный отдел добился полного совпадения заголовков, за исключением «Origin» (его браузер в «простых» запросах через XHR принципиально не ставит) и «Accept». «Ангуляр» по-умолчанию суёт в «Accept» «application/json, text/plain, */*», а для запроса через preload консоль разработчика показывает просто «*/*».
    Не беда! Наш инженерный отдел нагуглил, как поправить заголовки запросов в «Ангуляре», поставил там «*/*» и, довольный собой, приготовился наблюдать неебическое ускорение загрузки: https://i.imgur.com/q0CtQXp.png.

    Запостил: gost, 27 Февраля 2020

    Комментарии (66) RSS

    • Хуй. Не работает. И какие заголовки ему не нравятся — не говорит.
      На этом моменте наш инженерный отдел знатно охуел, взял в руки «x64dbg» и пошёл копать. Первые попытки ручной правки регистра заголовков-исключений (ну, мало ли, вдруг разрабы «Хрома» забыли) оказались неудачными. Первые результаты принёс патчинг самого начала chrome.dll!ShouldIgnoreHeaderForCacheReu se() на «xor rax, rax; inc rax; ret»: заработало!

      Но, конечно, предлагать пользователям установить грубо запатченный «Хром» — не очень хорошая затея (в первую очередь потому, что такой патч вреда принесёт гораздо больше, чем пользы). Стало понятно, что без пошаговой отладки не обойтись.

      Наконец, после нескольких бесплодных попыток (как же долго «x64dbg» загружает pdb для chrome.dll…) виновник сего безобразия был найден. Вот он:
      for (const auto& header : new_headers) {
        AtomicString header_name = header.key;
        if (!ShouldIgnoreHeaderForCacheReuse(header_name) &&
            header.value != old_headers.Get(header_name)) {
          return MatchStatus::kRequestHeadersDoNotMatch;
        }
      }

      Консоль разработчика нагло пиздит. В preload запросе попросту нет заголовка «Accept», и «old_headers.Get(header_name)» возвращает null. А null — это не то же самое, что и «*/*». А консоль разработчика говорит, что то же самое. Но оно не то же!

      Поэтому для корректной работы предварительной загрузки документов заголовок «Accept» нужно удалить.

      Такой вот багор.
      Ответить
      • ХУЙ
        Ответить
        • 3oJIoTou
          Ответить
          • ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ ХУЙ
            Ответить
      • показать все, что скрытоvanished
        Ответить
        • Я хочу. Показывай что нужно исправить.
          Ответить
        • Подписанный, там рядом с chrome.dll лежит «chrome.dll.sig». На время дебага я её удолил, но «Хром» на это внимания не обратил и спокойно загрузил пропатченную дллку.

          > не хочешь исправить, и послать гуглу пул реквест? Станешь контрибутером хрома
          Не, там простого фикса не выйдет. По сути надо завести список дефолтных значений заголовков (или взять их откуда-то из глубины движка, если такое есть) и сравнивать с ним в случае, если в одном из запросов заголовка не найдено. А для этого надо хорошо знать, какие заголовки как себя ведут, какие имеют дефолтные значения, какие не имеют, а какие имеют только в определённых контекстах.
          Ответить
    • > все заголовки, за исключением представленных в коде, в обоих запросах (из preload и из «Ангуляра») совпадали, что, конечно же, не лишено смысла
      А мне кажется, питушня.
      Приложение может использовать свои нестандартные заголовки, меняющиеся по неизвестным принципам для авторов правила равных заголовков (например, для каких-то целей может потребоваться заголовок Timestamp или Request-Id).
      Равенство должно требоваться только для списка уже известных авторам правила равных заголовков стандартных заголовков.
      Ответить
      • показать все, что скрытоvanished
        Ответить
        • Точно? Я перед тем, как пейсать комментарий, чуть взгуглил тему. На SO писали, что заголовки с хэ настолько часто вставляли в стандарт (не убирая хэ из-за обратной совместимости; не осилили переобувание boost:: в std::), что теперь просят писать без хэ и осмысленные имена, чтобы потом при случае стандартизовать эту психозу без кобенных префиксов.
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • Нагуглил статейку: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers.
              >>> Custom proprietary headers have historically been used with an X- prefix, but this convention was deprecated in June 2012 because of the inconveniences it caused when nonstandard fields became standard in RFC 6648;
              Ответить
            • https://stackoverflow.com/a/3561399
              там дают пример x-gzip
              Ответить
            • И вот ещё пояснение, https://tools.ietf.org/html/rfc6648:
              ⿌
                 The primary problem with the "X-" convention is that unstandardized
                 parameters have a tendency to leak into the protected space of
                 standardized parameters, thus introducing the need for migration from
                 the "X-" name to a standardized name.  Migration, in turn, introduces
                 interoperability issues (and sometimes security issues) because older
                 implementations will support only the "X-" name and newer
                 implementations might support only the standardized name.  To
                 preserve interoperability, newer implementations simply support the
                 "X-" name forever, which means that the unstandardized name has
                 become a de facto standard (thus obviating the need for segregation
                 of the name space into standardized and unstandardized areas in the
                 first place).
              
                 We have already seen this phenomenon at work with regard to FTP in
                 the quote from [RFC1123] in Appendix A.  The HTTP community had the
                 same experience with the "x-gzip" and "x-compress" media types, as
                 noted in [RFC2068]:
              
                    For compatibility with previous implementations of HTTP,
                    applications should consider "x-gzip" and "x-compress" to be
                    equivalent to "gzip" and "compress" respectively.
              Ответить
              • показать все, что скрытоvanished
                Ответить
                • GT при автоматическом определении языка говорит, что это "русский" и переводит на "русский" как ⿌ (читается miǎn)
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                  • miǎn kap̈m̂
                    Ответить
                  • Гугуру торансурейто не может перевести, потому что это не иероглиф, а радикал. Иероглиф состоящий только из этого радикала вот: 黽
                    В японском (китайский мне неинтересен) этот кандзи не входит в список дзёё кандзи и означает следующее (ЯРКСИ):

                    黽 «Лягушка» | ボー, ビン, ベン | 13 штрихов | +/x

                    黽部 ぼうぶ «лягушка» (ключ 205)
                    黽 かえる  あおがえる  べん то же

                    В сочетаниях непродуктивен

                    △水黽 あめんぼ водомерка болотная, водяной клоп, Aquarius paludum; Ср. 飴ん棒 あめんぼう 
                     黽勉 びんべん кн. усердие, старание
                    Ответить
      • А, хотя, может и не питушня. Это же как бы один и тот же запрос, который просто хотят выполнить заранее.

        Нечто вроде мемоизации функции. Если хочешь получить ответ из кэша, используй те же самые аргументы.
        Ответить
      • Если в запросе какие-то заголовки изменились — значит, с сервера может прийти другой ответ. Реальный пример: preloadим GET /hujLen -> 42, далее в скрипте посылается запрос GET /hujLen с кастомным заколовком «Secret: 123456», на который сервер бы ответил реальной длиной 12. Но если «Хром» будет игнорировать заголовки — скрипт получит из кэша значение 42.
        Ответить
        • Вообще, в мире с побочными эффектами всегда приходит другой ответ.
          Поэтому preload должен никогда не работать. Стоило бы дать возможность комитету крепких вопросов к столетию юбилея Попову Юрию Алексаилычу пользователю указать, какие два запроса считать эквивалентными.
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • В математическом смысле? Нет.

              Какая-нибудь питушня вроде /dev/random as a service или govnokod.ru/comments, или даже govnokod.ru будет выдавать разный ответ на тот же запрос.
              Ответить
              • показать все, что скрытоvanished
                Ответить
                • Мне кажется, это наоборот важно, что современная наука не может поменять значение времени. Из-за этого время является уникальным идентификатором и может служить единственным аргументом нечистых функций (вместо питушарского мира в этих ваших анскильных хаскелях).
                  Ответить
                  • > современная наука не может поменять значение времени
                    Квантово-релятивсткие питухи.

                    >время является уникальным идентификатором
                    Если верить «современной науке» время везде течёт по-разному.

                    >питушарского мира в этих ваших анскильных хаскелях
                    Всё очень просто, процессор Вселенной лениво разворачивает список иммутабельных состояний пространства. (см. аппорию Зенона о стреле висящей в воздухе).

                    Соответственно время — просто id текущего иммутабельного снепшота трёхмерного пространства.
                    Ответить
                    • >>время является уникальным идентификатором
                      >Если верить «современной науке» время везде течёт по-разному.
                      1. Мы рассматриваем только точку, где работает функция, поскольку даже без релятушни две функции, работающие одновременно, нарушат питушню об уникальности, и придётся добавлять ещё пространственные координаты для глобального уникального иденпитухатора.
                      2. Движется ли время назад, стоит ли оно? Если нет, то идентификатор всегда меняется со временем, нелинейность интересует только авторов физической реализации, которым придётся поднимать разрешение тайстемпа.
                      3. Как ведёт себя функция от времени? Аппаратура, которая её вычисляет, следит за временем или привязана к метавремени, а время - это то, что показывают часы? Если вычислитель функции замедляется во времени, когда замедляется время, то для него время всегда линейно, таймстемпы должны иметь фиксированное разрешение, проблем нет, кроме случаев, когда время решило пойти назад, а функция вычислилась по-другому.
                      Вариант, когда вычислитель функции рассинхронизован со временем, не так невозможен, как это кажется на первый взгляд. Вероятно, это вообще будет единственной из реальных проблем. Дело в том, что вычислитель функции и часы будут неминуемо находиться в разных точках пространства, время там будет течь по-другому, и передача результата куда-то наружу может занимать чуть разное время.
                      Ответить
                      • Мне кажется вы просто не мыслите хацкельно-функционально.

                        В программе на хаскеле нужно думать четрырёхмерно, т.к там нет времени.
                        У переменных нет прошлого состояния и нет будущего состояния.

                        Точнее они есть, просто в виде ещё одного измерения — последовательности состояний.

                        Есть множество переменных, представляющих совокупность состояний переменной в императивной программе (представьте себе миллион стрел соответсвующих стреле в каждой точке её полёта).

                        Проще всего представить время обычным счётчиком.

                        Как сделать переменную-счётчик, если простое i=i+1 в хаскеле не работает? Вернуть монаду! То же и со временем.
                        Ответить
                  • > время является уникальным идентификатором и может служить единственным аргументом нечистых функций

                    Так же служить аргументом нечистых функций может обычный монадный счётчик.
                    Просто вы не мыслите в дискурсе вневременной иммутабельности.
                    Ответить
              • Какой багор )))
                https://phoeagon.github.io/dev-random-as-a-service/
                Ответить
          • ЕМНИП, GET по стандарту идемпотентен, так что его можно смело кэшировать/прелоадить.
            Но да, было бы неплохо доложить в полковую канцелярию список солдат, которым не была сделана тифозная прививка правила обработки заголовков.
            Ответить
            • показать все, что скрытоvanished
              Ответить
            • > GET по стандарту идемпотентен
              Открыл для интереса "govnokod.ru". Сетевая вкладка в инструментах питуха в браузере говорит, что это был БАГОР GET.
              Но "govnokod.ru" постоянно выдаёт разные эффекты, как и остальные сайты.
              Так что если этот стандарт есть, то любая питушня с обновляемым контентом (чуть менее, чем каждая заглавная страница) его нарушает.

              Так что тут как-то сложно с правилами. Захотел кто-то явно прелоада или кэширования - ну так дайте, не видите, что человеку плохо? А не просил - значит творится любая питушня.
              Ответить
              • Неправильно я ЕМНИПнул.
                https://stackoverflow.com/questions/45016234/what-is-idempotency-in-http-methods.
                >>> A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.
                Действительно, про ответ тут ничего не говорится.
                Ответить
                • Какая-то питушня, не относящаяся к реальной жизни. Какая-то идемпотентность со множеством оговорок, звёздочек и скрытых комиссий.

                  Идемпотентность GET имеет только сайт-визитка CSS/HTML-программиста на бесплатном хостинге, где PHP выключен на сервере.
                  В старое время были PUT и DELETE, которые меняли эффект GET. Сейчас это POST-питушня, влияющая на БД.
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                    • Так бы и писали. А то наплодили каких-то терминов питушарских, смысла которых не знают.
                      Сообщение видел.
                      Ответить
                  • Ну почему, вроде всё нормально:
                    >>> To illustrate this, consider the DELETE method, which is defined as idempotent. Now consider a client performs a DELETE request to delete a resource from the server. The server processes the request, the resource gets deleted and the server returns 204. Then the client repeats the same DELETE request and, as the resource has already been deleted, the server returns 404.
                    >>>Despite the different status code received by the client, the effect produced by a single DELETE request is the same effect of multiple DELETE requests to the same URI.

                    Сколько раз govnokod.ru/comments не дёргай — эффект на состояние сервера будет одинаковым.
                    Ответить

    Добавить комментарий