Merge branch 'master' into feature/json_exceptions
| | |
| | | receive a valid JSON response. See: |
| | | https://github.com/Pylons/pyramid/pull/2489 |
| | | |
| | | - (Deprecation) Support for Python 3.3 will be removed in Pyramid 1.8. |
| | | https://github.com/Pylons/pyramid/issues/2477 |
| | | |
| | | - A new event and interface (BeforeTraversal) has been introduced that will |
| | | notify listeners before traversal starts in the router. See |
| | | https://github.com/Pylons/pyramid/pull/2469 and |
| | | https://github.com/Pylons/pyramid/pull/1876 |
| | | |
| | | - Python 2.6 is no longer supported by Pyramid. See |
| | | https://github.com/Pylons/pyramid/issues/2368 |
| | | |
| | |
| | | ``hashalg`` to ``sha512``. |
| | | |
| | | - 1.8: Remove set_request_property. |
| | | - 1.8: Drop Python 3.3 support. |
| | | |
| | | - 1.9: Remove extra code enabling ``pyramid.security.remember(principal=...)`` |
| | | and force use of ``userid``. |
| | |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>12</real> |
| | | <real>13</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>2</integer> |
| | |
| | | <key>GraphicsList</key> |
| | | <array> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 294.65604172230951}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169515</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, -0.49999999999999645}</string> |
| | | <string>{-0.49526813868737474, -0.4689979626999552}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 CSRF checks}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Class</key> |
| | | <string>LineGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>w</key> |
| | | <string>0</string> |
| | | </dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>12</real> |
| | | </dict> |
| | | <key>Head</key> |
| | | <dict> |
| | | <key>ID</key> |
| | | <integer>169513</integer> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169514</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Points</key> |
| | | <array> |
| | | <string>{154.9999760464211, 209.11365574251681}</string> |
| | | <string>{239.8333613077798, 209.14732074737549}</string> |
| | | </array> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>stroke</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.0980392</string> |
| | | <key>g</key> |
| | | <string>0.0980392</string> |
| | | <key>r</key> |
| | | <string>0.0980392</string> |
| | | </dict> |
| | | <key>HeadArrow</key> |
| | | <string>0</string> |
| | | <key>Legacy</key> |
| | | <true/> |
| | | <key>Pattern</key> |
| | | <integer>2</integer> |
| | | <key>TailArrow</key> |
| | | <string>0</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Tail</key> |
| | | <dict> |
| | | <key>ID</key> |
| | | <integer>169373</integer> |
| | | <key>Position</key> |
| | | <real>0.47711458802223206</real> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{239.83336130777977, 197.875}, {105.66666412353516, 22.544641494750977}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169513</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.999449</string> |
| | | <key>g</key> |
| | | <string>0.743511</string> |
| | | <key>r</key> |
| | | <string>0.872276</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 BeforeTraversal}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Class</key> |
| | | <string>LineGraphic</string> |
| | | <key>FontInfo</key> |
| | |
| | | <integer>0</integer> |
| | | <key>Points</key> |
| | | <array> |
| | | <string>{344.41668319702148, 402.88506673894034}</string> |
| | | <string>{375.5, 402.77232108797347}</string> |
| | | <string>{344.41668319702148, 411.88506673894034}</string> |
| | | <string>{375.5, 411.77232108797347}</string> |
| | | </array> |
| | | <key>Style</key> |
| | | <dict> |
| | |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 275.99999999999994}, {105.75002924601222, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>Group</string> |
| | | <key>Graphics</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169506</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, -0.49999999999999645}</string> |
| | | <string>{-0.49526813868737474, -0.4689979626999552}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 284.99999999999994}, {105.75002924601222, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169506</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, -0.49999999999999645}</string> |
| | | <string>{-0.49526813868737474, -0.4689979626999552}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 authorization}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 421.15071036499205}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169507</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, 0.5}</string> |
| | | <string>{-0.49999999999999911, 0.49999999999999289}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 412.15071036499205}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169507</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, 0.5}</string> |
| | | <string>{-0.49999999999999911, 0.49999999999999289}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 decorators egress}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 312.65604172230951}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169508</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, -0.49999999999999645}</string> |
| | | <string>{-0.49526813868737474, -0.4689979626999552}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 303.65604172230951}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169508</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | <string>{0.50000000000000089, -0.49999999999999645}</string> |
| | | <string>{-0.49526813868737474, -0.4689979626999552}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 decorators ingress}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 402.55704269887212}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169509</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 393.55704269887212}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169509</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 response adapter}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 383.90099016834085}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169510</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 374.90099016834085}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169510</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 view mapper egress}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 350.36561209044055}, {105.66668701171875, 33.089282989501953}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169511</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.422927</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 341.36561209044055}, {105.66668701171875, 33.089282989501953}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169511</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.422927</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 view}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 331.26348241170439}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>FontInfo</key> |
| | | <dict> |
| | | <key>Font</key> |
| | | <string>Helvetica</string> |
| | | <key>Size</key> |
| | | <real>11</real> |
| | | </dict> |
| | | <key>ID</key> |
| | | <integer>169512</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{238.74999618530273, 322.26348241170439}, {105.66668701171875, 18.656048080136394}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | | <integer>169512</integer> |
| | | <key>Magnets</key> |
| | | <array> |
| | | <string>{0, 1}</string> |
| | | <string>{0, -1}</string> |
| | | <string>{1, 0}</string> |
| | | <string>{-1, 0}</string> |
| | | </array> |
| | | <key>Shape</key> |
| | | <string>Rectangle</string> |
| | | <key>Style</key> |
| | | <dict> |
| | | <key>fill</key> |
| | | <dict> |
| | | <key>Color</key> |
| | | <dict> |
| | | <key>b</key> |
| | | <string>0.637876</string> |
| | | <key>g</key> |
| | | <string>1</string> |
| | | <key>r</key> |
| | | <string>1</string> |
| | | </dict> |
| | | </dict> |
| | | <key>shadow</key> |
| | | <dict> |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | <key>Draws</key> |
| | | <string>NO</string> |
| | | <key>ShadowVector</key> |
| | | <string>{2, 2}</string> |
| | | </dict> |
| | | </dict> |
| | | <key>Text</key> |
| | | <dict> |
| | | <key>Text</key> |
| | | <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 |
| | | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} |
| | | {\colortbl;\red255\green255\blue255;} |
| | | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc |
| | | |
| | | \f0\fs20 \cf0 view mapper ingress}</string> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | </array> |
| | | <key>ID</key> |
| | | <integer>169505</integer> |
| | | <key>Layer</key> |
| | | <integer>0</integer> |
| | | <key>VerticalPad</key> |
| | | <integer>0</integer> |
| | | </dict> |
| | | </dict> |
| | | <dict> |
| | | <key>Class</key> |
| | |
| | | <integer>0</integer> |
| | | <key>Points</key> |
| | | <array> |
| | | <string>{238.74999618530282, 430.80675844512831}</string> |
| | | <string>{238.74999618530282, 439.80675844512831}</string> |
| | | <string>{207.66666666666765, 385.656005859375}</string> |
| | | </array> |
| | | <key>Style</key> |
| | |
| | | <integer>0</integer> |
| | | <key>Points</key> |
| | | <array> |
| | | <string>{239.25039065750093, 285.57837549845181}</string> |
| | | <string>{239.25039065750093, 276.57837549845181}</string> |
| | | <string>{207.66666666666777, 353.07514659563753}</string> |
| | | </array> |
| | | <key>Style</key> |
| | |
| | | </dict> |
| | | <dict> |
| | | <key>Bounds</key> |
| | | <string>{{375.5, 391.5}, {105.66666412353516, 22.544642175946908}}</string> |
| | | <string>{{375.5, 400.5}, {105.66666412353516, 22.544642175946908}}</string> |
| | | <key>Class</key> |
| | | <string>ShapedGraphic</string> |
| | | <key>ID</key> |
| | |
| | | <string>YES</string> |
| | | <key>HPages</key> |
| | | <integer>1</integer> |
| | | <key>HorizontalGuides</key> |
| | | <array> |
| | | <real>209.875</real> |
| | | </array> |
| | | <key>ImageCounter</key> |
| | | <integer>3</integer> |
| | | <key>KeepToScale</key> |
| | |
| | | <key>MasterSheets</key> |
| | | <array/> |
| | | <key>ModificationDate</key> |
| | | <string>2016-03-13 08:04:48 +0000</string> |
| | | <string>2016-04-13 08:32:47 +0000</string> |
| | | <key>Modifier</key> |
| | | <string>Steve Piercy</string> |
| | | <key>NotesVisible</key> |
| | |
| | | </dict> |
| | | </array> |
| | | <key>Frame</key> |
| | | <string>{{35, 93}, {1394, 1325}}</string> |
| | | <string>{{35, 93}, {2284, 1325}}</string> |
| | | <key>ListView</key> |
| | | <true/> |
| | | <key>OutlineWidth</key> |
| | |
| | | <key>SidebarWidth</key> |
| | | <integer>163</integer> |
| | | <key>VisibleRegion</key> |
| | | <string>{{152.25, 226.5}, {255.75, 292.75}}</string> |
| | | <string>{{110.125, 77.875}, {239.125, 146.375}}</string> |
| | | <key>Zoom</key> |
| | | <real>4</real> |
| | | <real>8</real> |
| | | <key>ZoomValues</key> |
| | | <array> |
| | | <array> |
| | | <string>Request Processing</string> |
| | | <real>4</real> |
| | | <real>8</real> |
| | | <real>4</real> |
| | | </array> |
| | | </array> |
| | | </dict> |
| | |
| | | <?xml version="1.0"?> |
| | | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="91 11 424 533" width="424pt" height="533pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2016-03-13 08:04Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.4 --></metadata><defs><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="SharpArrow_Marker" viewBox="-4 -4 10 8" markerWidth="10" markerHeight="8" color="#191919"><g><path d="M 5 0 L -3 -3 L 0 0 L 0 0 L -3 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><font-face font-family="Helvetica" font-size="10" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="10" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Request Processing</title><rect fill="white" width="576" height="733"/><g><title>no exceptions</title><path d="M 155 444.75674 C 155 450.64061 155 486.2592 155 502.71617" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99999 322.33334 C 154.99999 327.72413 155 337.74646 155 346.1775" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99999 245.22768 C 154.99999 250.5417 154.99999 257.93189 154.99999 265.10145" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99995 198.62203 C 154.99995 203.74682 154.99998 209.1909 154.99999 215.28222" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="102.16667" y="45.183037" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="45.183037" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 50.455358)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="4.7596016" y="10" textLength="88.92578">middleware ingress </tspan></text><rect x="102.16667" y="96.183037" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="96.183037" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 101.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.983723" y="10" textLength="61.69922">tween ingress</tspan></text><rect x="102.16667" y="222.18304" width="105.666664" height="22.544641" fill="#d2ffd0"/><rect x="102.16667" y="222.18304" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 227.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="28.660969" y="10" textLength="38.344727">traversal</tspan></text><rect x="238.83336" y="247.18304" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="238.83336" y="247.18304" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 252.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.424641" y="10" textLength="62.817383">ContextFound</tspan></text><rect x="102.16667" y="422.2121" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="422.2121" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 427.48442)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="18.094563" y="10" textLength="59.47754">tween egress</tspan></text><rect x="239" y="445.2359" width="105.666664" height="22.544641" fill="#fed153"/><rect x="239" y="445.2359" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244 450.50821)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="5.3113594" y="10" textLength="85.043945">response callbacks</tspan></text><rect x="239" y="497.2359" width="105.666664" height="22.544641" fill="#fed153"/><rect x="239" y="497.2359" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244 502.5082)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="8.6463203" y="10" textLength="5">fi</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="13.64632" y="10" textLength="73.374023">nished callbacks</tspan></text><rect x="102.16667" y="509.61795" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="509.61795" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 514.89027)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="5.8704414" y="10" textLength="83.92578">middleware egress</tspan></text><path d="M 155 67.72768 C 155 73.048893 155 81.55558 155 89.2853" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 155 119.22768 C 155 124.62026 154.99997 133.48763 154.99996 141.38632" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="375.5" y="391.5" width="105.666664" height="22.544642" fill="#dfbeff"/><rect x="375.5" y="391.5" width="105.666664" height="22.544642" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(380.5 396.77232)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.702961" y="10" textLength="62.260742">BeforeRender</tspan></text><text transform="translate(233.5 20)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".31445312" y="11" textLength="115.371094">Request Processing</tspan></text><path d="M 375.99995 42.910746 L 498.66662 42.910746 C 501.42805 42.910746 503.66662 45.149323 503.66662 47.910746 L 503.66662 222 C 503.66662 224.76142 501.42805 227 498.66662 227 L 375.99995 227 C 373.23853 227 370.99995 224.76142 370.99995 222 L 370.99995 47.910746 C 370.99995 45.149323 373.23853 42.910746 375.99995 42.910746 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(375.99995 42.910746)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="bold" x="0" y="10" textLength="35.55664">Legend</tspan></text><rect x="383.66662" y="63.908513" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="383.66662" y="63.908513" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 69.180834)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="35.601887" y="10" textLength="24.46289">event</tspan></text><rect x="383.66662" y="186.58226" width="105.666664" height="22.544641" fill="#fed153"/><rect x="383.66662" y="186.58226" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 191.85458)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="29.769367" y="10" textLength="36.12793">callback</tspan></text><rect x="383.66662" y="158.54998" width="105.666664" height="22.544641" fill="#ffff6c"/><rect x="383.66662" y="158.54998" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 163.8223)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="21.158527" y="10" textLength="53.34961">view deriver</tspan></text><rect x="383.66662" y="91.94079" width="105.666664" height="33.089283" fill="#a4cfff"/><rect x="383.66662" y="91.94079" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 96.48543)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="11.148762" y="10" textLength="76.14746">external process </tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="2.8162422" y="22" textLength="90.03418">(middleware, tween)</tspan></text><rect x="383.66662" y="130.51771" width="105.666664" height="22.544641" fill="#d2ffd0"/><rect x="383.66662" y="130.51771" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 135.79003)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="12.537922" y="10" textLength="70.59082">internal process</tspan></text><line x1="154.99999" y1="258.44082" x2="238.83336" y2="258.45536" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="102.16667" y="353.07515" width="105.666664" height="33.089283" fill="#ffff6c"/><rect x="102.16667" y="353.07515" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 363.61979)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.205402" y="10" textLength="57.25586">view pipeline</tspan></text><path d="M 155 386.66443 C 155 392.17252 155 405.5052 155 415.30935" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><line x1="239.25039" y1="285.57838" x2="207.66667" y2="353.07515" stroke="#c1c1c1" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,3"/><line x1="238.75" y1="430.80676" x2="207.66667" y2="385.656" stroke="#c1c1c1" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,3"/><rect x="102.16666" y="305.0893" width="105.666664" height="17.244049" fill="#d2ffd0"/><rect x="102.16666" y="305.0893" width="105.666664" height="17.244049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16666 307.71132)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="24.764484" y="10" textLength="46.137695">predicates</tspan></text><rect x="102.16666" y="272" width="105.666664" height="33.089294" fill="#d2ffd0"/><rect x="102.16666" y="272" width="105.666664" height="33.089294" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16666 282.54465)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="21.707844" y="10" textLength="52.250977">view lookup</tspan></text><rect x="102.166606" y="181.37798" width="105.666695" height="17.244049" fill="#d2ffd0"/><rect x="102.166606" y="181.37798" width="105.666695" height="17.244049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.166606 184)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="11.978855" y="10" textLength="71.708984">route predicates</tspan></text><rect x="102.166606" y="148.28869" width="105.666695" height="33.089294" fill="#d2ffd0"/><rect x="102.166606" y="148.28869" width="105.666695" height="33.089294" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.166606 158.83333)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="18.001804" y="10" textLength="20.004883">URL</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.640476" y="10" textLength="40.024414"> dispatch</tspan></text><rect x="239.8334" y="117.3192" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="239.8334" y="117.3192" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244.8334 122.59152)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.207844" y="10" textLength="57.250977">NewRequest</tspan></text><line x1="154.99999" y1="128.68025" x2="239.8334" y2="128.59152" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.83336" y="471.2262" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="238.83336" y="471.2262" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 476.49852)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="15.316242" y="10" textLength="65.03418">NewResponse</tspan></text><line x1="155" y1="470.25295" x2="238.33861" y2="482.42625" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.75" y="322.26348" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="322.26348" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 325.5915)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="1.9812927" y="10" textLength="91.7041">view mapper ingress</tspan></text><rect x="238.75" y="341.36561" width="105.66669" height="33.089283" fill="#ffff6c"/><rect x="238.75" y="341.36561" width="105.66669" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 351.91025)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.830902" y="10" textLength="20.004883">view</tspan></text><rect x="238.75" y="374.901" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="374.901" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 378.22901)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="3.0921326" y="10" textLength="89.48242">view mapper egress</tspan></text><rect x="238.75" y="393.55704" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="393.55704" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 396.88507)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="8.917328" y="10" textLength="77.83203">response adapter</tspan></text><rect x="238.75" y="303.65604" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="303.65604" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 306.98407)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="6.7029724" y="10" textLength="82.26074">decorators ingress</tspan></text><rect x="238.75" y="412.1507" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="412.1507" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 415.47873)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="7.8138123" y="10" textLength="80.039062">decorators egress</tspan></text><rect x="238.75" y="285" width="105.75003" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="285" width="105.75003" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 288.32802)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.244644" y="10" textLength="57.260742">authorization</tspan></text><line x1="155" y1="482.12575" x2="238.52297" y2="508.3584" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><line x1="155" y1="459.27668" x2="238.50027" y2="456.52468" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><line x1="344.41668" y1="402.88507" x2="375.5" y2="402.77232" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/></g></g></svg> |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="91 11 424 533" width="424pt" height="533pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2016-04-13 08:32Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.4 --></metadata><defs><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="SharpArrow_Marker" viewBox="-4 -4 10 8" markerWidth="10" markerHeight="8" color="#191919"><g><path d="M 5 0 L -3 -3 L 0 0 L 0 0 L -3 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><font-face font-family="Helvetica" font-size="10" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="10" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Request Processing</title><rect fill="white" width="576" height="733"/><g><title>no exceptions</title><path d="M 155 444.75674 C 155 450.64061 155 486.2592 155 502.71617" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99999 322.33334 C 154.99999 327.72413 155 337.74646 155 346.1775" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99999 245.22768 C 154.99999 250.5417 154.99999 257.93189 154.99999 265.10145" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99995 198.62203 C 154.99995 203.74682 154.99998 209.1909 154.99999 215.28222" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="102.16667" y="45.183037" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="45.183037" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 50.455358)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="4.7596016" y="10" textLength="88.92578">middleware ingress </tspan></text><rect x="102.16667" y="96.183037" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="96.183037" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 101.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.983723" y="10" textLength="61.69922">tween ingress</tspan></text><rect x="102.16667" y="222.18304" width="105.666664" height="22.544641" fill="#d2ffd0"/><rect x="102.16667" y="222.18304" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 227.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="28.660969" y="10" textLength="38.344727">traversal</tspan></text><rect x="238.83336" y="247.18304" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="238.83336" y="247.18304" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 252.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.424641" y="10" textLength="62.817383">ContextFound</tspan></text><rect x="102.16667" y="422.2121" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="422.2121" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 427.48442)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="18.094563" y="10" textLength="59.47754">tween egress</tspan></text><rect x="239" y="445.2359" width="105.666664" height="22.544641" fill="#fed153"/><rect x="239" y="445.2359" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244 450.50821)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="5.3113594" y="10" textLength="85.043945">response callbacks</tspan></text><rect x="239" y="497.2359" width="105.666664" height="22.544641" fill="#fed153"/><rect x="239" y="497.2359" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244 502.5082)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="8.6463203" y="10" textLength="5">fi</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="13.64632" y="10" textLength="73.374023">nished callbacks</tspan></text><rect x="102.16667" y="509.61795" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="509.61795" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 514.89027)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="5.8704414" y="10" textLength="83.92578">middleware egress</tspan></text><path d="M 155 67.72768 C 155 73.048893 155 81.55558 155 89.2853" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 155 119.22768 C 155 124.62026 154.99997 133.48763 154.99996 141.38632" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="375.5" y="400.5" width="105.666664" height="22.544642" fill="#dfbeff"/><rect x="375.5" y="400.5" width="105.666664" height="22.544642" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(380.5 405.77232)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.702961" y="10" textLength="62.260742">BeforeRender</tspan></text><text transform="translate(233.5 20)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".31445312" y="11" textLength="115.371094">Request Processing</tspan></text><path d="M 375.99995 42.910746 L 498.66662 42.910746 C 501.42805 42.910746 503.66662 45.149323 503.66662 47.910746 L 503.66662 222 C 503.66662 224.76142 501.42805 227 498.66662 227 L 375.99995 227 C 373.23853 227 370.99995 224.76142 370.99995 222 L 370.99995 47.910746 C 370.99995 45.149323 373.23853 42.910746 375.99995 42.910746 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(375.99995 42.910746)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="bold" x="0" y="10" textLength="35.55664">Legend</tspan></text><rect x="383.66662" y="63.908513" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="383.66662" y="63.908513" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 69.180834)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="35.601887" y="10" textLength="24.46289">event</tspan></text><rect x="383.66662" y="186.58226" width="105.666664" height="22.544641" fill="#fed153"/><rect x="383.66662" y="186.58226" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 191.85458)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="29.769367" y="10" textLength="36.12793">callback</tspan></text><rect x="383.66662" y="158.54998" width="105.666664" height="22.544641" fill="#ffff6c"/><rect x="383.66662" y="158.54998" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 163.8223)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="21.158527" y="10" textLength="53.34961">view deriver</tspan></text><rect x="383.66662" y="91.94079" width="105.666664" height="33.089283" fill="#a4cfff"/><rect x="383.66662" y="91.94079" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 96.48543)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="11.148762" y="10" textLength="76.14746">external process </tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="2.8162422" y="22" textLength="90.03418">(middleware, tween)</tspan></text><rect x="383.66662" y="130.51771" width="105.666664" height="22.544641" fill="#d2ffd0"/><rect x="383.66662" y="130.51771" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 135.79003)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="12.537922" y="10" textLength="70.59082">internal process</tspan></text><line x1="154.99999" y1="258.44082" x2="238.83336" y2="258.45536" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="102.16667" y="353.07515" width="105.666664" height="33.089283" fill="#ffff6c"/><rect x="102.16667" y="353.07515" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 363.61979)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.205402" y="10" textLength="57.25586">view pipeline</tspan></text><path d="M 155 386.66443 C 155 392.17252 155 405.5052 155 415.30935" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><line x1="239.25039" y1="276.57838" x2="207.66667" y2="353.07515" stroke="#c1c1c1" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,3"/><line x1="238.75" y1="439.80676" x2="207.66667" y2="385.656" stroke="#c1c1c1" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,3"/><rect x="102.16666" y="305.0893" width="105.666664" height="17.244049" fill="#d2ffd0"/><rect x="102.16666" y="305.0893" width="105.666664" height="17.244049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16666 307.71132)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="24.764484" y="10" textLength="46.137695">predicates</tspan></text><rect x="102.16666" y="272" width="105.666664" height="33.089294" fill="#d2ffd0"/><rect x="102.16666" y="272" width="105.666664" height="33.089294" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16666 282.54465)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="21.707844" y="10" textLength="52.250977">view lookup</tspan></text><rect x="102.166606" y="181.37798" width="105.666695" height="17.244049" fill="#d2ffd0"/><rect x="102.166606" y="181.37798" width="105.666695" height="17.244049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.166606 184)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="11.978855" y="10" textLength="71.708984">route predicates</tspan></text><rect x="102.166606" y="148.28869" width="105.666695" height="33.089294" fill="#d2ffd0"/><rect x="102.166606" y="148.28869" width="105.666695" height="33.089294" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.166606 158.83333)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="18.001804" y="10" textLength="20.004883">URL</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.640476" y="10" textLength="40.024414"> dispatch</tspan></text><rect x="239.8334" y="117.3192" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="239.8334" y="117.3192" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244.8334 122.59152)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.207844" y="10" textLength="57.250977">NewRequest</tspan></text><line x1="154.99999" y1="128.68025" x2="239.8334" y2="128.59152" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.83336" y="471.2262" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="238.83336" y="471.2262" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 476.49852)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="15.316242" y="10" textLength="65.03418">NewResponse</tspan></text><line x1="155" y1="470.25295" x2="238.33861" y2="482.42625" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.75" y="331.26348" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="331.26348" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 334.5915)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="1.9812927" y="10" textLength="91.7041">view mapper ingress</tspan></text><rect x="238.75" y="350.36561" width="105.66669" height="33.089283" fill="#ffff6c"/><rect x="238.75" y="350.36561" width="105.66669" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 360.91025)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.830902" y="10" textLength="20.004883">view</tspan></text><rect x="238.75" y="383.901" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="383.901" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 387.22901)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="3.0921326" y="10" textLength="89.48242">view mapper egress</tspan></text><rect x="238.75" y="402.55704" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="402.55704" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 405.88507)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="8.917328" y="10" textLength="77.83203">response adapter</tspan></text><rect x="238.75" y="312.65604" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="312.65604" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 315.98407)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="6.7029724" y="10" textLength="82.26074">decorators ingress</tspan></text><rect x="238.75" y="421.1507" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="421.1507" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 424.47873)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="7.8138123" y="10" textLength="80.039062">decorators egress</tspan></text><rect x="238.75" y="276" width="105.75003" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="276" width="105.75003" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 279.32802)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.244644" y="10" textLength="57.260742">authorization</tspan></text><line x1="155" y1="482.12575" x2="238.52297" y2="508.3584" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><line x1="155" y1="459.27668" x2="238.50027" y2="456.52468" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><line x1="344.41668" y1="411.88507" x2="375.5" y2="411.77232" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="239.83336" y="197.875" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="239.83336" y="197.875" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244.83336 203.14732)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="12.44759" y="10" textLength="35.57129">BeforeT</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="47.652668" y="10" textLength="35.566406">raversal</tspan></text><line x1="154.99998" y1="209.11366" x2="239.83336" y2="209.14732" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.75" y="294.65604" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.75" y="294.65604" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75 297.98407)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="17.27182" y="10" textLength="61.123047">CSRF checks</tspan></text></g></g></svg> |
| | |
| | | |
| | | .. autoclass:: ContextFound |
| | | |
| | | .. autoclass:: BeforeTraversal |
| | | |
| | | .. autoclass:: NewResponse |
| | | |
| | | .. autoclass:: BeforeRender |
| | |
| | | .. autointerface:: IContextFound |
| | | :members: |
| | | |
| | | .. autointerface:: IBeforeTraversal |
| | | :members: |
| | | |
| | | .. autointerface:: INewResponse |
| | | :members: |
| | | |
| | |
| | | Examples of built-in derivers including view mapper, the permission |
| | | checker, and applying a renderer to a dictionary returned from the view. |
| | | |
| | | truthy string |
| | | A string represeting a value of ``True``. Acceptable values are |
| | | ``t``, ``true``, ``y``, ``yes``, ``on`` and ``1``. |
| | | |
| | | falsey string |
| | | A string represeting a value of ``False``. Acceptable values are |
| | | ``f``, ``false``, ``n``, ``no``, ``off`` and ``0``. |
| | | |
| | | pip |
| | | The `Python Packaging Authority's <https://www.pypa.io/>`_ recommended |
| | | tool for installing Python packages. |
| | |
| | | This element will also output useful debugging information when |
| | | ``pyramid.debug_authorization`` is enabled. |
| | | |
| | | ``csrf_view`` |
| | | |
| | | Used to check the CSRF token provided in the request. This element is a |
| | | no-op if both the ``require_csrf`` view option and the |
| | | ``pyramid.require_default_csrf`` setting are disabled. |
| | | |
| | | ``owrapped_view`` |
| | | |
| | | Invokes the wrapped view defined by the ``wrapper`` option. |
| | |
| | | View derivers are unique in that they have access to most of the options |
| | | passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what |
| | | to do, and they have a chance to affect every view in the application. |
| | | |
| | | Let's look at one more example which will protect views by requiring a CSRF |
| | | token unless ``disable_csrf=True`` is passed to the view: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | from pyramid.session import check_csrf_token |
| | | |
| | | def require_csrf_view(view, info): |
| | | wrapper_view = view |
| | | if not info.options.get('disable_csrf', False): |
| | | def wrapper_view(context, request): |
| | | if request.method == 'POST': |
| | | check_csrf_token(request) |
| | | return view(context, request) |
| | | return wrapper_view |
| | | |
| | | require_csrf_view.options = ('disable_csrf',) |
| | | |
| | | config.add_view_deriver(require_csrf_view) |
| | | |
| | | def protected_view(request): |
| | | return Response('protected') |
| | | |
| | | def unprotected_view(request): |
| | | return Response('unprotected') |
| | | |
| | | config.add_view(protected_view, name='safe') |
| | | config.add_view(unprotected_view, name='unsafe', disable_csrf=True) |
| | | |
| | | Navigating to ``/safe`` with a POST request will then fail when the call to |
| | | :func:`pyramid.session.check_csrf_token` raises a |
| | | :class:`pyramid.exceptions.BadCSRFToken` exception. However, ``/unsafe`` will |
| | | not error. |
| | | |
| | | Ordering View Derivers |
| | | ~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | user-defined :term:`route` matches the current WSGI environment. The |
| | | :term:`router` passes the request as an argument to the mapper. |
| | | |
| | | #. If any route matches, the route mapper adds attributes to the request: |
| | | ``matchdict`` and ``matched_route`` attributes are added to the request |
| | | object. The former contains a dictionary representing the matched dynamic |
| | | elements of the request's ``PATH_INFO`` value, and the latter contains the |
| | | #. If any route matches, the route mapper adds the attributes ``matchdict`` |
| | | and ``matched_route`` to the request object. The former contains a |
| | | dictionary representing the matched dynamic elements of the request's |
| | | ``PATH_INFO`` value, and the latter contains the |
| | | :class:`~pyramid.interfaces.IRoute` object representing the route which |
| | | matched. The root object associated with the route found is also generated: |
| | | if the :term:`route configuration` which matched has an associated |
| | | ``factory`` argument, this factory is used to generate the root object, |
| | | otherwise a default :term:`root factory` is used. |
| | | matched. |
| | | |
| | | #. If a route match was *not* found, and a ``root_factory`` argument was passed |
| | | #. A :class:`~pyramid.events.BeforeTraversal` :term:`event` is sent to any |
| | | subscribers. |
| | | |
| | | #. Continuing, if any route matches, the root object associated with the found |
| | | route is generated. If the :term:`route configuration` which matched has an |
| | | associated ``factory`` argument, then this factory is used to generate the |
| | | root object; otherwise a default :term:`root factory` is used. |
| | | |
| | | However, if no route matches, and if a ``root_factory`` argument was passed |
| | | to the :term:`Configurator` constructor, that callable is used to generate |
| | | the root object. If the ``root_factory`` argument passed to the |
| | | the root object. If the ``root_factory`` argument passed to the |
| | | Configurator constructor was ``None``, a default root factory is used to |
| | | generate a root object. |
| | | |
| | |
| | | The handler for the URL that receives the request should then require that the |
| | | correct CSRF token is supplied. |
| | | |
| | | .. index:: |
| | | single: session.new_csrf_token |
| | | |
| | | Using the ``session.new_csrf_token`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | To explicitly create a new CSRF token, use the ``session.new_csrf_token()`` |
| | | method. This differs only from ``session.get_csrf_token()`` inasmuch as it |
| | | clears any existing CSRF token, creates a new CSRF token, sets the token into |
| | | the session, and returns the token. |
| | | |
| | | .. code-block:: python |
| | | |
| | | token = request.session.new_csrf_token() |
| | | |
| | | Checking CSRF Tokens Manually |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | |
| | | # ... |
| | | |
| | | .. index:: |
| | | single: session.new_csrf_token |
| | | .. _auto_csrf_checking: |
| | | |
| | | Checking CSRF Tokens Automatically |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | .. versionadded:: 1.7 |
| | | |
| | | :app:`Pyramid` supports automatically checking CSRF tokens on POST requests. |
| | | Any other request may be checked manually. This feature can be turned on |
| | | globally for an application using the ``pyramid.require_default_csrf`` setting. |
| | | |
| | | If the ``pyramid.required_default_csrf`` setting is a :term:`truthy string` or |
| | | ``True`` then the default CSRF token parameter will be ``csrf_token``. If a |
| | | different token is desired, it may be passed as the value. Finally, a |
| | | :term:`falsey string` or ``False`` will turn off automatic CSRF checking |
| | | globally on every POST request. |
| | | |
| | | No matter what, CSRF checking may be explicitly enabled or disabled on a |
| | | per-view basis using the ``require_csrf`` view option. This option is of the |
| | | same format as the ``pyramid.require_default_csrf`` setting, accepting strings |
| | | or boolean values. |
| | | |
| | | If ``require_csrf`` is ``True`` but does not explicitly define a token to |
| | | check, then the token name is pulled from whatever was set in the |
| | | ``pyramid.require_default_csrf`` setting. Finally, if that setting does not |
| | | explicitly define a token, then ``csrf_token`` is the token required. This token |
| | | name will be required in ``request.params`` which is a combination of the |
| | | query string and a submitted form body. |
| | | |
| | | It is always possible to pass the token in the ``X-CSRF-Token`` header as well. |
| | | There is currently no way to define an alternate name for this header without |
| | | performing CSRF checking manually. |
| | | |
| | | If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` exception |
| | | will be raised. This exception may be caught and handled by an |
| | | :term:`exception view` but, by default, will result in a ``400 Bad Request`` |
| | | response being sent to the client. |
| | | |
| | | Checking CSRF Tokens with a View Predicate |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | .. deprecated:: 1.7 |
| | | Use the ``require_csrf`` option or read :ref:`auto_csrf_checking` instead |
| | | to have :class:`pyramid.exceptions.BadCSRFToken` exceptions raised. |
| | | |
| | | A convenient way to require a valid CSRF token for a particular view is to |
| | | include ``check_csrf=True`` as a view predicate. See |
| | |
| | | predicate system, when it doesn't find a view, raises ``HTTPNotFound`` |
| | | instead of ``HTTPBadRequest``, so ``check_csrf=True`` behavior is different |
| | | from calling :func:`pyramid.session.check_csrf_token`. |
| | | |
| | | Using the ``session.new_csrf_token`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | To explicitly create a new CSRF token, use the ``session.new_csrf_token()`` |
| | | method. This differs only from ``session.get_csrf_token()`` inasmuch as it |
| | | clears any existing CSRF token, creates a new CSRF token, sets the token into |
| | | the session, and returns the token. |
| | | |
| | | .. code-block:: python |
| | | |
| | | token = request.session.new_csrf_token() |
| | |
| | | only influence ``Cache-Control`` headers, pass a tuple as ``http_cache`` with |
| | | the first element of ``None``, i.e., ``(None, {'public':True})``. |
| | | |
| | | |
| | | ``require_csrf`` |
| | | |
| | | CSRF checks only affect POST requests. Any other request methods will pass |
| | | untouched. This option is used in combination with the |
| | | ``pyramid.require_default_csrf`` setting to control which request parameters |
| | | are checked for CSRF tokens. |
| | | |
| | | This feature requires a configured :term:`session factory`. |
| | | |
| | | If this option is set to ``True`` then CSRF checks will be enabled for POST |
| | | requests to this view. The required token will be whatever was specified by |
| | | the ``pyramid.require_default_csrf`` setting, or will fallback to |
| | | ``csrf_token``. |
| | | |
| | | If this option is set to a string then CSRF checks will be enabled and it |
| | | will be used as the required token regardless of the |
| | | ``pyramid.require_default_csrf`` setting. |
| | | |
| | | If this option is set to ``False`` then CSRF checks will be disabled |
| | | regardless of the ``pyramid.require_default_csrf`` setting. |
| | | |
| | | See :ref:`auto_csrf_checking` for more information. |
| | | |
| | | .. versionadded:: 1.7 |
| | | |
| | | ``wrapper`` |
| | | The :term:`view name` of a different :term:`view configuration` which will |
| | | receive the response body of this view as the ``request.wrapped_body`` |
| | |
| | | config_prevent_cachebust) |
| | | eff_prevent_cachebust = asbool(eget('PYRAMID_PREVENT_CACHEBUST', |
| | | config_prevent_cachebust)) |
| | | require_default_csrf = self.get('pyramid.require_default_csrf') |
| | | eff_require_default_csrf = require_default_csrf |
| | | |
| | | update = { |
| | | 'debug_authorization': eff_debug_all or eff_debug_auth, |
| | |
| | | 'default_locale_name':eff_locale_name, |
| | | 'prevent_http_cache':eff_prevent_http_cache, |
| | | 'prevent_cachebust':eff_prevent_cachebust, |
| | | 'require_default_csrf':eff_require_default_csrf, |
| | | |
| | | 'pyramid.debug_authorization': eff_debug_all or eff_debug_auth, |
| | | 'pyramid.debug_notfound': eff_debug_all or eff_debug_notfound, |
| | |
| | | 'pyramid.default_locale_name':eff_locale_name, |
| | | 'pyramid.prevent_http_cache':eff_prevent_http_cache, |
| | | 'pyramid.prevent_cachebust':eff_prevent_cachebust, |
| | | } |
| | | 'pyramid.require_default_csrf':eff_require_default_csrf, |
| | | } |
| | | |
| | | self.update(update) |
| | | |
| | |
| | | http_cache=None, |
| | | match_param=None, |
| | | check_csrf=None, |
| | | require_csrf=None, |
| | | **view_options): |
| | | """ Add a :term:`view configuration` to the current |
| | | configuration state. Arguments to ``add_view`` are broken |
| | |
| | | this machinery, set ``response.cache_control.prevent_auto = True`` |
| | | before returning the response from the view. This effectively |
| | | disables any HTTP caching done by ``http_cache`` for that response. |
| | | |
| | | require_csrf |
| | | |
| | | .. versionadded:: 1.7 |
| | | |
| | | CSRF checks only affect POST requests. Any other request methods |
| | | will pass untouched. This option is used in combination with the |
| | | ``pyramid.require_default_csrf`` setting to control which |
| | | request parameters are checked for CSRF tokens. |
| | | |
| | | This feature requires a configured :term:`session factory`. |
| | | |
| | | If this option is set to ``True`` then CSRF checks will be enabled |
| | | for POST requests to this view. The required token will be whatever |
| | | was specified by the ``pyramid.require_default_csrf`` setting, or |
| | | will fallback to ``csrf_token``. |
| | | |
| | | If this option is set to a string then CSRF checks will be enabled |
| | | and it will be used as the required token regardless of the |
| | | ``pyramid.require_default_csrf`` setting. |
| | | |
| | | If this option is set to ``False`` then CSRF checks will be disabled |
| | | regardless of the ``pyramid.require_default_csrf`` setting. |
| | | |
| | | See :ref:`auto_csrf_checking` for more information. |
| | | |
| | | wrapper |
| | | |
| | |
| | | |
| | | check_csrf |
| | | |
| | | .. deprecated:: 1.7 |
| | | Use the ``require_csrf`` option or see :ref:`auto_csrf_checking` |
| | | instead to have :class:`pyramid.exceptions.BadCSRFToken` |
| | | exceptions raised. |
| | | |
| | | If specified, this value should be one of ``None``, ``True``, |
| | | ``False``, or a string representing the 'check name'. If the value |
| | | is ``True`` or a string, CSRF checking will be performed. If the |
| | |
| | | 'Predicate" in the "Hooks" chapter of the documentation ' |
| | | 'for more information.'), |
| | | DeprecationWarning, |
| | | stacklevel=4 |
| | | stacklevel=4, |
| | | ) |
| | | |
| | | if check_csrf is not None: |
| | | warnings.warn( |
| | | ('The "check_csrf" argument to Configurator.add_view is ' |
| | | 'deprecated as of Pyramid 1.7. Use the "require_csrf" option ' |
| | | 'instead or see "Checking CSRF Tokens Automatically" in the ' |
| | | '"Sessions" chapter of the documentation for more ' |
| | | 'information.'), |
| | | DeprecationWarning, |
| | | stacklevel=4, |
| | | ) |
| | | |
| | | view = self.maybe_dotted(view) |
| | |
| | | path_info=path_info, |
| | | match_param=match_param, |
| | | check_csrf=check_csrf, |
| | | http_cache=http_cache, |
| | | require_csrf=require_csrf, |
| | | callable=view, |
| | | mapper=mapper, |
| | | decorator=decorator, |
| | |
| | | decorator=decorator, |
| | | mapper=mapper, |
| | | http_cache=http_cache, |
| | | require_csrf=require_csrf, |
| | | extra_options=ovals, |
| | | ) |
| | | derived_view.__discriminator__ = lambda *arg: discriminator |
| | |
| | | d = pyramid.viewderivers |
| | | derivers = [ |
| | | ('secured_view', d.secured_view), |
| | | ('csrf_view', d.csrf_view), |
| | | ('owrapped_view', d.owrapped_view), |
| | | ('http_cached_view', d.http_cached_view), |
| | | ('decorated_view', d.decorated_view), |
| | |
| | | viewname=None, accept=None, order=MAX_ORDER, |
| | | phash=DEFAULT_PHASH, decorator=None, |
| | | mapper=None, http_cache=None, context=None, |
| | | extra_options=None): |
| | | require_csrf=None, extra_options=None): |
| | | view = self.maybe_dotted(view) |
| | | mapper = self.maybe_dotted(mapper) |
| | | if isinstance(renderer, string_types): |
| | |
| | | mapper=mapper, |
| | | decorator=decorator, |
| | | http_cache=http_cache, |
| | | require_csrf=require_csrf, |
| | | ) |
| | | if extra_options: |
| | | options.update(extra_options) |
| | |
| | | INewResponse, |
| | | IApplicationCreated, |
| | | IBeforeRender, |
| | | IBeforeTraversal, |
| | | ) |
| | | |
| | | class subscriber(object): |
| | |
| | | self.request = request |
| | | self.response = response |
| | | |
| | | @implementer(IBeforeTraversal) |
| | | class BeforeTraversal(object): |
| | | """ |
| | | An instance of this class is emitted as an :term:`event` after the |
| | | :app:`Pyramid` :term:`router` has attempted to find a :term:`route` object |
| | | but before any traversal or view code is executed. The instance has an |
| | | attribute, ``request``, which is the request object generated by |
| | | :app:`Pyramid`. |
| | | |
| | | Notably, the request object **may** have an attribute named |
| | | ``matched_route``, which is the matched route if found. If no route |
| | | matched, this attribute is not available. |
| | | |
| | | This class implements the :class:`pyramid.interfaces.IBeforeTraversal` |
| | | interface. |
| | | """ |
| | | |
| | | def __init__(self, request): |
| | | self.request = request |
| | | |
| | | @implementer(IContextFound) |
| | | class ContextFound(object): |
| | | """ An instance of this class is emitted as an :term:`event` after |
| | |
| | | AfterTraversal = ContextFound # b/c as of 1.0 |
| | | |
| | | @implementer(IApplicationCreated) |
| | | class ApplicationCreated(object): |
| | | class ApplicationCreated(object): |
| | | """ An instance of this class is emitted as an :term:`event` when |
| | | the :meth:`pyramid.config.Configurator.make_wsgi_app` is |
| | | called. The instance has an attribute, ``app``, which is an |
| | |
| | | def __init__(self, system, rendering_val=None): |
| | | dict.__init__(self, system) |
| | | self.rendering_val = rendering_val |
| | | |
| | | |
| | |
| | | |
| | | IAfterTraversal = IContextFound |
| | | |
| | | class IBeforeTraversal(Interface): |
| | | """ |
| | | An event type that is emitted after :app:`Pyramid` attempted to find a |
| | | route but before it calls any traversal or view code. See the documentation |
| | | attached to :class:`pyramid.events.Routefound` for more information. |
| | | """ |
| | | request = Attribute('The request object') |
| | | |
| | | class INewRequest(Interface): |
| | | """ An event type that is emitted whenever :app:`Pyramid` |
| | | begins to process a new request. See the documentation attached |
| | |
| | | ContextFound, |
| | | NewRequest, |
| | | NewResponse, |
| | | BeforeTraversal, |
| | | ) |
| | | |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | |
| | | |
| | | root_factory = route.factory or self.root_factory |
| | | |
| | | # Notify anyone listening that we are about to start traversal |
| | | # |
| | | # Notify before creating root_factory in case we want to do something |
| | | # special on a route we may have matched. See |
| | | # https://github.com/Pylons/pyramid/pull/1876 for ideas of what is |
| | | # possible. |
| | | has_listeners and notify(BeforeTraversal(request)) |
| | | |
| | | # Create the root factory |
| | | root = root_factory(request) |
| | | attrs['root'] = root |
| | | |
| | | # find a context |
| | | # We are about to traverse and find a context |
| | | traverser = adapters.queryAdapter(root, ITraverser) |
| | | if traverser is None: |
| | | traverser = ResourceTreeTraverser(root) |
| | |
| | | ) |
| | | |
| | | attrs.update(tdict) |
| | | |
| | | # Notify anyone listening that we have a context and traversal is |
| | | # complete |
| | | has_listeners and notify(ContextFound(request)) |
| | | |
| | | # find a view callable |
| | |
| | | Note that using this function requires that a :term:`session factory` is |
| | | configured. |
| | | |
| | | See :ref:`auto_csrf_checking` for information about how to secure your |
| | | application automatically against CSRF attacks. |
| | | |
| | | .. versionadded:: 1.4a2 |
| | | """ |
| | | supplied_token = request.params.get(token, request.headers.get(header, "")) |
| | |
| | | from pyramid.compat import string_types |
| | | |
| | | truthy = frozenset(('t', 'true', 'y', 'yes', 'on', '1')) |
| | | falsey = frozenset(('f', 'false', 'n', 'no', 'off', '0')) |
| | | |
| | | def asbool(s): |
| | | """ Return the boolean value ``True`` if the case-lowered value of string |
| | | input ``s`` is any of ``t``, ``true``, ``y``, ``on``, or ``1``, otherwise |
| | | return the boolean value ``False``. If ``s`` is the value ``None``, |
| | | return ``False``. If ``s`` is already one of the boolean values ``True`` |
| | | or ``False``, return it.""" |
| | | input ``s`` is a :term:`truthy string`. If ``s`` is already one of the |
| | | boolean values ``True`` or ``False``, return it.""" |
| | | if s is None: |
| | | return False |
| | | if isinstance(s, bool): |
| | |
| | | request.upath_info = text_('/') |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_check_csrf_predicates_match(self): |
| | | import warnings |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | with warnings.catch_warnings(record=True) as w: |
| | | warnings.filterwarnings('always') |
| | | config.add_view(view=view, check_csrf=True, renderer=null_renderer) |
| | | self.assertEqual(len(w), 1) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params = {'csrf_token': 'foo'} |
| | | request.headers = {} |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_with_custom_predicates_match(self): |
| | | import warnings |
| | | from pyramid.renderers import null_renderer |
| | |
| | | config.add_view(view=view1) |
| | | config.add_view(view=view2) |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | | |
| | | def test_add_view_with_csrf_param(self): |
| | | from pyramid.renderers import null_renderer |
| | | def view(request): |
| | | return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view, require_csrf='st', renderer=null_renderer) |
| | | view = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.method = 'POST' |
| | | request.params = {'st': 'foo'} |
| | | request.headers = {} |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | self.assertEqual(view(None, request), 'OK') |
| | | |
| | | def test_add_view_with_csrf_header(self): |
| | | from pyramid.renderers import null_renderer |
| | | def view(request): |
| | | return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view, require_csrf=True, renderer=null_renderer) |
| | | view = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.method = 'POST' |
| | | request.headers = {'X-CSRF-Token': 'foo'} |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | self.assertEqual(view(None, request), 'OK') |
| | | |
| | | def test_add_view_with_missing_csrf_header(self): |
| | | from pyramid.exceptions import BadCSRFToken |
| | | from pyramid.renderers import null_renderer |
| | | def view(request): return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view, require_csrf=True, renderer=null_renderer) |
| | | view = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.method = 'POST' |
| | | request.headers = {} |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | self.assertRaises(BadCSRFToken, lambda: view(None, request)) |
| | | |
| | | def test_add_view_with_permission(self): |
| | | from pyramid.renderers import null_renderer |
| | |
| | | return self.getval |
| | | def relate(self, a, b): |
| | | self.related.append((a, b)) |
| | | |
| | | class DummySession(dict): |
| | | def get_csrf_token(self): |
| | | return self['csrf_token'] |
| | |
| | | from zope.interface.verify import verifyClass |
| | | klass = self._getTargetClass() |
| | | verifyClass(INewRequest, klass) |
| | | |
| | | |
| | | def test_instance_conforms_to_INewRequest(self): |
| | | from pyramid.interfaces import INewRequest |
| | | from zope.interface.verify import verifyObject |
| | |
| | | from zope.interface.verify import verifyClass |
| | | klass = self._getTargetClass() |
| | | verifyClass(INewResponse, klass) |
| | | |
| | | |
| | | def test_instance_conforms_to_INewResponse(self): |
| | | from pyramid.interfaces import INewResponse |
| | | from zope.interface.verify import verifyObject |
| | |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IContextFound |
| | | verifyClass(IContextFound, self._getTargetClass()) |
| | | |
| | | |
| | | def test_instance_conforms_to_IContextFound(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IContextFound |
| | |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAfterTraversal |
| | | verifyClass(IAfterTraversal, self._getTargetClass()) |
| | | |
| | | |
| | | def test_instance_conforms_to_IAfterTraversal(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IAfterTraversal |
| | | verifyObject(IAfterTraversal, self._makeOne()) |
| | | |
| | | class BeforeTraversalEventTests(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.events import BeforeTraversal |
| | | return BeforeTraversal |
| | | |
| | | def _makeOne(self, request=None): |
| | | if request is None: |
| | | request = DummyRequest() |
| | | return self._getTargetClass()(request) |
| | | |
| | | def test_class_conforms_to_IBeforeTraversal(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IBeforeTraversal |
| | | verifyClass(IBeforeTraversal, self._getTargetClass()) |
| | | |
| | | def test_instance_conforms_to_IBeforeTraversal(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IBeforeTraversal |
| | | verifyObject(IBeforeTraversal, self._makeOne()) |
| | | |
| | | |
| | | class TestSubscriber(unittest.TestCase): |
| | | def setUp(self): |
| | |
| | | result = event.setdefault('a', 1) |
| | | self.assertEqual(result, 1) |
| | | self.assertEqual(event, {'a':1}) |
| | | |
| | | |
| | | def test_setdefault_success(self): |
| | | event = self._makeOne({}) |
| | | event['a'] = 1 |
| | |
| | | |
| | | class DummyRegistry(object): |
| | | pass |
| | | |
| | | |
| | | class DummyVenusian(object): |
| | | def __init__(self): |
| | | self.attached = [] |
| | |
| | | |
| | | class Dummy: |
| | | pass |
| | | |
| | | |
| | | class DummyRequest: |
| | | pass |
| | | |
| | |
| | | def test_call_eventsends(self): |
| | | from pyramid.interfaces import INewRequest |
| | | from pyramid.interfaces import INewResponse |
| | | from pyramid.interfaces import IBeforeTraversal |
| | | from pyramid.interfaces import IContextFound |
| | | from pyramid.interfaces import IViewClassifier |
| | | context = DummyContext() |
| | |
| | | environ = self._makeEnviron() |
| | | self._registerView(view, '', IViewClassifier, None, None) |
| | | request_events = self._registerEventListener(INewRequest) |
| | | beforetraversal_events = self._registerEventListener(IBeforeTraversal) |
| | | context_found_events = self._registerEventListener(IContextFound) |
| | | response_events = self._registerEventListener(INewResponse) |
| | | router = self._makeOne() |
| | |
| | | result = router(environ, start_response) |
| | | self.assertEqual(len(request_events), 1) |
| | | self.assertEqual(request_events[0].request.environ, environ) |
| | | self.assertEqual(len(beforetraversal_events), 1) |
| | | self.assertEqual(beforetraversal_events[0].request.environ, environ) |
| | | self.assertEqual(len(context_found_events), 1) |
| | | self.assertEqual(context_found_events[0].request.environ, environ) |
| | | self.assertEqual(context_found_events[0].request.context, context) |
| | |
| | | self.assertRaises(ConfigurationError, self.config._derive_view, |
| | | view, http_cache=(None,)) |
| | | |
| | | def test_csrf_view_requires_bool_or_str_in_require_csrf(self): |
| | | def view(request): pass |
| | | try: |
| | | self.config._derive_view(view, require_csrf=object()) |
| | | except ConfigurationError as ex: |
| | | self.assertEqual( |
| | | 'View option "require_csrf" must be a string or boolean value', |
| | | ex.args[0]) |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | def test_csrf_view_requires_bool_or_str_in_config_setting(self): |
| | | def view(request): pass |
| | | self.config.add_settings({'pyramid.require_default_csrf': object()}) |
| | | try: |
| | | self.config._derive_view(view) |
| | | except ConfigurationError as ex: |
| | | self.assertEqual( |
| | | 'Config setting "pyramid.require_csrf_default" must be a ' |
| | | 'string or boolean value', |
| | | ex.args[0]) |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | def test_csrf_view_requires_header(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.headers = {'X-CSRF-Token': 'foo'} |
| | | view = self.config._derive_view(inner_view, require_csrf=True) |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_requires_param(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['DUMMY'] = 'foo' |
| | | view = self.config._derive_view(inner_view, require_csrf='DUMMY') |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_ignores_GET(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'GET' |
| | | view = self.config._derive_view(inner_view, require_csrf=True) |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_fails_on_bad_POST_param(self): |
| | | from pyramid.exceptions import BadCSRFToken |
| | | def inner_view(request): pass |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['DUMMY'] = 'bar' |
| | | view = self.config._derive_view(inner_view, require_csrf='DUMMY') |
| | | self.assertRaises(BadCSRFToken, lambda: view(None, request)) |
| | | |
| | | def test_csrf_view_fails_on_bad_POST_header(self): |
| | | from pyramid.exceptions import BadCSRFToken |
| | | def inner_view(request): pass |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.headers = {'X-CSRF-Token': 'bar'} |
| | | view = self.config._derive_view(inner_view, require_csrf='DUMMY') |
| | | self.assertRaises(BadCSRFToken, lambda: view(None, request)) |
| | | |
| | | def test_csrf_view_uses_config_setting_truthy(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['csrf_token'] = 'foo' |
| | | self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) |
| | | view = self.config._derive_view(inner_view) |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_uses_config_setting_with_custom_token(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['DUMMY'] = 'foo' |
| | | self.config.add_settings({'pyramid.require_default_csrf': 'DUMMY'}) |
| | | view = self.config._derive_view(inner_view) |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_uses_config_setting_falsey(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['csrf_token'] = 'foo' |
| | | self.config.add_settings({'pyramid.require_default_csrf': 'no'}) |
| | | view = self.config._derive_view(inner_view) |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_uses_view_option_override(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['DUMMY'] = 'foo' |
| | | self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) |
| | | view = self.config._derive_view(inner_view, require_csrf='DUMMY') |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | def test_csrf_view_uses_config_setting_when_view_option_is_true(self): |
| | | response = DummyResponse() |
| | | def inner_view(request): |
| | | return response |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | request.session = DummySession({'csrf_token': 'foo'}) |
| | | request.params['DUMMY'] = 'foo' |
| | | self.config.add_settings({'pyramid.require_default_csrf': 'DUMMY'}) |
| | | view = self.config._derive_view(inner_view, require_csrf=True) |
| | | result = view(None, request) |
| | | self.assertTrue(result is response) |
| | | |
| | | |
| | | class TestDerivationOrder(unittest.TestCase): |
| | | def setUp(self): |
| | |
| | | dlist = [d for (d, _) in derivers_sorted] |
| | | self.assertEqual([ |
| | | 'secured_view', |
| | | 'csrf_view', |
| | | 'owrapped_view', |
| | | 'http_cached_view', |
| | | 'decorated_view', |
| | |
| | | dlist = [d for (d, _) in derivers_sorted] |
| | | self.assertEqual([ |
| | | 'secured_view', |
| | | 'csrf_view', |
| | | 'owrapped_view', |
| | | 'http_cached_view', |
| | | 'decorated_view', |
| | |
| | | dlist = [d for (d, _) in derivers_sorted] |
| | | self.assertEqual([ |
| | | 'secured_view', |
| | | 'csrf_view', |
| | | 'owrapped_view', |
| | | 'http_cached_view', |
| | | 'decorated_view', |
| | |
| | | dlist = [d for (d, _) in derivers_sorted] |
| | | self.assertEqual([ |
| | | 'secured_view', |
| | | 'csrf_view', |
| | | 'owrapped_view', |
| | | 'http_cached_view', |
| | | 'decorated_view', |
| | |
| | | self.environ = environ |
| | | self.params = {} |
| | | self.cookies = {} |
| | | self.headers = {} |
| | | self.response = DummyResponse() |
| | | |
| | | class DummyLogger: |
| | |
| | | def permits(self, context, principals, permission): |
| | | return self.permitted |
| | | |
| | | class DummySession(dict): |
| | | def get_csrf_token(self): |
| | | return self['csrf_token'] |
| | | |
| | | def parse_httpdate(s): |
| | | import datetime |
| | | # cannot use %Z, must use literal GMT; Jython honors timezone |
| | |
| | | ``request_type``, ``route_name``, ``request_method``, ``request_param``, |
| | | ``containment``, ``xhr``, ``accept``, ``header``, ``path_info``, |
| | | ``custom_predicates``, ``decorator``, ``mapper``, ``http_cache``, |
| | | ``match_param``, ``check_csrf``, ``physical_path``, and ``predicates``. |
| | | ``require_csrf``, ``match_param``, ``check_csrf``, ``physical_path``, and |
| | | ``view_options``. |
| | | |
| | | The meanings of these arguments are the same as the arguments passed to |
| | | :meth:`pyramid.config.Configurator.add_view`. If any argument is left |
| | |
| | | ) |
| | | |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | from pyramid.session import check_csrf_token |
| | | from pyramid.response import Response |
| | | |
| | | from pyramid.interfaces import ( |
| | |
| | | ) |
| | | |
| | | from pyramid.compat import ( |
| | | string_types, |
| | | is_bound_method, |
| | | is_unbound_method, |
| | | ) |
| | |
| | | PredicateMismatch, |
| | | ) |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.settings import ( |
| | | falsey, |
| | | truthy, |
| | | ) |
| | | from pyramid.util import object_description |
| | | from pyramid.view import render_view_to_response |
| | | from pyramid import renderers |
| | |
| | | |
| | | decorated_view.options = ('decorator',) |
| | | |
| | | def _parse_csrf_setting(val, error_source): |
| | | if val: |
| | | if isinstance(val, string_types): |
| | | if val.lower() in truthy: |
| | | val = True |
| | | elif val.lower() in falsey: |
| | | val = False |
| | | elif not isinstance(val, bool): |
| | | raise ConfigurationError( |
| | | '{0} must be a string or boolean value' |
| | | .format(error_source)) |
| | | return val |
| | | |
| | | def csrf_view(view, info): |
| | | default_val = _parse_csrf_setting( |
| | | info.settings.get('pyramid.require_default_csrf'), |
| | | 'Config setting "pyramid.require_csrf_default"') |
| | | val = _parse_csrf_setting( |
| | | info.options.get('require_csrf'), |
| | | 'View option "require_csrf"') |
| | | if (val is True and default_val) or val is None: |
| | | val = default_val |
| | | if val is True: |
| | | val = 'csrf_token' |
| | | wrapped_view = view |
| | | if val: |
| | | def csrf_view(context, request): |
| | | if request.method == 'POST': |
| | | check_csrf_token(request, val, raises=True) |
| | | return view(context, request) |
| | | wrapped_view = csrf_view |
| | | return wrapped_view |
| | | |
| | | csrf_view.options = ('require_csrf',) |
| | | |
| | | VIEW = 'VIEW' |
| | | INGRESS = 'INGRESS' |