الخلاصة

  • لا يحمل فهرس جدول HPACK الديناميكي معنى إلا داخل سياق الترميز أو فك الترميز الصحيح، وفي اتجاه وترتيب محددين من اتصال HTTP/2 واحد.
  • إعادة بناء قائمة الحقول ليست إصابة في الذاكرة المؤقتة؛ فمفتاح التخزين والحداثة والتحقق والتفويض ونتيجة التطبيق تحتاج إلى أدلة مستقلة.

تقول لوحة التشغيل إن «ذاكرة HPACK المؤقتة أصابت الهدف». ما حدث فعلياً أضيق من العبارة: أرسل الطرف الأول فهرساً قصيراً، وكان لدى الطرف الآخر في تلك اللحظة جدول يسمح له بإعادة الحقل الطويل. أما وجود استجابة محفوظة تصلح لطلب جديد، فلم يثبته هذا الحدث.

كلا النظامين يستفيد من التكرار. لكن HPACK يتذكر ثمانيات الاسم والقيمة كي يعيد قائمة حقول داخل اتصال، في حين تحفظ ذاكرة HTTP المؤقتة رسائل الاستجابة وتقرر متى يمكن لإحداها أن تجيب عن طلب لاحق. التشابه في الاقتصاد لا يمنحهما السلطة نفسها.

يرتبط روبرتو بيون مباشرة بهذه الطبقة، إذ شارك Hervé Ruellan في تأليف RFC 7541. وتسرد صفحته في IETF Datatracker هذه الوثيقة وRFC 7540، وهي المواصفة الأصلية لـHTTP/2. وتصفه نبذة مؤتمر QCon San Francisco لعام 2012 آنذاك بأنه مهندس في Google ومشارك في إنشاء SPDY. تلك شهادة تاريخية مؤرخة، لا إثباتاً لوظيفته الحالية. كما أن مؤلفي RFC 9113 الحالية أشخاص آخرون.

مهمة HPACK إعادة ترتيب الثمانيات

تعامل RFC 7541 قائمة الحقول بوصفها مجموعة مرتبة من أزواج الاسم والقيمة. يجوز أن تتكرر الأزواج المتطابقة. وعلى مستوى الضغط، ليست الأسماء والقيم سوى سلاسل مبهمة من الثمانيات، ويجب أن يبقى ترتيبها محفوظاً بعد فك الضغط.

لهذا لا يعني إخراج cache-control: private أن HPACK طبّق معنى private. لم ينشئ ذاكرة خاصة ولم يحكم على ذاكرة مشتركة. أعاد الثمانيات إلى القائمة، ثم تأتي طبقة HTTP لتفسرها ضمن الرسالة.

يستخدم HPACK جدولاً ثابتاً وجداول ديناميكية. الجدول الثابت معرّف مسبقاً ولا يتغير. أما الديناميكي فيبدأ فارغاً، وتضاف إليه الحقول أثناء المعالجة، ويقبل قيوداً متطابقة، ويطرد الأقدم كي يبقى تحت حد الذاكرة.

الفهرس إذن إحداثي داخل مساحة متحركة، لا هوية دائمة. يحتل القيد الأحدث أدنى موضع ديناميكي، ثم تغير الإضافات المواضع وتزيل عمليات الطرد القيود القديمة. في اتصال آخر قد يدل الرقم نفسه على حقل مختلف أو يكون غير صالح. تسجيل «الفهرس 63» بلا جيل الجدول يشبه تسجيل رقم مقعد من دون مخطط القاعة.

لكل اتجاه ذاكرته الخاصة

تفصل RFC 7541 تماماً بين جدولي الترميز وفك الترميز الديناميكيين عند كل طرف. يستخدم العميل سياقاً لترميز الطلبات وسياقاً آخر لفك استجابات الخادم، ويحتفظ الخادم بالزوج المقابل. وجودهما في اتصال واحد لا يدمجهما.

تضع RFC 9113 هذا التصميم في HTTP/2 الحالي. لدى كل طرف سياق ترميز وسياق فك ترميز HPACK تستخدمهما جميع كتل الحقول في الاتصال، ويكون الجدول الديناميكي أهم حالة متغيرة في كل سياق.

لذلك لا تكفي عبارة «كان الحقل في جدول الاتصال». يلزم تحديد الطرف والاتجاه ورقم كتلة الحقول والحالة السابقة والحد الفعلي. إذا فات المستقبل إدخال واحد، فقد يفهم المرسل والمستقبل الفهرس اللاحق على أنه ثمانيات مختلفة.

ومن هنا وجوب جمع كتلة الحقول وفكها كاملة حتى إن كان المستقبل ينوي التخلص من الرسالة. قد تحتوي الكتلة أوامر تغير السياق الذي تحتاج إليه تدفقات لاحقة. إسقاط نتيجة تدفق على مستوى التطبيق لا يسمح بتجاوز تاريخ الضغط المشترك.

حد الحجم مسار تفاوض لا مدة حفظ

يبدأ اتصال HTTP/2 بحد أقصى أولي قدره 4096 بايت للجدول المعني. يعلن مفكك الترميز حدّه عبر SETTINGS_HEADER_TABLE_SIZE، ويختار المرمّز حجماً فعالاً لا يتجاوزه، ثم يعبّر عن التغيير بتعليمة تحديث حجم في HPACK.

هذا الرقم قيمة بدء في البروتوكول، لا قياساً لكل منتج منشور. كما أن خفض الحد يعتمد على ترتيب الإعداد وإقراره. وبعد الإقرار يجب، عند الحاجة، أن تبدأ كتلة الحقول التالية بتحديث متوافق مع الحد الجديد.

