
فازر DOM
كتبه ويشرف عليه Ivan Fratric، [email protected]
حقوق النشر 2017 Google Inc. جميع الحقوق محفوظة.
مرخّص بموجب رخصة Apache، الإصدار 2.0 (يُشار إليها فيما يلي باسم "الرخصة")؛ لا يجوز لك استخدام هذا الملف إلا امتثالاً للرخصة. يمكنك الحصول على نسخة من الرخصة على:
http://www.apache.org/licenses/LICENSE-2.0
ما لم يكن ذلك مطلوبًا بموجب القانون المعمول به أو متفقًا عليه كتابيًا، يتم توزيع البرنامج الموزَّع بموجب الرخصة على أساس "كما هو" (AS IS)، دون أي ضمانات أو شروط من أي نوع، سواء كانت صريحة أو ضمنية. راجع الرخصة للاطلاع على الصلاحيات والقيود المحددة التي تحكم الاستخدام.
لعرض معلومات الاستخدام، نفّذ الأمر التالي:
python3 generator.py --help
لتوليد عيّنة .html واحدة، نفّذ:
python generator.py --file <output file>
لتوليد عيّنة .html واحدة باستخدام قالب كتبته بنفسك، نفّذ:
python generator.py --file <output file> --template <your custom template file>
لتوليد عيّنات متعددة باستدعاء واحد، نفّذ:
python generator.py --output_dir <output directory> --no_of_files <number of output files>
سيتم وضع العيّنات المولّدة في الدليل المحدد وستُسمى fuzz-<number>.html، مثل fuzz-00001.html و fuzz-00002.html وهكذا. يعد توليد عيّنات متعددة أسرع لأن ملفات القواعد تحتاج إلى التحميل والتحليل مرة واحدة فقط.
يحتوي generator.py على النص البرمجي الرئيسي. يستخدم grammar.py كمكتبة ويحتوي على كود مساعد إضافي لفازنغ DOM.
يحتوي grammar.py على محرك التوليد الذي يكون في معظمه غير مرتبط بتطبيق معين، وبالتالي يمكن استخدامه في أدوات فازنغ أخرى قائمة على التوليد (أي غير مخصصة لـ DOM). ولأنه يمكن استخدامه كمكتبة، فقد تم وصف استخدامه في قسم منفصل أدناه.
تحتوي ملفات .txt على تعريفات القواعد. هناك 3 ملفات رئيسية، وهي html.txt و css.txt و js.txt، وتحتوي على قواعد HTML و CSS و JavaScript على الترتيب. وقد تتضمن ملفات القواعد الجذرية هذه محتوى من ملفات أخرى.
لاستخدام محرك التوليد مع قواعد مخصصة، يمكنك استخدام كود Python التالي:
from grammar import Grammar
my_grammar = Grammar()
my_grammar.parse_from_file('input_file.txt')
result_string = my_grammar.generate_symbol('symbol_name')
تصف الأقسام التالية صيغة ملفات القواعد.
يعتمد Domato على محرك يقوم، عند تزويده بقواعد خالية من السياق (context-free grammar) بصيغة بسيطة محددة أدناه، بتوليد عيّنات من تلك القواعد.
تُوصف القواعد النحوية على أنها مجموعة من القواعد الإنتاجية بالصيغة الأساسية التالية:
<symbol> = a mix of constants and <other_symbol>s
تحتوي كل قاعدة على جانب أيسر وجانب أيمن يفصل بينهما حرف المساواة. يحتوي الجانب الأيسر على رمز (symbol)، بينما يحتوي الجانب الأيمن على تفاصيل كيفية توسيع هذا الرمز. عند توسيع رمز ما، تتم توسعة جميع الرموز في الجانب الأيمن بشكل تكراري، في حين أن كل ما ليس رمزًا يُنسخ ببساطة إلى المخرجات. لاحظ أن القاعدة الواحدة لا يمكن أن تمتد على أكثر من سطر واحد في ملف الإدخال.
لننظر إلى المثال المبسّط التالي لجزء من قواعد CSS:
<cssrule> = <selector> { <declaration> }
<selector> = a
<selector> = b
<declaration> = width:100%
إذا طلبنا من محرك القواعد تحليل هذه القواعد وتوليد 'cssrule'، فقد نحصل في النهاية على أي من الناتجين:
a { width:100% }
أو
b { width:100% }
لاحظ وجود قاعدتين للرمز 'selector'. في مثل هذه الحالات، عندما يُطلب من المولّد توليد رمز 'selector'، سيختار القاعدة التي سيستخدمها بشكل عشوائي. ومن الممكن أيضًا تحديد احتمال القاعدة باستخدام الخاصية 'p'، على سبيل المثال:
<selector p=0.9> = a
<selector p=0.1> = b
في هذه الحالة، سيتم إخراج السلسلة 'a' بشكل أكثر تكرارًا من 'b'.
هناك خصائص أخرى يمكن تطبيقها على الرموز بالإضافة إلى الاحتمال. وهذه الخصائص مدرجة في قسم منفصل.
لننظر إلى مثال آخر لتوليد عيّنات html:
<html> = <lt>html<gt><head><body><lt>/html<gt>
<head> = <lt>head<gt>...<lt>/head<gt>
<body> = <lt>body<gt>...<lt>/body<gt>
لاحظ أنه بما أن '<' و '>' لهما معنى خاص في صيغة القواعد، فإننا نستخدم هنا <lt> و <gt> بدلاً منهما. هذه الرموز مدمجة في المحرك ولا تحتاج إلى تعريفها من قبل المستخدم. توجد قائمة بجميع الرموز المدمجة في قسم منفصل.
لتوليد كود بلغة برمجة، يمكن استخدام صيغة مشابهة، لكن هناك بضعة اختلافات. كل سطر من قواعد لغة البرمجة سيقابل سطرًا من المخرجات. وبسبب ذلك، ستكون صيغة القواعد أكثر حريةً للسماح بالتعبير عن الإنشاءات البرمجية في لغات برمجة مختلفة. ثانيًا، عند توليد سطر، وبالإضافة إلى إخراج السطر، قد يتم إنشاء متغير واحد أو أكثر، ويمكن إعادة استخدام تلك المتغيرات عند توليد أسطر أخرى. مرة أخرى، لنلقِ نظرة على المثال المبسّط:
!varformat fuzzvar%05d
!lineguard try { <line> } catch(e) {}
!begin lines
<new element> = document.getElementById("<string min=97 max=122>");
<element>.doSomething();
!end lines
إذا طلبنا من المحرك توليد 5 أسطر، فقد نحصل في النهاية على شيء مثل:
try { var00001 = document.getElementById("hw"); } catch(e) {}
try { var00001.doSomething(); } catch(e) {}
try { var00002 = document.getElementById("feezcqbndf"); } catch(e) {}
try { var00002.doSomething(); } catch(e) {}
try { var00001.doSomething(); } catch(e) {}
لاحظ أن:
<new element> بدلاً من <element>. يوجّه هذا المولّد إلى إنشاء متغير جديد من النوع 'element' بدلاً من توليد الرمز 'element'.<string> هو أحد الرموز المدمجة، لذا لا حاجة لتعريفه.كل ما يلي أول حرف '#' في السطر يُعتبر تعليقًا، على سبيل المثال:
#This is a comment
توفر صيغة القواعد طريقةً لإخبار أداة الفازنغ بالقواعد غير التكرارية التي يمكن استخدامها بأمان حتى لو تم بلوغ أقصى مستوى للتكرار. ويتم ذلك باستخدام خاصية ‘nonrecursive’. مثال موضح أدناه.
!max_recursion 10
<test root=true> = <foobar>
<foobar> = foo<foobar>
<foobar nonrecursive> = bar
أولاً، يحدد بيان اختياري باسم ‘!max_recursion’ أقصى عمق للتكرار (50 افتراضيًا). لاحظ أن القاعدة الإنتاجية الثانية للرمز ‘foobar’ معلمة على أنها غير تكرارية. إذا تم بلوغ أقصى مستوى للتكرار في أي وقت، سيفرض المولّد استخدام القاعدة غير التكرارية للرمز ‘foobar’، مما يمنع التكرار اللانهائي.
في Domato، يعد تضمين القواعد واستيرادها سياقين مختلفين.
التضمين أبسط. يمكنك استخدام:
!include other.txt
لتضمين القواعد من other.txt في القواعد التي يتم تحليلها حاليًا.
أما الاستيراد فيعمل بشكل مختلف قليلاً:
!import other.txt
يخبر المحلل بإنشاء كائن Grammar() جديد يمكن الرجوع إليه من القواعد الحالية باستخدام الرمز الخاص <import>، على سبيل المثال كما يلي:
<cssrule> = <import from=css.txt symbol=rule>
يمكنك التفكير في الاستيراد والتضمين من منظور مساحات الأسماء (namespaces): سيضع بيان !include القواعد المضمّنة في مساحة الأسماء الموحدة، بينما ينشئ بيان !import مساحة أسماء جديدة يمكن الوصول إليها بعد ذلك باستخدام الرمز <import> ومساحة الأسماء المحددة عبر الخاصية 'from'.
قد ترغب أحيانًا في استدعاء كود Python مخصص من داخل قواعدك. على سبيل المثال، لنفترض أنك تريد استخدام المحرك لتوليد استجابة HTTP وتريد أن يتطابق طول الجسم (body) مع ترويسة 'Size'. وبما أن هذا أمر غير ممكن باستخدام قواعد نحوية عادية، يمكنك تضمين كود Python مخصص لإنجازه كما يلي:
!begin function savesize
context['size'] = ret_val
!end function
!begin function createbody
n = int(context['size'])
ret_val = 'a' * n
!end function
<foo root> = <header><cr><lf><body>
<header> = Size: <int min=1 max=20 beforeoutput=savesize>
<body> = <call function=createbody>
تُعرَّف دوال Python بين الأمرين ‘!begin function <function_name>’ و ‘!end function’. يمكن استدعاء الدوال بطريقتين: باستخدام الخاصية ‘beforeoutput’ وباستخدام الرمز <call>.
عند تحديد الخاصية ‘beforeoutput’ في أحد الرموز، سيتم استدعاء الدالة المقابلة عند توسيع هذا الرمز، وذلك قبل إخراج نتيجة التوسيع إلى العيّنة مباشرة. ستُمرَّر نتيجة التوسيع إلى الدالة في متغير ret_val. وتكون الدالة حرة بعد ذلك في تعديل ret_val أو تخزينه لاستخدام لاحق أو تنفيذ أي عمليات أخرى.
عند استخدام الرمز الخاص <call>، سيتم استدعاء الدالة (المحددة في الخاصية ‘function’) عندما يُصادف الرمز أثناء توليد اللغة. أي قيمة تخزنها الدالة في ret_val ستُعتبر نتيجة التوسيع (يُضمَّن ret_val في العيّنة).
لدى كود Python الخاص بك إمكانية الوصول إلى المتغيرات التالية:
context - قاموس (dictionary) يتم تمريره عبر عملية توليد العيّنة بأكملها. يمكنك استخدامه لتخزين القيم (مثل تخزين الحجم في المثال أعلاه) واسترجاعها في القواعد التي يتم تفعيلها لاحقًا.attributes - قاموس يطابق الرمز الذي تتم معالجته حاليًا. يمكنك استخدامه لتمرير المعاملات إلى دوالك. على سبيل المثال، إذا استخدمت شيئًا مثل <call function=func foo=bar> لاستدعاء الدالة، فسيتم تعيين attributes[‘foo’] إلى ‘bar’.ret_val - القيمة التي سيتم إخراجها كنتيجة لاستدعاء الدالة. تتم تهيئتها إلى قيمة فارغة عند استخدام الرمز <call> لاستدعاء دالة، وإلا فستتم تهيئتها إلى القيمة المولّدة بواسطة الرمز.الرموز التالية لها معنى خاص ولا ينبغي للمستخدمين إعادة تعريفها:
<lt> - الحرف ‘<’<gt> - الحرف ‘>’<hash> - الحرف ‘#’<cr> - حرف الإرجاع (CR)<lf> - حرف تغذية السطر (LF)<space> - حرف المسافة<tab> - حرف الجدولة (Tab)<ex> - الحرف ‘!’<char> - يمكن استخدامه لتوليد حرف ascii عشوائي باستخدام الخاصية ‘code’. على سبيل المثال، يقابل <char code=97> الحرف ‘a’. يولّد حرفًا عشوائيًا إذا لم تُحدد الخاصية. يدعم الخاصيتين ‘min’ و ‘max’.<hex> - يولّد رقمًا سداسيًا عشريًا (hex) عشوائيًا.<int>, <int 8>, <uint8>, , , , , , - يمكن استخدامها لتوليد أعداد صحيحة عشوائية. تدعم الخاصيتين ‘min’ و ‘max’ اللتين يمكن استخدامهما لتحديد نطاق الأعداد الصحيحة التي سيتم توليدها. وتدعم الخاصيتين ‘b’ و ‘be’ اللتين تجعلان المخرجات ثنائية بصيغة endian الصغير/الكبير (little/big endian) بدلاً من المخرجات النصية.الخصائص التالية مدعومة:
‘doSomething(<int id=1>, <int id=1>)’ سينتهي المطاف بكلا العددين الصحيحين بالقيمة نفسها. في الواقع، يتم توسيع المثيل الأول فقط، بينما يُنسخ الثاني من الأول.<call>، راجع قسم ‘تضمين كود Python’ لمزيد من المعلومات.بعض الثغرات التي تم اكتشافها باستخدام Domato:
هذا ليس منتجًا رسميًا من Google.
<int16><uint16><int32><uint32><int64><uint64><float>, <double> - يولّدان رقمًا عشوائيًا بفاصلة عائمة. يدعمان الخاصيتين ‘min’ و ‘max’ (0 و 1 إذا لم تُحددا). ويدعمان الخاصية ‘b’ التي تجعل المخرجات ثنائية.<string> - يولّد سلسلة نصية عشوائية. يدعم الخاصيتين ‘min’ و ‘max’ اللتين تتحكمان في أدنى وأعلى رمز حرف (charcode) يتم توليده، بالإضافة إلى الخاصيتين ‘minlength’ و ‘maxlength’ اللتين تتحكمان في طول السلسلة.<htmlsafestring> - مثل <string> تمامًا، باستثناء أن الرموز الوصفية (metacharacters) الخاصة بـ HTML سيتم إفلاتها (escape)، مما يجعل تضمين السلسلة ضمن نص HTML أو قيم الخصائص آمنًا.<lines> - يُخرج العدد المحدد من أسطر الكود (عبر الخاصية ‘count’). راجع القسم الخاص بتوليد كود لغات البرمجة للحصول على مثال.<import> - يستورد رمزًا من قواعد أخرى، راجع القسم الخاص بتضمين القواعد الخارجية للتفاصيل.<call> - يستدعي دالة معرّفة من قبل المستخدم تقابل الخاصية function. راجع القسم الخاص بتضمين كود Python في القواعد لمزيد من المعلومات.