قد يطرد كل إدخال قيوداً أقدم حتى يتاح المكان. وإذا كان القيد وحده أكبر من السعة القصوى، يُفرغ الجدول ولا يبقى القيد. تلك خصائص قاموس ضغط محدود العمر، لا مستودع استجابات.

حين يختلف السياقان، يكشف نطاق الفشل طبيعة الاعتماد. تطلب RFC 9113 إنهاء الاتصال بخطأ COMPRESSION_ERROR إذا تعذر فك كتلة حقول. ظهرت المشكلة في تدفق واحد، لكن السياق المكسور مشترك بين كتل لاحقة في الاتجاه نفسه. الخطأ يثبت أن محادثة الضغط لا يمكن أن تستمر بأمان، ولا يحكم على صحة العملية التجارية.

ذاكرة HTTP المؤقتة تملك قرار إعادة الاستخدام

تعرّف RFC 9111 ذاكرة HTTP المؤقتة بأنها مخزن محلي لرسائل الاستجابة مع النظام الفرعي الذي يتحكم في حفظها واسترجاعها وحذفها. والغرض أن تخدم استجابة سابقة طلباً لاحقاً عندما تسمح القواعد.

يبدأ الاختيار بمفتاح يضم طريقة الطلب وعنوان URI المستهدف على الأقل. وقد تضيف Vary حقول طلب إلى المقارنة. ثم تُفحص حداثة الاستجابة، أو الإذن باستعمال نسخة قديمة، أو نجاح التحقق من المصدر، وتطبّق توجيهات مثل no-store وprivate وno-cache وقواعد الطلبات ذات التفويض.

لا يحمل قيد HPACK أياً من هذه السلطة. يمكنه حفظ ثمانيات etag: "blue" بلا تمثيل الاستجابة الذي يتحقق منه الوسم. ويمكنه ضغط age: 300 من دون حساب العمر الحالي. ويمكنه إعادة vary: accept-language من دون مقارنة طلبين.

يوضح cache-control: private الفارق. ربما يدخله المرمّز إلى الجدول لأنه متكرر. هذا الإدخال لا ينشئ ذاكرة خاصة ولا يقرر ما يجوز لذاكرة مشتركة. لا تطبق الدلالة إلا طبقة التخزين بعد تحليل الرسالة. قد يُطرد الحقل من HPACK فيما تبقى الاستجابة محفوظة، أو يبقى الحقل فيما لم تُحفظ أي استجابة.

والعكس صحيح أيضاً. قد تعيد إصابة حقيقية في الذاكرة المؤقتة حقولاً حرفية أو مراجع من الجدول الثابت، أو تمر عبر اتصال جديد جدوله الديناميكي فارغ. ضغط الحقل وإعادة استخدام الاستجابة ليس أحدهما شرطاً أو برهاناً للآخر.

نجاح فك الضغط دليل ضيق

يثبت الفهرس الصالح أن المستقبل امتلك حالة متوافقة عند تلك النقطة، فاستعاد قيد الحقل. بعد ذلك تبقى صلاحية الاسم والقيمة في HTTP، وخصائص القناة، وتحويلات الوسطاء، ووصول الطلب إلى المصدر، واستجابة التطبيق أسئلة مستقلة.

لا يملأ فك الضغط هذه الخانات. قد يكون الوسيط عدّل الرسالة، وقد لا يكون المصدر رأى الطلب، وقد يرفض التطبيق قيمة صحيحة نحوياً.

وللسرية حد منفصل. تحذر RFC 7541 من قدرة مهاجم يتحكم في الحقول ويراقب طولها المضغوط على سبر حالة الجدول. يشفر TLS المحتوى، لكنه لا يمحو كل إشارة طول. ليست كل نسبة ضغط متغيرة هجوماً، كما أن قصر التمثيل ليس شهادة أمان.

تمنع الصيغة الحرفية «غير المفهرسة أبداً» إدخال القيمة، وتلزم الوسيط بالحفاظ على هذا الاختيار عند إعادة الترميز. إنها حماية محددة، لا ضماناً شاملاً: القيمة ضعيفة العشوائية قد تبقى قابلة للتخمين، وإشارات الطول قد تبقى، ولا ينشأ عنها تفويض للتطبيق.

إيصالان لحالتين مختلفتين

يسجل إيصال الضغط هوية الاتصال وأدوار الطرفين والاتجاه والتدفق وترتيب كتل الحقول. ويضيف الحد المعلن ووقت الإقرار والحجم الفعال قبل الكتلة وبعدها والإدخالات وعمليات الطرد وتغييرات الحجم وصيغة كل حقل ونتيجة فك الضغط.

أما إيصال HTTP فيبدأ بعد إعادة البناء: الطريقة وURI والحالة ومسار المصدر ودلالة الحقول بعد تحليلها. وإذا دخل التخزين المؤقت، يسجل المفتاح ومدخلات Vary وقرار الحفظ والعمر والحداثة وأدوات التحقق وقواعد التفويض ونتيجة إعادة التحقق وما وصل إلى التطبيق.

قد يثبت التقاط الحزم تزامن HPACK من دون رؤية داخل الذاكرة المؤقتة. وقد يثبت سجل الذاكرة إعادة الاستخدام من دون إظهار تمثيل السلك. يجب أن تبقى الخانة الغائبة فارغة؛ فتذكّر ثمانيات حقل لا يمنح وحده حق إعادة استخدام استجابة.

المصادر