Nexcessnet_Turpentine - Version 0.5.4

Version Notes

Supports Magento v1.6 and later

Download this release

Release Info

Developer Chris Wells
Extension Nexcessnet_Turpentine
Version 0.5.4
Comparing to
See all releases


Code changes from version 0.5.3 to 0.5.4

Files changed (24) hide show
  1. app/code/community/Nexcessnet/Turpentine/Block/Core/Messages.php +20 -13
  2. app/code/community/Nexcessnet/Turpentine/Block/Management.php +10 -0
  3. app/code/community/Nexcessnet/Turpentine/Block/Notices.php +23 -0
  4. app/code/community/Nexcessnet/Turpentine/Helper/Cron.php +9 -2
  5. app/code/community/Nexcessnet/Turpentine/Helper/Data.php +16 -0
  6. app/code/community/Nexcessnet/Turpentine/Helper/Esi.php +3 -1
  7. app/code/community/Nexcessnet/Turpentine/Helper/Varnish.php +21 -0
  8. app/code/community/Nexcessnet/Turpentine/Model/Dummy/Request.php +800 -0
  9. app/code/community/Nexcessnet/Turpentine/Model/Observer/Ban.php +8 -4
  10. app/code/community/Nexcessnet/Turpentine/Model/Observer/Esi.php +0 -1
  11. app/code/community/Nexcessnet/Turpentine/Model/PageCache/Container/Notices.php +46 -0
  12. app/code/community/Nexcessnet/Turpentine/Model/Varnish/Admin/Socket.php +18 -0
  13. app/code/community/Nexcessnet/Turpentine/Model/Varnish/Configurator/Abstract.php +14 -4
  14. app/code/community/Nexcessnet/Turpentine/controllers/EsiController.php +25 -11
  15. app/code/community/Nexcessnet/Turpentine/controllers/Varnish/ManagementController.php +39 -0
  16. app/code/community/Nexcessnet/Turpentine/etc/cache.xml +29 -0
  17. app/code/community/Nexcessnet/Turpentine/etc/config.xml +2 -1
  18. app/code/community/Nexcessnet/Turpentine/etc/system.xml +9 -0
  19. app/code/community/Nexcessnet/Turpentine/misc/version-2.vcl +32 -24
  20. app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl +23 -18
  21. app/design/adminhtml/default/default/template/turpentine/varnish_management.phtml +55 -20
  22. app/design/frontend/base/default/layout/turpentine_esi.xml +7 -0
  23. app/design/frontend/base/default/template/turpentine/notices.phtml +36 -0
  24. package.xml +1 -1
app/code/community/Nexcessnet/Turpentine/Block/Core/Messages.php CHANGED
@@ -55,6 +55,7 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
55
  'customer',
56
  'review',
57
  'wishlist',
 
58
  );
59
 
60
  /**
@@ -82,8 +83,11 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
82
  * @return Mage_Core_Block_Messages
83
  */
84
  public function setMessages( Mage_Core_Model_Message_Collection $messages ) {
85
- parent::setMessages( $messages );
86
- $this->_saveMessages( $messages->getItems() );
 
 
 
87
  return $this;
88
  }
89
 
@@ -94,8 +98,11 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
94
  * @return Mage_Core_Block_Messages
95
  */
96
  public function addMessages( Mage_Core_Model_Message_Collection $messages ) {
97
- parent::addMessages( $messages );
98
- $this->_saveMessages( $messages->getItems() );
 
 
 
99
  return $this;
100
  }
101
 
@@ -106,8 +113,11 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
106
  * @return Mage_Core_Block_Messages
107
  */
108
  public function addMessage( Mage_Core_Model_Message_Abstract $message ) {
109
- parent::addMessage( $message );
110
- $this->_saveMessages( array( $message ) );
 
 
 
111
  return $this;
112
  }
113
 
@@ -266,7 +276,7 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
266
  protected function _loadSavedMessages() {
267
  $session = Mage::getSingleton( 'turpentine/session' );
268
  foreach( $session->loadMessages( $this->getNameInLayout() ) as $msg ) {
269
- $this->getMessageCollection()->add( $msg );
270
  }
271
  $this->_clearMessages();
272
  }
@@ -280,7 +290,7 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
280
  protected function _loadMessagesFromStorage( $type ) {
281
  foreach( Mage::getSingleton( $type )
282
  ->getMessages( true )->getItems() as $msg ) {
283
- $this->addMessage( $msg );
284
  }
285
  }
286
 
@@ -343,10 +353,7 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
343
  * @return boolean
344
  */
345
  protected function _isEsiRequest() {
346
- $liveReq = Mage::app()->getRequest();
347
- $dummyReq = Mage::helper( 'turpentine/esi' )->getDummyRequest();
348
- return $liveReq->getModuleName() === $dummyReq->getModuleName() &&
349
- $liveReq->getControllerName() === $dummyReq->getControllerName() &&
350
- $liveReq->getActionName() === $dummyReq->getActionName();
351
  }
352
  }
55
  'customer',
56
  'review',
57
  'wishlist',
58
+ 'core',
59
  );
60
 
61
  /**
83
  * @return Mage_Core_Block_Messages
84
  */
85
  public function setMessages( Mage_Core_Model_Message_Collection $messages ) {
86
+ if( $this->_fixMessages() ) {
87
+ $this->_saveMessages( $messages->getItems() );
88
+ } else {
89
+ parent::setMessages( $messages );
90
+ }
91
  return $this;
92
  }
93
 
98
  * @return Mage_Core_Block_Messages
99
  */
100
  public function addMessages( Mage_Core_Model_Message_Collection $messages ) {
101
+ if( $this->_fixMessages() ) {
102
+ $this->_saveMessages( $messages->getItems() );
103
+ } else {
104
+ parent::addMessages( $messages );
105
+ }
106
  return $this;
107
  }
108
 
113
  * @return Mage_Core_Block_Messages
114
  */
115
  public function addMessage( Mage_Core_Model_Message_Abstract $message ) {
116
+ if( $this->_fixMessages() ) {
117
+ $this->_saveMessages( $message->getItems() );
118
+ } else {
119
+ parent::addMessage( $message );
120
+ }
121
  return $this;
122
  }
123
 
276
  protected function _loadSavedMessages() {
277
  $session = Mage::getSingleton( 'turpentine/session' );
278
  foreach( $session->loadMessages( $this->getNameInLayout() ) as $msg ) {
279
+ parent::addMessage( $msg );
280
  }
281
  $this->_clearMessages();
282
  }
290
  protected function _loadMessagesFromStorage( $type ) {
291
  foreach( Mage::getSingleton( $type )
292
  ->getMessages( true )->getItems() as $msg ) {
293
+ parent::addMessage( $msg );
294
  }
295
  }
296
 
353
  * @return boolean
354
  */
355
  protected function _isEsiRequest() {
356
+ return is_subclass_of( Mage::app()->getRequest(),
357
+ 'Nexcessnet_Turpentine_Model_Dummy_Request' );
 
 
 
358
  }
359
  }
app/code/community/Nexcessnet/Turpentine/Block/Management.php CHANGED
@@ -81,4 +81,14 @@ class Nexcessnet_Turpentine_Block_Management
81
  public function getGetConfigUrl() {
82
  return $this->getUrl('*/varnish_management/getConfig');
83
  }
 
 
 
 
 
 
 
 
 
 
84
  }
81
  public function getGetConfigUrl() {
82
  return $this->getUrl('*/varnish_management/getConfig');
83
  }
84
+
85
+ /**
86
+ * Get the switchNavigation URL
87
+ *
88
+ * @param string $type
89
+ * @return string
90
+ */
91
+ public function getSwitchNavigationUrl( $type ) {
92
+ return $this->getUrl('*/varnish_management/switchNavigation', array('type' => $type));
93
+ }
94
  }
app/code/community/Nexcessnet/Turpentine/Block/Notices.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Nexcess.net Turpentine Extension for Magento
5
+ * Copyright (C) 2012 Nexcess.net L.L.C.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+ class Nexcessnet_Turpentine_Block_Notices
23
+ extends Mage_Adminhtml_Block_Template {}
app/code/community/Nexcessnet/Turpentine/Helper/Cron.php CHANGED
@@ -153,6 +153,10 @@ class Nexcessnet_Turpentine_Helper_Cron extends Mage_Core_Helper_Abstract {
153
  public function getAllUrls() {
154
  $urls = array();
155
  $origStore = Mage::app()->getStore();
 
 
 
 
156
  foreach( Mage::app()->getStores() as $storeId => $store ) {
157
  Mage::app()->setCurrentStore( $store );
158
  $baseUrl = $store->getBaseUrl( Mage_Core_Model_Store::URL_TYPE_LINK );
@@ -161,11 +165,14 @@ class Nexcessnet_Turpentine_Helper_Cron extends Mage_Core_Helper_Abstract {
161
  ->getCollection( $storeId ) as $cat ) {
162
  $urls[] = $cat->getUrl();
163
  foreach( $cat->getProductCollection( $storeId )
164
- ->addUrlRewrite( $cat->getId() ) as $prod ) {
 
 
165
  $urls[] = $prod->getProductUrl();
166
  }
167
  }
168
- foreach( Mage::getResourceModel( 'sitemap/cms_page' )->getCollection( $storeId ) as $item ) {
 
169
  $urls[] = $baseUrl . $item->getUrl();
170
  }
171
  }
153
  public function getAllUrls() {
154
  $urls = array();
155
  $origStore = Mage::app()->getStore();
156
+ $visibility = array(
157
+ Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
158
+ Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG,
159
+ );
160
  foreach( Mage::app()->getStores() as $storeId => $store ) {
161
  Mage::app()->setCurrentStore( $store );
162
  $baseUrl = $store->getBaseUrl( Mage_Core_Model_Store::URL_TYPE_LINK );
165
  ->getCollection( $storeId ) as $cat ) {
166
  $urls[] = $cat->getUrl();
167
  foreach( $cat->getProductCollection( $storeId )
168
+ ->addUrlRewrite( $cat->getId() )
169
+ ->addAttributeToFilter( 'visibility', $visibility )
170
+ as $prod ) {
171
  $urls[] = $prod->getProductUrl();
172
  }
173
  }
174
+ foreach( Mage::getResourceModel( 'sitemap/cms_page' )
175
+ ->getCollection( $storeId ) as $item ) {
176
  $urls[] = $baseUrl . $item->getUrl();
177
  }
178
  }
app/code/community/Nexcessnet/Turpentine/Helper/Data.php CHANGED
@@ -40,6 +40,13 @@ class Nexcessnet_Turpentine_Helper_Data extends Mage_Core_Helper_Abstract {
40
  */
41
  const HASH_ALGORITHM = 'sha256';
42
 
 
 
 
 
 
 
 
43
  /**
44
  * encryption singleton thing
45
  *
@@ -263,6 +270,15 @@ class Nexcessnet_Turpentine_Helper_Data extends Mage_Core_Helper_Abstract {
263
  'turpentine_varnish/general/auto_apply_on_save' );
264
  }
265
 
 
 
 
 
 
 
 
 
 
266
  /**
267
  * The actual recursive implementation of getChildBlockNames
268
  *
40
  */
41
  const HASH_ALGORITHM = 'sha256';
42
 
43
+ /**
44
+ * Cookie name for the Varnish bypass
45
+ *
46
+ * @var string
47
+ */
48
+ const BYPASS_COOKIE_NAME = 'varnish_bypass';
49
+
50
  /**
51
  * encryption singleton thing
52
  *
270
  'turpentine_varnish/general/auto_apply_on_save' );
271
  }
272
 
273
+ /**
274
+ * Get the cookie name for the Varnish bypass
275
+ *
276
+ * @return string
277
+ */
278
+ public function getBypassCookieName() {
279
+ return self::BYPASS_COOKIE_NAME;
280
+ }
281
+
282
  /**
283
  * The actual recursive implementation of getChildBlockNames
284
  *
app/code/community/Nexcessnet/Turpentine/Helper/Esi.php CHANGED
@@ -172,7 +172,9 @@ class Nexcessnet_Turpentine_Helper_Esi extends Mage_Core_Helper_Abstract {
172
  if( $url === null ) {
173
  $url = $this->getDummyUrl();
174
  }
175
- return new Mage_Core_Controller_Request_Http( $url );
 
 
176
  }
177
 
178
  /**
172
  if( $url === null ) {
173
  $url = $this->getDummyUrl();
174
  }
175
+ $request = new Nexcessnet_Turpentine_Model_Dummy_Request( $url );
176
+ $request->fakeRouterDispatch();
177
+ return $request;
178
  }
179
 
180
  /**
app/code/community/Nexcessnet/Turpentine/Helper/Varnish.php CHANGED
@@ -155,4 +155,25 @@ class Nexcessnet_Turpentine_Helper_Varnish extends Mage_Core_Helper_Abstract {
155
  return Mage::helper( 'turpentine/data' )->useProductListToolbarFix() &&
156
  Mage::app()->getStore()->getCode() !== 'admin';
157
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  }
155
  return Mage::helper( 'turpentine/data' )->useProductListToolbarFix() &&
156
  Mage::app()->getStore()->getCode() !== 'admin';
157
  }
158
+
159
+ /**
160
+ * Check if the Varnish bypass is enabled
161
+ *
162
+ * @return boolean
163
+ */
164
+ public function isBypassEnabled() {
165
+ $cookieName = Mage::helper( 'turpentine' )->getBypassCookieName();
166
+ $cookieValue = (bool)Mage::getModel( 'core/cookie' )->get($cookieName);
167
+
168
+ return $cookieValue;
169
+ }
170
+
171
+ /**
172
+ * Check if the notification about the Varnish bypass must be displayed
173
+ *
174
+ * @return boolean
175
+ */
176
+ public function shouldDisplayNotice() {
177
+ return $this->getVarnishEnabled() && $this->isBypassEnabled();
178
+ }
179
  }
app/code/community/Nexcessnet/Turpentine/Model/Dummy/Request.php ADDED
@@ -0,0 +1,800 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Nexcess.net Turpentine Extension for Magento
5
+ * Copyright (C) 2012 Nexcess.net L.L.C.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+ class Nexcessnet_Turpentine_Model_Dummy_Request extends
23
+ Mage_Core_Controller_Request_Http {
24
+
25
+ public $GET = null;
26
+ public $POST = null;
27
+ public $SERVER = null;
28
+ public $ENV = null;
29
+
30
+ /**
31
+ * Constructor
32
+ *
33
+ * If a $uri is passed, the object will attempt to populate itself using
34
+ * that information.
35
+ *
36
+ * @param string|Zend_Uri $uri
37
+ * @return void
38
+ * @throws Zend_Controller_Request_Exception when invalid URI passed
39
+ */
40
+ public function __construct( $uri=null ) {
41
+ $this->_initFakeSuperGlobals();
42
+ $this->_fixupFakeSuperGlobals( $uri );
43
+ parent::__construct( $uri );
44
+ }
45
+
46
+ /**
47
+ * Access values contained in the superglobals as public members
48
+ * Order of precedence: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV
49
+ *
50
+ * @see http://msdn.microsoft.com/en-us/library/system.web.httprequest.item.aspx
51
+ * @param string $key
52
+ * @return mixed
53
+ */
54
+ public function __get( $key ) {
55
+ switch( true ) {
56
+ case isset( $this->_params[$key] ):
57
+ return $this->_params[$key];
58
+ case isset( $this->GET[$key] ):
59
+ return $this->GET[$key];
60
+ case isset( $this->POST[$key] ):
61
+ return $this->POST[$key];
62
+ case isset( $_COOKIE[$key] ):
63
+ return $_COOKIE[$key];
64
+ case ($key == 'REQUEST_URI'):
65
+ return $this->getRequestUri();
66
+ case ($key == 'PATH_INFO'):
67
+ return $this->getPathInfo();
68
+ case isset( $this->SERVER[$key] ):
69
+ return $this->SERVER[$key];
70
+ case isset( $this->ENV[$key] ):
71
+ return $this->ENV[$key];
72
+ default:
73
+ return null;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Check to see if a property is set
79
+ *
80
+ * @param string $key
81
+ * @return boolean
82
+ */
83
+ public function __isset( $key ) {
84
+ switch (true) {
85
+ case isset( $this->_params[$key] ):
86
+ return true;
87
+ case isset( $this->GET[$key] ):
88
+ return true;
89
+ case isset( $this->POST[$key] ):
90
+ return true;
91
+ case isset( $_COOKIE[$key] ):
92
+ return true;
93
+ case isset( $this->SERVER[$key] ):
94
+ return true;
95
+ case isset( $this->ENV[$key] ):
96
+ return true;
97
+ default:
98
+ return false;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Set GET values
104
+ *
105
+ * @param string|array $spec
106
+ * @param null|mixed $value
107
+ * @return Zend_Controller_Request_Http
108
+ */
109
+ public function setQuery( $spec, $value=null ) {
110
+ if ((null === $value) && !is_array($spec)) {
111
+ #require_once 'Zend/Controller/Exception.php';
112
+ throw new Zend_Controller_Exception('Invalid value passed to setQuery(); must be either array of values or key/value pair');
113
+ }
114
+ if ((null === $value) && is_array($spec)) {
115
+ foreach ($spec as $key => $value) {
116
+ $this->setQuery($key, $value);
117
+ }
118
+ return $this;
119
+ }
120
+ $this->GET[(string) $spec] = $value;
121
+ return $this;
122
+ }
123
+
124
+ /**
125
+ * Retrieve a member of the $_GET superglobal
126
+ *
127
+ * If no $key is passed, returns the entire $_GET array.
128
+ *
129
+ * @todo How to retrieve from nested arrays
130
+ * @param string $key
131
+ * @param mixed $default Default value to use if key not found
132
+ * @return mixed Returns null if key does not exist
133
+ */
134
+ public function getQuery( $key=null, $default=null ) {
135
+ if( null === $key ) {
136
+ return $this->GET;
137
+ }
138
+ return ( isset( $this->GET[$key] ) ) ? $this->GET[$key] : $default;
139
+ }
140
+
141
+ /**
142
+ * Retrieve a member of the $_POST superglobal
143
+ *
144
+ * If no $key is passed, returns the entire $_POST array.
145
+ *
146
+ * @todo How to retrieve from nested arrays
147
+ * @param string $key
148
+ * @param mixed $default Default value to use if key not found
149
+ * @return mixed Returns null if key does not exist
150
+ */
151
+ public function getPost( $key=null, $default=null ) {
152
+ if (null === $key) {
153
+ return $this->POST;
154
+ }
155
+
156
+ return (isset($this->POST[$key])) ? $this->POST[$key] : $default;
157
+ }
158
+
159
+ /**
160
+ * Retrieve a member of the $_SERVER superglobal
161
+ *
162
+ * If no $key is passed, returns the entire $_SERVER array.
163
+ *
164
+ * @param string $key
165
+ * @param mixed $default Default value to use if key not found
166
+ * @return mixed Returns null if key does not exist
167
+ */
168
+ public function getServer( $key=null, $default=null ) {
169
+ if (null === $key) {
170
+ return $this->SERVER;
171
+ }
172
+
173
+ return (isset($this->SERVER[$key])) ? $this->SERVER[$key] : $default;
174
+ }
175
+
176
+ /**
177
+ * Retrieve a member of the $_ENV superglobal
178
+ *
179
+ * If no $key is passed, returns the entire $_ENV array.
180
+ *
181
+ * @param string $key
182
+ * @param mixed $default Default value to use if key not found
183
+ * @return mixed Returns null if key does not exist
184
+ */
185
+ public function getEnv( $key=null, $default=null ) {
186
+ if (null === $key) {
187
+ return $this->ENV;
188
+ }
189
+
190
+ return (isset($this->ENV[$key])) ? $this->ENV[$key] : $default;
191
+ }
192
+
193
+ /**
194
+ * Return the value of the given HTTP header. Pass the header name as the
195
+ * plain, HTTP-specified header name. Ex.: Ask for 'Accept' to get the
196
+ * Accept header, 'Accept-Encoding' to get the Accept-Encoding header.
197
+ *
198
+ * @param string $header HTTP header name
199
+ * @return string|false HTTP header value, or false if not found
200
+ * @throws Zend_Controller_Request_Exception
201
+ */
202
+ public function getHeader( $header ) {
203
+ if (empty($header)) {
204
+ #require_once 'Zend/Controller/Request/Exception.php';
205
+ throw new Zend_Controller_Request_Exception('An HTTP header name is required');
206
+ }
207
+
208
+ // Try to get it from the $_SERVER array first
209
+ $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
210
+ if (isset($this->SERVER[$temp])) {
211
+ return $this->SERVER[$temp];
212
+ }
213
+
214
+ // This seems to be the only way to get the Authorization header on
215
+ // Apache
216
+ if (function_exists('apache_request_headers')) {
217
+ $headers = apache_request_headers();
218
+ if (isset($headers[$header])) {
219
+ return $headers[$header];
220
+ }
221
+ $header = strtolower($header);
222
+ foreach ($headers as $key => $value) {
223
+ if (strtolower($key) == $header) {
224
+ return $value;
225
+ }
226
+ }
227
+ }
228
+
229
+ return false;
230
+ }
231
+
232
+ /**
233
+ * Set the REQUEST_URI on which the instance operates
234
+ *
235
+ * If no request URI is passed, uses the value in $_SERVER['REQUEST_URI'],
236
+ * $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING'].
237
+ *
238
+ * @param string $requestUri
239
+ * @return Zend_Controller_Request_Http
240
+ */
241
+ public function setRequestUri( $requestUri=null ) {
242
+ if ($requestUri === null) {
243
+ if (isset($this->SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
244
+ $requestUri = $this->SERVER['HTTP_X_REWRITE_URL'];
245
+ } elseif (
246
+ // IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
247
+ isset($this->SERVER['IIS_WasUrlRewritten'])
248
+ && $this->SERVER['IIS_WasUrlRewritten'] == '1'
249
+ && isset($this->SERVER['UNENCODED_URL'])
250
+ && $this->SERVER['UNENCODED_URL'] != ''
251
+ ) {
252
+ $requestUri = $this->SERVER['UNENCODED_URL'];
253
+ } elseif (isset($this->SERVER['REQUEST_URI'])) {
254
+ $requestUri = $this->SERVER['REQUEST_URI'];
255
+ // Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
256
+ $schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost();
257
+ if (strpos($requestUri, $schemeAndHttpHost) === 0) {
258
+ $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
259
+ }
260
+ } elseif (isset($this->SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
261
+ $requestUri = $this->SERVER['ORIG_PATH_INFO'];
262
+ if (!empty($this->SERVER['QUERY_STRING'])) {
263
+ $requestUri .= '?' . $this->SERVER['QUERY_STRING'];
264
+ }
265
+ } else {
266
+ return $this;
267
+ }
268
+ } elseif (!is_string($requestUri)) {
269
+ return $this;
270
+ } else {
271
+ // Set GET items, if available
272
+ if (false !== ($pos = strpos($requestUri, '?'))) {
273
+ // Get key => value pairs and set $_GET
274
+ $query = substr($requestUri, $pos + 1);
275
+ parse_str($query, $vars);
276
+ $this->setQuery($vars);
277
+ }
278
+ }
279
+
280
+ $this->_requestUri = $requestUri;
281
+ return $this;
282
+ }
283
+
284
+ /**
285
+ * Set the base URL of the request; i.e., the segment leading to the script name
286
+ *
287
+ * E.g.:
288
+ * - /admin
289
+ * - /myapp
290
+ * - /subdir/index.php
291
+ *
292
+ * Do not use the full URI when providing the base. The following are
293
+ * examples of what not to use:
294
+ * - http://example.com/admin (should be just /admin)
295
+ * - http://example.com/subdir/index.php (should be just /subdir/index.php)
296
+ *
297
+ * If no $baseUrl is provided, attempts to determine the base URL from the
298
+ * environment, using SCRIPT_FILENAME, SCRIPT_NAME, PHP_SELF, and
299
+ * ORIG_SCRIPT_NAME in its determination.
300
+ *
301
+ * @param mixed $baseUrl
302
+ * @return Zend_Controller_Request_Http
303
+ */
304
+ public function setBaseUrl( $baseUrl=null ) {
305
+ if ((null !== $baseUrl) && !is_string($baseUrl)) {
306
+ return $this;
307
+ }
308
+
309
+ if ($baseUrl === null) {
310
+ $filename = (isset($this->SERVER['SCRIPT_FILENAME'])) ? basename($this->SERVER['SCRIPT_FILENAME']) : '';
311
+
312
+ if (isset($this->SERVER['SCRIPT_NAME']) && basename($this->SERVER['SCRIPT_NAME']) === $filename) {
313
+ $baseUrl = $this->SERVER['SCRIPT_NAME'];
314
+ } elseif (isset($this->SERVER['PHP_SELF']) && basename($this->SERVER['PHP_SELF']) === $filename) {
315
+ $baseUrl = $this->SERVER['PHP_SELF'];
316
+ } elseif (isset($this->SERVER['ORIG_SCRIPT_NAME']) && basename($this->SERVER['ORIG_SCRIPT_NAME']) === $filename) {
317
+ $baseUrl = $this->SERVER['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility
318
+ } else {
319
+ // Backtrack up the script_filename to find the portion matching
320
+ // php_self
321
+ $path = isset($this->SERVER['PHP_SELF']) ? $this->SERVER['PHP_SELF'] : '';
322
+ $file = isset($this->SERVER['SCRIPT_FILENAME']) ? $this->SERVER['SCRIPT_FILENAME'] : '';
323
+ $segs = explode('/', trim($file, '/'));
324
+ $segs = array_reverse($segs);
325
+ $index = 0;
326
+ $last = count($segs);
327
+ $baseUrl = '';
328
+ do {
329
+ $seg = $segs[$index];
330
+ $baseUrl = '/' . $seg . $baseUrl;
331
+ ++$index;
332
+ } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));
333
+ }
334
+
335
+ // Does the baseUrl have anything in common with the request_uri?
336
+ $requestUri = $this->getRequestUri();
337
+
338
+ if (0 === strpos($requestUri, $baseUrl)) {
339
+ // full $baseUrl matches
340
+ $this->_baseUrl = $baseUrl;
341
+ return $this;
342
+ }
343
+
344
+ if (0 === strpos($requestUri, dirname($baseUrl))) {
345
+ // directory portion of $baseUrl matches
346
+ $this->_baseUrl = rtrim(dirname($baseUrl), '/');
347
+ return $this;
348
+ }
349
+
350
+ $truncatedRequestUri = $requestUri;
351
+ if (($pos = strpos($requestUri, '?')) !== false) {
352
+ $truncatedRequestUri = substr($requestUri, 0, $pos);
353
+ }
354
+
355
+ $basename = basename($baseUrl);
356
+ if (empty($basename) || !strpos($truncatedRequestUri, $basename)) {
357
+ // no match whatsoever; set it blank
358
+ $this->_baseUrl = '';
359
+ return $this;
360
+ }
361
+
362
+ // If using mod_rewrite or ISAPI_Rewrite strip the script filename
363
+ // out of baseUrl. $pos !== 0 makes sure it is not matching a value
364
+ // from PATH_INFO or QUERY_STRING
365
+ if ((strlen($requestUri) >= strlen($baseUrl))
366
+ && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0)))
367
+ {
368
+ $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
369
+ }
370
+ }
371
+
372
+ $this->_baseUrl = rtrim($baseUrl, '/');
373
+ return $this;
374
+ }
375
+
376
+ /**
377
+ * Set the base path for the URL
378
+ *
379
+ * @param string|null $basePath
380
+ * @return Zend_Controller_Request_Http
381
+ */
382
+ public function setBasePath( $basePath=null ) {
383
+ if ($basePath === null) {
384
+ $filename = (isset($this->SERVER['SCRIPT_FILENAME']))
385
+ ? basename($this->SERVER['SCRIPT_FILENAME'])
386
+ : '';
387
+
388
+ $baseUrl = $this->getBaseUrl();
389
+ if (empty($baseUrl)) {
390
+ $this->_basePath = '';
391
+ return $this;
392
+ }
393
+
394
+ if (basename($baseUrl) === $filename) {
395
+ $basePath = dirname($baseUrl);
396
+ } else {
397
+ $basePath = $baseUrl;
398
+ }
399
+ }
400
+
401
+ if (substr(PHP_OS, 0, 3) === 'WIN') {
402
+ $basePath = str_replace('\\', '/', $basePath);
403
+ }
404
+
405
+ $this->_basePath = rtrim($basePath, '/');
406
+ return $this;
407
+ }
408
+
409
+ /**
410
+ * Retrieve a parameter
411
+ *
412
+ * Retrieves a parameter from the instance. Priority is in the order of
413
+ * userland parameters (see {@link setParam()}), $_GET, $_POST. If a
414
+ * parameter matching the $key is not found, null is returned.
415
+ *
416
+ * If the $key is an alias, the actual key aliased will be used.
417
+ *
418
+ * @param mixed $key
419
+ * @param mixed $default Default value to use if key not found
420
+ * @return mixed
421
+ */
422
+ public function getParam( $key, $default=null ) {
423
+ $keyName = (null !== ($alias = $this->getAlias($key))) ? $alias : $key;
424
+
425
+ $paramSources = $this->getParamSources();
426
+ if (isset($this->_params[$keyName])) {
427
+ return $this->_params[$keyName];
428
+ } elseif (in_array('_GET', $paramSources) && (isset($this->GET[$keyName]))) {
429
+ return $this->GET[$keyName];
430
+ } elseif (in_array('_POST', $paramSources) && (isset($this->POST[$keyName]))) {
431
+ return $this->POST[$keyName];
432
+ }
433
+
434
+ return $default;
435
+ }
436
+
437
+ /**
438
+ * Retrieve an array of parameters
439
+ *
440
+ * Retrieves a merged array of parameters, with precedence of userland
441
+ * params (see {@link setParam()}), $_GET, $_POST (i.e., values in the
442
+ * userland params will take precedence over all others).
443
+ *
444
+ * @return array
445
+ */
446
+ public function getParams() {
447
+ $return = $this->_params;
448
+ $paramSources = $this->getParamSources();
449
+ if (in_array('_GET', $paramSources)
450
+ && isset($this->GET)
451
+ && is_array($this->GET)
452
+ ) {
453
+ $return += $this->GET;
454
+ }
455
+ if (in_array('_POST', $paramSources)
456
+ && isset($this->POST)
457
+ && is_array($this->POST)
458
+ ) {
459
+ $return += $this->POST;
460
+ }
461
+ return $return;
462
+ }
463
+
464
+ /**
465
+ * Retrieve HTTP HOST
466
+ *
467
+ * @param bool $trimPort
468
+ * @return string
469
+ */
470
+ public function getHttpHost( $trimPort=true ) {
471
+ if (!isset($this->SERVER['HTTP_HOST'])) {
472
+ return false;
473
+ }
474
+ if ($trimPort) {
475
+ $host = explode(':', $this->SERVER['HTTP_HOST']);
476
+ return $host[0];
477
+ }
478
+ return $this->SERVER['HTTP_HOST'];
479
+ }
480
+
481
+ /**
482
+ * Set a member of the $_POST superglobal
483
+ *
484
+ * @param string|array $key
485
+ * @param mixed $value
486
+ *
487
+ * @return Mage_Core_Controller_Request_Http
488
+ */
489
+ public function setPost( $key, $value=null ) {
490
+ if (is_array($key)) {
491
+ $this->POST = $key;
492
+ }
493
+ else {
494
+ $this->POST[$key] = $value;
495
+ }
496
+ return $this;
497
+ }
498
+
499
+ /**
500
+ * Init the fake superglobal vars
501
+ *
502
+ * @return null
503
+ */
504
+ protected function _initFakeSuperGlobals() {
505
+ $this->GET = array();
506
+ $this->POST = $_POST;
507
+ $this->SERVER = $_SERVER;
508
+ $this->ENV = $_ENV;
509
+ }
510
+
511
+ /**
512
+ * Fix up the fake superglobal vars
513
+ *
514
+ * @param string $uri
515
+ * @return null
516
+ */
517
+ protected function _fixupFakeSuperGlobals( $uri ) {
518
+ $parsedUrl = parse_url( $uri );
519
+
520
+ $this->SERVER['REQUEST_URI'] = $parsedUrl['path'];
521
+ if( isset( $parsedUrl['query'] ) && $parsedUrl['query'] ) {
522
+ $this->SERVER['QUERY_STRING'] = $parsedUrl['query'];
523
+ $this->SERVER['REQUEST_URI'] .= '?' . $this->SERVER['QUERY_STRING'];
524
+ } else {
525
+ $this->SERVER['QUERY_STRING'] = null;
526
+ }
527
+ parse_str( $this->SERVER['QUERY_STRING'], $this->GET );
528
+ if( isset( $this->SERVER['SCRIPT_URI'] ) ) {
529
+ $start = strpos( $this->SERVER['SCRIPT_URI'], '/', 9 );
530
+ $sub = substr( $this->SERVER['SCRIPT_URI'], $start );
531
+ $this->SERVER['SCRIPT_URI'] = substr(
532
+ $this->SERVER['SCRIPT_URI'], 0, $start ) .
533
+ @str_replace(
534
+ $this->SERVER['SCRIPT_URL'], $parsedUrl['path'],
535
+ $sub, $c=1 );
536
+ }
537
+ if( isset( $this->SERVER['SCRIPT_URL'] ) ) {
538
+ $this->SERVER['SCRIPT_URL'] = $parsedUrl['path'];
539
+ }
540
+ }
541
+
542
+ /**
543
+ * Check this request against the cms, standard, and default routers to fill
544
+ * the module/controller/action/route fields.
545
+ *
546
+ * TODO: This whole thing is a gigantic hack. Would be nice to have a
547
+ * better solution.
548
+ *
549
+ * @return null
550
+ */
551
+ public function fakeRouterDispatch() {
552
+ if( $this->_cmsRouterMatch() ) {
553
+ Mage::helper( 'turpentine/debug' )->logDebug( 'Matched router: cms' );
554
+ } elseif( $this->_standardRouterMatch() ) {
555
+ Mage::helper( 'turpentine/debug' )->logDebug( 'Matched router: standard' );
556
+ } elseif( $this->_defaultRouterMatch() ) {
557
+ Mage::helper( 'turpentine/debug' )->logDebug( 'Matched router: default' );
558
+ } else {
559
+ Mage::helper( 'turpentine/debug' )->logDebug( 'No router match' );
560
+ }
561
+ }
562
+
563
+ /**
564
+ *
565
+ *
566
+ * @return boolean
567
+ */
568
+ protected function _defaultRouterMatch() {
569
+ $noRoute = explode('/', Mage::app()->getStore()->getConfig('web/default/no_route'));
570
+ $moduleName = isset($noRoute[0]) ? $noRoute[0] : 'core';
571
+ $controllerName = isset($noRoute[1]) ? $noRoute[1] : 'index';
572
+ $actionName = isset($noRoute[2]) ? $noRoute[2] : 'index';
573
+
574
+ if (Mage::app()->getStore()->isAdmin()) {
575
+ $adminFrontName = (string)Mage::getConfig()->getNode('admin/routers/adminhtml/args/frontName');
576
+ if ($adminFrontName != $moduleName) {
577
+ $moduleName = 'core';
578
+ $controllerName = 'index';
579
+ $actionName = 'noRoute';
580
+ Mage::app()->setCurrentStore(Mage::app()->getDefaultStoreView());
581
+ }
582
+ }
583
+
584
+ $this->setModuleName($moduleName)
585
+ ->setControllerName($controllerName)
586
+ ->setActionName($actionName);
587
+
588
+ return true;
589
+ }
590
+
591
+ /**
592
+ *
593
+ *
594
+ * @return bool
595
+ */
596
+ protected function _standardRouterMatch() {
597
+ $router = Mage::app()->getFrontController()->getRouter( 'standard' );
598
+
599
+ // $router->fetchDefault();
600
+
601
+ $front = $router->getFront();
602
+ $path = trim($this->getPathInfo(), '/');
603
+
604
+ if ($path) {
605
+ $p = explode('/', $path);
606
+ } else {
607
+ // was $router->_getDefaultPath()
608
+ $p = explode('/', Mage::getStoreConfig('web/default/front'));
609
+ }
610
+
611
+ // get module name
612
+ if ($this->getModuleName()) {
613
+ $module = $this->getModuleName();
614
+ } else {
615
+ if (!empty($p[0])) {
616
+ $module = $p[0];
617
+ } else {
618
+ $module = $router->getFront()->getDefault('module');
619
+ $this->setAlias(Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS, '');
620
+ }
621
+ }
622
+ if (!$module) {
623
+ if (Mage::app()->getStore()->isAdmin()) {
624
+ $module = 'admin';
625
+ } else {
626
+ return false;
627
+ }
628
+ }
629
+
630
+ /**
631
+ * Searching router args by module name from route using it as key
632
+ */
633
+ $modules = $router->getModuleByFrontName($module);
634
+
635
+ if ($modules === false) {
636
+ return false;
637
+ }
638
+
639
+ /**
640
+ * Going through modules to find appropriate controller
641
+ */
642
+ $found = false;
643
+ foreach ($modules as $realModule) {
644
+ $this->setRouteName($router->getRouteByFrontName($module));
645
+
646
+ // get controller name
647
+ if ($this->getControllerName()) {
648
+ $controller = $this->getControllerName();
649
+ } else {
650
+ if (!empty($p[1])) {
651
+ $controller = $p[1];
652
+ } else {
653
+ $controller = $front->getDefault('controller');
654
+ $this->setAlias(
655
+ Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS,
656
+ ltrim($this->getOriginalPathInfo(), '/')
657
+ );
658
+ }
659
+ }
660
+
661
+ // get action name
662
+ if (empty($action)) {
663
+ if ($this->getActionName()) {
664
+ $action = $this->getActionName();
665
+ } else {
666
+ $action = !empty($p[2]) ? $p[2] : $front->getDefault('action');
667
+ }
668
+ }
669
+
670
+ //checking if this place should be secure
671
+ // $router->_checkShouldBeSecure($this, '/'.$module.'/'.$controller.'/'.$action);
672
+
673
+ // $controllerClassName = $router->_validateControllerClassName($realModule, $controller);
674
+ $controllerClassName = $router->getControllerClassName( $realModule, $controller );
675
+ if (!$controllerClassName) {
676
+ continue;
677
+ } else {
678
+ $controllerFileName = $router->getControllerFileName( $realModule, $controller );
679
+ if( !$router->validateControllerFileName( $controllerFileName ) ) {
680
+ return false;
681
+ }
682
+ if (!class_exists($controllerClassName, false)) {
683
+ if (!file_exists($controllerFileName)) {
684
+ return false;
685
+ }
686
+ include_once $controllerFileName;
687
+
688
+ if (!class_exists($controllerClassName, false)) {
689
+ throw Mage::exception('Mage_Core', Mage::helper('core')->__('Controller file was loaded but class does not exist'));
690
+ }
691
+ }
692
+ }
693
+
694
+ // instantiate controller class
695
+ $controllerInstance = Mage::getControllerInstance($controllerClassName, $this, $front->getResponse());
696
+
697
+ if (!$controllerInstance->hasAction($action)) {
698
+ continue;
699
+ }
700
+
701
+ $found = true;
702
+ break;
703
+ }
704
+
705
+ /**
706
+ * if we did not found any suitable
707
+ */
708
+ if (!$found) {
709
+ /*
710
+ if ($router->_noRouteShouldBeApplied()) {
711
+ $controller = 'index';
712
+ $action = 'noroute';
713
+
714
+ $controllerClassName = $router->_validateControllerClassName($realModule, $controller);
715
+ if (!$controllerClassName) {
716
+ return false;
717
+ }
718
+
719
+ // instantiate controller class
720
+ $controllerInstance = Mage::getControllerInstance($controllerClassName, $this,
721
+ $front->getResponse());
722
+
723
+ if (!$controllerInstance->hasAction($action)) {
724
+ return false;
725
+ }
726
+ } else {
727
+ return false;
728
+ }
729
+ */
730
+ return false;
731
+ }
732
+
733
+ // set values only after all the checks are done
734
+ $this->setModuleName($module);
735
+ $this->setControllerName($controller);
736
+ $this->setActionName($action);
737
+ $this->setControllerModule($realModule);
738
+
739
+ // set parameters from pathinfo
740
+ for ($i = 3, $l = sizeof($p); $i < $l; $i += 2) {
741
+ $this->setParam($p[$i], isset($p[$i+1]) ? urldecode($p[$i+1]) : '');
742
+ }
743
+
744
+ // dispatch action
745
+ $this->setDispatched(true);
746
+ // $controllerInstance->dispatch($action);
747
+
748
+ return true;
749
+ }
750
+
751
+ /**
752
+ *
753
+ *
754
+ * @return bool
755
+ */
756
+ protected function _cmsRouterMatch() {
757
+ $router = Mage::app()->getFrontController()->getRouter( 'cms' );
758
+
759
+ $identifier = trim($this->getPathInfo(), '/');
760
+
761
+ $condition = new Varien_Object(array(
762
+ 'identifier' => $identifier,
763
+ 'continue' => true
764
+ ));
765
+ Mage::dispatchEvent('cms_controller_router_match_before', array(
766
+ 'router' => $router,
767
+ 'condition' => $condition
768
+ ));
769
+ $identifier = $condition->getIdentifier();
770
+
771
+ if ($condition->getRedirectUrl()) {
772
+ Mage::app()->getFrontController()->getResponse()
773
+ ->setRedirect($condition->getRedirectUrl())
774
+ ->sendResponse();
775
+ $this->setDispatched(true);
776
+ return true;
777
+ }
778
+
779
+ if (!$condition->getContinue()) {
780
+ return false;
781
+ }
782
+
783
+ $page = Mage::getModel('cms/page');
784
+ $pageId = $page->checkIdentifier($identifier, Mage::app()->getStore()->getId());
785
+ if (!$pageId) {
786
+ return false;
787
+ }
788
+
789
+ $this->setModuleName('cms')
790
+ ->setControllerName('page')
791
+ ->setActionName('view')
792
+ ->setParam('page_id', $pageId);
793
+ $this->setAlias(
794
+ Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS,
795
+ $identifier
796
+ );
797
+
798
+ return true;
799
+ }
800
+ }
app/code/community/Nexcessnet/Turpentine/Model/Observer/Ban.php CHANGED
@@ -83,15 +83,19 @@ class Nexcessnet_Turpentine_Model_Observer_Ban extends Varien_Event_Observer {
83
  */
84
  public function banProductPageCache( $eventObject ) {
85
  if( Mage::helper( 'turpentine/varnish' )->getVarnishEnabled() ) {
 
86
  $product = $eventObject->getProduct();
87
- $urlPattern = Mage::helper( 'turpentine/ban' )
88
- ->getProductBanRegex( $product );
89
  $result = $this->_getVarnishAdmin()->flushUrl( $urlPattern );
90
  Mage::dispatchEvent( 'turpentine_ban_product_cache', $result );
91
  $cronHelper = Mage::helper( 'turpentine/cron' );
92
  if( $this->_checkResult( $result ) &&
93
  $cronHelper->getCrawlerEnabled() ) {
94
  $cronHelper->addProductToCrawlerQueue( $product );
 
 
 
 
95
  }
96
  }
97
  }
@@ -108,7 +112,7 @@ class Nexcessnet_Turpentine_Model_Observer_Ban extends Varien_Event_Observer {
108
  public function banProductPageCacheCheckStock( $eventObject ) {
109
  if( Mage::helper( 'turpentine/varnish' )->getVarnishEnabled() ) {
110
  $item = $eventObject->getItem();
111
- if( $item->getStockStatusChangedAuto() ||
112
  ( $item->getOriginalInventoryQty() <= 0 &&
113
  $item->getQty() > 0 &&
114
  $item->getQtyCorrection() > 0 ) ) {
@@ -125,7 +129,7 @@ class Nexcessnet_Turpentine_Model_Observer_Ban extends Varien_Event_Observer {
125
  $cronHelper->addProductToCrawlerQueue( $product );
126
  foreach( $banHelper->getParentProducts( $product )
127
  as $parentProduct ) {
128
- $cronHelper->addProductToCrawlerQueue( $product );
129
  }
130
  }
131
  }
83
  */
84
  public function banProductPageCache( $eventObject ) {
85
  if( Mage::helper( 'turpentine/varnish' )->getVarnishEnabled() ) {
86
+ $banHelper = Mage::helper( 'turpentine/ban' );
87
  $product = $eventObject->getProduct();
88
+ $urlPattern = $banHelper->getProductBanRegex( $product );
 
89
  $result = $this->_getVarnishAdmin()->flushUrl( $urlPattern );
90
  Mage::dispatchEvent( 'turpentine_ban_product_cache', $result );
91
  $cronHelper = Mage::helper( 'turpentine/cron' );
92
  if( $this->_checkResult( $result ) &&
93
  $cronHelper->getCrawlerEnabled() ) {
94
  $cronHelper->addProductToCrawlerQueue( $product );
95
+ foreach( $banHelper->getParentProducts( $product )
96
+ as $parentProduct ) {
97
+ $cronHelper->addProductToCrawlerQueue( $parentProduct );
98
+ }
99
  }
100
  }
101
  }
112
  public function banProductPageCacheCheckStock( $eventObject ) {
113
  if( Mage::helper( 'turpentine/varnish' )->getVarnishEnabled() ) {
114
  $item = $eventObject->getItem();
115
+ if( $item->getStockStatusChangedAutomatically() ||
116
  ( $item->getOriginalInventoryQty() <= 0 &&
117
  $item->getQty() > 0 &&
118
  $item->getQtyCorrection() > 0 ) ) {
129
  $cronHelper->addProductToCrawlerQueue( $product );
130
  foreach( $banHelper->getParentProducts( $product )
131
  as $parentProduct ) {
132
+ $cronHelper->addProductToCrawlerQueue( $parentProduct );
133
  }
134
  }
135
  }
app/code/community/Nexcessnet/Turpentine/Model/Observer/Esi.php CHANGED
@@ -79,7 +79,6 @@ class Nexcessnet_Turpentine_Model_Observer_Esi extends Varien_Event_Observer {
79
  $esiHelper = Mage::helper( 'turpentine/esi' );
80
  $url = $eventObject->getTransport()->getUrl();
81
  $referer = Mage::helper( 'core/http' )->getHttpReferer();
82
- // $referer = Mage::app()->getRequest()->getHeader( 'Referer' );
83
  $dummyUrl = $esiHelper->getDummyUrl();
84
  $reqUenc = Mage::helper( 'core' )->urlDecode(
85
  Mage::app()->getRequest()->getParam( 'uenc' ) );
79
  $esiHelper = Mage::helper( 'turpentine/esi' );
80
  $url = $eventObject->getTransport()->getUrl();
81
  $referer = Mage::helper( 'core/http' )->getHttpReferer();
 
82
  $dummyUrl = $esiHelper->getDummyUrl();
83
  $reqUenc = Mage::helper( 'core' )->urlDecode(
84
  Mage::app()->getRequest()->getParam( 'uenc' ) );
app/code/community/Nexcessnet/Turpentine/Model/PageCache/Container/Notices.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Nexcess.net Turpentine Extension for Magento
5
+ * Copyright (C) 2012 Nexcess.net L.L.C.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+ class Nexcessnet_Turpentine_Model_PageCache_Container_Notices
23
+ extends Enterprise_PageCache_Model_Container_Abstract {
24
+
25
+ /**
26
+ * Generate placeholder content before application was initialized and apply to page content if possible
27
+ *
28
+ * @param string $content
29
+ * @return boolean
30
+ */
31
+ public function applyWithoutApp( &$content ) {
32
+ return false;
33
+ }
34
+
35
+ /**
36
+ * Render block content
37
+ *
38
+ * @return string
39
+ */
40
+ protected function _renderBlock() {
41
+ $block = new Nexcessnet_Turpentine_Block_Notices();
42
+ $block->setTemplate( 'turpentine/notices.phtml' );
43
+
44
+ return $block->toHtml();
45
+ }
46
+ }
app/code/community/Nexcessnet/Turpentine/Model/Varnish/Admin/Socket.php CHANGED
@@ -43,6 +43,24 @@
43
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
  * THE SOFTWARE.
45
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  class Nexcessnet_Turpentine_Model_Varnish_Admin_Socket {
47
 
48
  // possible command return codes, from vcli.h
43
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
  * THE SOFTWARE.
45
  */
46
+
47
+ /**
48
+ * @method array help()
49
+ * @method array ping()
50
+ * @method array auth()
51
+ * @method array banner()
52
+ * @method array vcl_load()
53
+ * @method array vcl_inline()
54
+ * @method array vcl_use()
55
+ * @method array vcl_discard()
56
+ * @method array vcl_list()
57
+ * @method array vcl_show()
58
+ * @method array param_show()
59
+ * @method array param_set()
60
+ * @method array ban_url()
61
+ * @method array ban()
62
+ * @method array ban_list()
63
+ */
64
  class Nexcessnet_Turpentine_Model_Varnish_Admin_Socket {
65
 
66
  // possible command return codes, from vcli.h
app/code/community/Nexcessnet/Turpentine/Model/Varnish/Configurator/Abstract.php CHANGED
@@ -21,7 +21,6 @@
21
 
22
  abstract class Nexcessnet_Turpentine_Model_Varnish_Configurator_Abstract {
23
 
24
- const VCL_FRAGMENT_FILE = 'custom_include.vcl';
25
  const VCL_CUSTOM_C_CODE_FILE = 'uuid.c';
26
 
27
  /**
@@ -121,6 +120,17 @@ abstract class Nexcessnet_Turpentine_Model_Varnish_Configurator_Abstract {
121
  array( 'root_dir' => Mage::getBaseDir() ) );
122
  }
123
 
 
 
 
 
 
 
 
 
 
 
 
124
  /**
125
  * Format a template string, replacing {{keys}} with the appropriate values
126
  * and remove unspecified keys
@@ -640,9 +650,9 @@ EOS;
640
  $vars['normalize_host'] = $this->_vcl_sub_normalize_host();
641
  }
642
 
643
- $customInclude = $this->_getVclTemplateFilename( self::VCL_FRAGMENT_FILE );
644
- if( is_readable( $customInclude ) ) {
645
- $vars['custom_vcl_include'] = file_get_contents( $customInclude );
646
  }
647
 
648
  return $vars;
21
 
22
  abstract class Nexcessnet_Turpentine_Model_Varnish_Configurator_Abstract {
23
 
 
24
  const VCL_CUSTOM_C_CODE_FILE = 'uuid.c';
25
 
26
  /**
120
  array( 'root_dir' => Mage::getBaseDir() ) );
121
  }
122
 
123
+ /**
124
+ * Get the name of the custom include VCL file
125
+ *
126
+ * @return string
127
+ */
128
+ protected function _getCustomIncludeFilename() {
129
+ return $this->_formatTemplate(
130
+ Mage::getStoreConfig( 'turpentine_varnish/servers/custom_include_file' ),
131
+ array( 'root_dir' => Mage::getBaseDir() ) );
132
+ }
133
+
134
  /**
135
  * Format a template string, replacing {{keys}} with the appropriate values
136
  * and remove unspecified keys
650
  $vars['normalize_host'] = $this->_vcl_sub_normalize_host();
651
  }
652
 
653
+ $customIncludeFile = $this->_getCustomIncludeFilename();
654
+ if( is_readable( $customIncludeFile ) ) {
655
+ $vars['custom_vcl_include'] = file_get_contents( $customIncludeFile );
656
  }
657
 
658
  return $vars;
app/code/community/Nexcessnet/Turpentine/controllers/EsiController.php CHANGED
@@ -69,8 +69,14 @@ class Nexcessnet_Turpentine_EsiController extends Mage_Core_Controller_Front_Act
69
  Mage::app()->setCurrentStore(
70
  Mage::app()->getStore( $esiData->getStoreId() ) );
71
  $appShim = Mage::getModel( 'turpentine/shim_mage_core_app' );
72
- $appShim->shim_setRequest( Mage::helper( 'turpentine/esi' )->
73
- getDummyRequest() );
 
 
 
 
 
 
74
  $block = $this->_getEsiBlock( $esiData );
75
  if( $block ) {
76
  $block->setEsiOptions( false );
@@ -125,6 +131,7 @@ class Nexcessnet_Turpentine_EsiController extends Mage_Core_Controller_Front_Act
125
  * @return Mage_Core_Block_Template
126
  */
127
  protected function _getEsiBlock( $esiData ) {
 
128
  Varien_Profiler::start( 'turpentine::controller::esi::_getEsiBlock' );
129
  foreach( $esiData->getSimpleRegistry() as $key => $value ) {
130
  Mage::register( $key, $value, true );
@@ -147,18 +154,25 @@ class Nexcessnet_Turpentine_EsiController extends Mage_Core_Controller_Front_Act
147
  $blockNode = current( $layout->getNode()->xpath( sprintf(
148
  '//block[@name=\'%s\']',
149
  $esiData->getNameInLayout() ) ) );
150
- $nodesToGenerate = Mage::helper( 'turpentine/data' )
151
- ->getChildBlockNames( $blockNode );
152
- Mage::getModel( 'turpentine/shim_mage_core_layout' )
153
- ->shim_generateFullBlock( $blockNode );
154
- foreach( $nodesToGenerate as $nodeName ) {
155
- foreach( $layout->getNode()->xpath( sprintf(
156
- '//reference[@name=\'%s\']', $nodeName ) ) as $node ) {
157
- $layout->generateBlocks( $node );
 
 
158
  }
 
 
 
 
 
159
  }
160
  Varien_Profiler::stop( 'turpentine::controller::esi::_getEsiBlock' );
161
- return $layout->getBlock( $esiData->getNameInLayout() );
162
  }
163
 
164
  /**
69
  Mage::app()->setCurrentStore(
70
  Mage::app()->getStore( $esiData->getStoreId() ) );
71
  $appShim = Mage::getModel( 'turpentine/shim_mage_core_app' );
72
+ if( $referer = Mage::helper( 'core/http' )->getHttpReferer() ) {
73
+ $dummyRequest = Mage::helper( 'turpentine/esi' )
74
+ ->getDummyRequest( $referer );
75
+ } else {
76
+ $dummyRequest = Mage::helper( 'turpentine/esi' )
77
+ ->getDummyRequest();
78
+ }
79
+ $appShim->shim_setRequest( $dummyRequest );
80
  $block = $this->_getEsiBlock( $esiData );
81
  if( $block ) {
82
  $block->setEsiOptions( false );
131
  * @return Mage_Core_Block_Template
132
  */
133
  protected function _getEsiBlock( $esiData ) {
134
+ $block = null;
135
  Varien_Profiler::start( 'turpentine::controller::esi::_getEsiBlock' );
136
  foreach( $esiData->getSimpleRegistry() as $key => $value ) {
137
  Mage::register( $key, $value, true );
154
  $blockNode = current( $layout->getNode()->xpath( sprintf(
155
  '//block[@name=\'%s\']',
156
  $esiData->getNameInLayout() ) ) );
157
+ if( $blockNode instanceof Varien_Simplexml_Element ) {
158
+ $nodesToGenerate = Mage::helper( 'turpentine/data' )
159
+ ->getChildBlockNames( $blockNode );
160
+ Mage::getModel( 'turpentine/shim_mage_core_layout' )
161
+ ->shim_generateFullBlock( $blockNode );
162
+ foreach( $nodesToGenerate as $nodeName ) {
163
+ foreach( $layout->getNode()->xpath( sprintf(
164
+ '//reference[@name=\'%s\']', $nodeName ) ) as $node ) {
165
+ $layout->generateBlocks( $node );
166
+ }
167
  }
168
+ $block = $layout->getBlock( $esiData->getNameInLayout() );
169
+ } else {
170
+ Mage::helper( 'turpentine/debug' )->logWarn(
171
+ 'No block node found with @name="%s"',
172
+ $esiData->getNameInLayout() );
173
  }
174
  Varien_Profiler::stop( 'turpentine::controller::esi::_getEsiBlock' );
175
+ return $block;
176
  }
177
 
178
  /**
app/code/community/Nexcessnet/Turpentine/controllers/Varnish/ManagementController.php CHANGED
@@ -195,6 +195,45 @@ class Nexcessnet_Turpentine_Varnish_ManagementController
195
  }
196
  }
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  /**
199
  * Check if a visitor is allowed access to this controller/action(?)
200
  *
195
  }
196
  }
197
 
198
+ /**
199
+ * Activate or deactivate the Varnish bypass
200
+ *
201
+ * @return void
202
+ */
203
+ public function switchNavigationAction() {
204
+ $type = $this->getRequest()->get( 'type' );
205
+ if( is_null( $type ) ) {
206
+ $this->_redirect( 'noRoute' );
207
+ return;
208
+ }
209
+
210
+ $cookieName = Mage::helper( 'turpentine' )->getBypassCookieName();
211
+ $cookieModel = Mage::getModel( 'core/cookie' );
212
+ $adminSession = Mage::getSingleton( 'adminhtml/session' );
213
+
214
+ switch( $type ) {
215
+ case 'default':
216
+ $cookieModel->set( $cookieName,
217
+ Mage::helper( 'turpentine/varnish' )->getSecretHandshake() );
218
+ $adminSession->addSuccess( Mage::helper( 'turpentine/data' )
219
+ ->__( 'The Varnish bypass cookie has been successfully added.' ) );
220
+ break;
221
+
222
+ case 'varnish':
223
+ $cookieModel->delete( $cookieName );
224
+ $adminSession->addSuccess( Mage::helper( 'turpentine/data' )
225
+ ->__( 'The Varnish bypass cookie has been successfully removed.' ) );
226
+ break;
227
+
228
+ default:
229
+ $adminSession->addError( Mage::helper( 'turpentine/data' )
230
+ ->__( 'The given navigation type is not supported!' ) );
231
+ break;
232
+ }
233
+
234
+ $this->_redirectReferer();
235
+ }
236
+
237
  /**
238
  * Check if a visitor is allowed access to this controller/action(?)
239
  *
app/code/community/Nexcessnet/Turpentine/etc/cache.xml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ Nexcess.net Turpentine Extension for Magento
4
+ Copyright (C) 2012 Nexcess.net L.L.C.
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License along
17
+ with this program; if not, write to the Free Software Foundation, Inc.,
18
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ -->
20
+ <config>
21
+ <placeholders>
22
+ <turpentine_notices>
23
+ <block>turpentine/notices</block>
24
+ <placeholder>TURPENTINE_NOTICES</placeholder>
25
+ <container>Nexcessnet_Turpentine_Model_PageCache_Container_Notices</container>
26
+ <cache_lifetime>false</cache_lifetime>
27
+ </turpentine_notices>
28
+ </placeholders>
29
+ </config>
app/code/community/Nexcessnet/Turpentine/etc/config.xml CHANGED
@@ -20,7 +20,7 @@
20
  <config>
21
  <modules>
22
  <Nexcessnet_Turpentine>
23
- <version>0.5.3</version>
24
  </Nexcessnet_Turpentine>
25
  </modules>
26
  <default>
@@ -38,6 +38,7 @@
38
  <version>auto</version>
39
  <server_list>127.0.0.1:6082</server_list>
40
  <config_file>{{root_dir}}/var/default.vcl</config_file>
 
41
  </servers>
42
  </turpentine_varnish>
43
  <turpentine_vcl>
20
  <config>
21
  <modules>
22
  <Nexcessnet_Turpentine>
23
+ <version>0.5.4</version>
24
  </Nexcessnet_Turpentine>
25
  </modules>
26
  <default>
38
  <version>auto</version>
39
  <server_list>127.0.0.1:6082</server_list>
40
  <config_file>{{root_dir}}/var/default.vcl</config_file>
41
+ <custom_include_file>{{root_dir}}/app/code/community/Nexcessnet/Turpentine/misc/custom_include.vcl</custom_include_file>
42
  </servers>
43
  </turpentine_varnish>
44
  <turpentine_vcl>
app/code/community/Nexcessnet/Turpentine/etc/system.xml CHANGED
@@ -158,6 +158,15 @@
158
  <show_in_website>0</show_in_website>
159
  <show_in_store>0</show_in_store>
160
  </config_file>
 
 
 
 
 
 
 
 
 
161
  </fields>
162
  </servers>
163
  </groups>
158
  <show_in_website>0</show_in_website>
159
  <show_in_store>0</show_in_store>
160
  </config_file>
161
+ <custom_include_file translate="label" module="turpentine">
162
+ <label>Custom VCL File Location</label>
163
+ <frontend_type>text</frontend_type>
164
+ <comment>Specify where the Varnish VCL customization file should be saved</comment>
165
+ <sort_order>40</sort_order>
166
+ <show_in_default>1</show_in_default>
167
+ <show_in_website>0</show_in_website>
168
+ <show_in_store>0</show_in_store>
169
+ </custom_include_file>
170
  </fields>
171
  </servers>
172
  </groups>
app/code/community/Nexcessnet/Turpentine/misc/version-2.vcl CHANGED
@@ -112,28 +112,27 @@ sub vcl_recv {
112
  }
113
  }
114
 
115
- # We only deal with GET and HEAD by default
116
- if (!(req.request ~ "^(GET|HEAD)$")) {
117
- return (pipe);
118
- }
119
-
120
- call remove_double_slashes;
121
-
122
- {{normalize_encoding}}
123
- {{normalize_user_agent}}
124
- {{normalize_host}}
125
-
126
  # varnish 2.1 doesn't support bare booleans so we have to add these
127
  # as headers to the req so they've available throught the VCL
128
  set req.http.X-Opt-Enable-Caching = "{{enable_caching}}";
129
  set req.http.X-Opt-Force-Static-Caching = "{{force_cache_static}}";
130
  set req.http.X-Opt-Enable-Get-Excludes = "{{enable_get_excludes}}";
131
 
 
132
  # we test this here instead of inside the url base regex section
133
  # so we can disable caching for the entire site if needed
134
- if (req.http.X-Opt-Enable-Caching != "true" || req.http.Authorization) {
 
 
135
  return (pipe);
136
  }
 
 
 
 
 
 
 
137
  # check if the request is for part of magento
138
  if (req.url ~ "{{url_base_regex}}") {
139
  # set this so Turpentine can see the request passed through Varnish
@@ -190,19 +189,23 @@ sub vcl_recv {
190
  # this doesn't need a enable_url_excludes because we can be reasonably
191
  # certain that cron.php at least will always be in it, so it will
192
  # never be empty
193
- if (req.url ~ "{{url_base_regex}}(?:{{url_excludes}})") {
194
- return (pipe);
195
- }
196
- if (req.url ~ "\?.*__from_store=") {
197
- # user switched stores. we pipe this instead of passing below because
198
- # switching stores doesn't redirect (302), just acts like a link to
199
- # another page (200) so the Set-Cookie header would be removed
200
  return (pipe);
201
  }
202
  if (req.http.X-Opt-Enable-Get-Excludes == "true" &&
203
  req.url ~ "(?:[?&](?:{{get_param_excludes}})(?=[&=]|$))") {
204
  return (pass);
205
  }
 
 
 
 
 
 
206
  return (lookup);
207
  }
208
  # else it's not part of magento so do default handling (doesn't help
@@ -235,9 +238,15 @@ sub vcl_hash {
235
  # make sure we give back the right encoding
236
  set req.hash += req.http.Accept-Encoding;
237
  }
238
- # make sure data is for the right store and currency based on the *store*
239
- # and *currency* cookies
240
- set req.hash += "s=" req.http.X-Varnish-Store "&c=" req.http.X-Varnish-Currency;
 
 
 
 
 
 
241
  if (req.http.X-Varnish-Esi-Access == "private" &&
242
  req.http.Cookie ~ "frontend=") {
243
  set req.hash += regsub(req.http.Cookie, "^.*?frontend=([^;]*);*.*$", "\1");
@@ -334,8 +343,7 @@ sub vcl_deliver {
334
  # need to set the set-cookie header since we just made it out of thin air
335
  call generate_session_expires;
336
  set resp.http.Set-Cookie = req.http.X-Varnish-Faked-Session "; expires="
337
- resp.http.X-Varnish-Cookie-Expires "; path="
338
- regsub(regsub(req.url, "{{url_base_regex}}.*", "\1"), "^(.+)/$", "\1");
339
  if (req.http.Host) {
340
  set resp.http.Set-Cookie = resp.http.Set-Cookie
341
  "; domain=" regsub(req.http.Host, ":\d+$", "");
112
  }
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
115
  # varnish 2.1 doesn't support bare booleans so we have to add these
116
  # as headers to the req so they've available throught the VCL
117
  set req.http.X-Opt-Enable-Caching = "{{enable_caching}}";
118
  set req.http.X-Opt-Force-Static-Caching = "{{force_cache_static}}";
119
  set req.http.X-Opt-Enable-Get-Excludes = "{{enable_get_excludes}}";
120
 
121
+ # We only deal with GET and HEAD by default
122
  # we test this here instead of inside the url base regex section
123
  # so we can disable caching for the entire site if needed
124
+ if (req.http.X-Opt-Enable-Caching != "true" || req.http.Authorization ||
125
+ !(req.request ~ "^(GET|HEAD)$") ||
126
+ req.http.Cookie ~ "varnish_bypass={{secret_handshake}}") {
127
  return (pipe);
128
  }
129
+
130
+ call remove_double_slashes;
131
+
132
+ {{normalize_encoding}}
133
+ {{normalize_user_agent}}
134
+ {{normalize_host}}
135
+
136
  # check if the request is for part of magento
137
  if (req.url ~ "{{url_base_regex}}") {
138
  # set this so Turpentine can see the request passed through Varnish
189
  # this doesn't need a enable_url_excludes because we can be reasonably
190
  # certain that cron.php at least will always be in it, so it will
191
  # never be empty
192
+ if (req.url ~ "{{url_base_regex}}(?:{{url_excludes}})" ||
193
+ # user switched stores. we pipe this instead of passing below because
194
+ # switching stores doesn't redirect (302), just acts like a link to
195
+ # another page (200) so the Set-Cookie header would be removed
196
+ req.url ~ "\?.*__from_store=") {
 
 
197
  return (pipe);
198
  }
199
  if (req.http.X-Opt-Enable-Get-Excludes == "true" &&
200
  req.url ~ "(?:[?&](?:{{get_param_excludes}})(?=[&=]|$))") {
201
  return (pass);
202
  }
203
+ if (req.url ~ "[?&](utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
204
+ # Strip out Google related parameters
205
+ set req.url = regsuball(req.url, "(?:(\?)?|&)(?:utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=[^&]+", "\1");
206
+ set req.url = regsuball(req.url, "(?:(\?)&|\?$)", "\1");
207
+ }
208
+
209
  return (lookup);
210
  }
211
  # else it's not part of magento so do default handling (doesn't help
238
  # make sure we give back the right encoding
239
  set req.hash += req.http.Accept-Encoding;
240
  }
241
+ if (req.http.X-Varnish-Store || req.http.X-Varnish-Currency) {
242
+ # make sure data is for the right store and currency based on the *store*
243
+ # and *currency* cookies
244
+ set req.hash += "s=";
245
+ set req.hash += req.http.X-Varnish-Store;
246
+ set req.hash += "&c=";
247
+ set req.hash += req.http.X-Varnish-Currency;
248
+ }
249
+
250
  if (req.http.X-Varnish-Esi-Access == "private" &&
251
  req.http.Cookie ~ "frontend=") {
252
  set req.hash += regsub(req.http.Cookie, "^.*?frontend=([^;]*);*.*$", "\1");
343
  # need to set the set-cookie header since we just made it out of thin air
344
  call generate_session_expires;
345
  set resp.http.Set-Cookie = req.http.X-Varnish-Faked-Session "; expires="
346
+ resp.http.X-Varnish-Cookie-Expires "; path=/";
 
347
  if (req.http.Host) {
348
  set resp.http.Set-Cookie = resp.http.Set-Cookie
349
  "; domain=" regsub(req.http.Host, ":\d+$", "");
app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl CHANGED
@@ -121,7 +121,11 @@ sub vcl_recv {
121
  }
122
 
123
  # We only deal with GET and HEAD by default
124
- if (req.request !~ "^(GET|HEAD)$") {
 
 
 
 
125
  return (pipe);
126
  }
127
 
@@ -131,11 +135,6 @@ sub vcl_recv {
131
  {{normalize_user_agent}}
132
  {{normalize_host}}
133
 
134
- # we test this here instead of inside the url base regex section
135
- # so we can disable caching for the entire site if needed
136
- if (!{{enable_caching}} || req.http.Authorization) {
137
- return (pipe);
138
- }
139
  # check if the request is for part of magento
140
  if (req.url ~ "{{url_base_regex}}") {
141
  # set this so Turpentine can see the request passed through Varnish
@@ -188,13 +187,11 @@ sub vcl_recv {
188
  # this doesn't need a enable_url_excludes because we can be reasonably
189
  # certain that cron.php at least will always be in it, so it will
190
  # never be empty
191
- if (req.url ~ "{{url_base_regex}}(?:{{url_excludes}})") {
192
- return (pipe);
193
- }
194
- if (req.url ~ "\?.*__from_store=") {
195
- # user switched stores. we pipe this instead of passing below because
196
- # switching stores doesn't redirect (302), just acts like a link to
197
- # another page (200) so the Set-Cookie header would be removed
198
  return (pipe);
199
  }
200
  if ({{enable_get_excludes}} &&
@@ -202,6 +199,12 @@ sub vcl_recv {
202
  # TODO: should this be pass or pipe?
203
  return (pass);
204
  }
 
 
 
 
 
 
205
  # everything else checks out, try and pull from the cache
206
  return (lookup);
207
  }
@@ -235,9 +238,12 @@ sub vcl_hash {
235
  # make sure we give back the right encoding
236
  hash_data(req.http.Accept-Encoding);
237
  }
238
- # make sure data is for the right store and currency based on the *store*
239
- # and *currency* cookies
240
- hash_data("s=" + req.http.X-Varnish-Store + "&c=" + req.http.X-Varnish-Currency);
 
 
 
241
  if (req.http.X-Varnish-Esi-Access == "private" &&
242
  req.http.Cookie ~ "frontend=") {
243
  hash_data(regsub(req.http.Cookie, "^.*?frontend=([^;]*);*.*$", "\1"));
@@ -337,8 +343,7 @@ sub vcl_deliver {
337
  # need to set the set-cookie header since we just made it out of thin air
338
  call generate_session_expires;
339
  set resp.http.Set-Cookie = req.http.X-Varnish-Faked-Session +
340
- "; expires=" + resp.http.X-Varnish-Cookie-Expires + "; path=" +
341
- regsub(regsub(req.url, "{{url_base_regex}}.*", "\1"), "^(.+)/$", "\1");
342
  if (req.http.Host) {
343
  set resp.http.Set-Cookie = resp.http.Set-Cookie +
344
  "; domain=" + regsub(req.http.Host, ":\d+$", "");
121
  }
122
 
123
  # We only deal with GET and HEAD by default
124
+ # we test this here instead of inside the url base regex section
125
+ # so we can disable caching for the entire site if needed
126
+ if (!{{enable_caching}} || req.http.Authorization ||
127
+ req.request !~ "^(GET|HEAD)$" ||
128
+ req.http.Cookie ~ "varnish_bypass={{secret_handshake}}") {
129
  return (pipe);
130
  }
131
 
135
  {{normalize_user_agent}}
136
  {{normalize_host}}
137
 
 
 
 
 
 
138
  # check if the request is for part of magento
139
  if (req.url ~ "{{url_base_regex}}") {
140
  # set this so Turpentine can see the request passed through Varnish
187
  # this doesn't need a enable_url_excludes because we can be reasonably
188
  # certain that cron.php at least will always be in it, so it will
189
  # never be empty
190
+ if (req.url ~ "{{url_base_regex}}(?:{{url_excludes}})" ||
191
+ # user switched stores. we pipe this instead of passing below because
192
+ # switching stores doesn't redirect (302), just acts like a link to
193
+ # another page (200) so the Set-Cookie header would be removed
194
+ req.url ~ "\?.*__from_store=") {
 
 
195
  return (pipe);
196
  }
197
  if ({{enable_get_excludes}} &&
199
  # TODO: should this be pass or pipe?
200
  return (pass);
201
  }
202
+ if (req.url ~ "[?&](utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
203
+ # Strip out Google related parameters
204
+ set req.url = regsuball(req.url, "(?:(\?)?|&)(?:utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=[^&]+", "\1");
205
+ set req.url = regsuball(req.url, "(?:(\?)&|\?$)", "\1");
206
+ }
207
+
208
  # everything else checks out, try and pull from the cache
209
  return (lookup);
210
  }
238
  # make sure we give back the right encoding
239
  hash_data(req.http.Accept-Encoding);
240
  }
241
+ if (req.http.X-Varnish-Store || req.http.X-Varnish-Currency) {
242
+ # make sure data is for the right store and currency based on the *store*
243
+ # and *currency* cookies
244
+ hash_data("s=" + req.http.X-Varnish-Store + "&c=" + req.http.X-Varnish-Currency);
245
+ }
246
+
247
  if (req.http.X-Varnish-Esi-Access == "private" &&
248
  req.http.Cookie ~ "frontend=") {
249
  hash_data(regsub(req.http.Cookie, "^.*?frontend=([^;]*);*.*$", "\1"));
343
  # need to set the set-cookie header since we just made it out of thin air
344
  call generate_session_expires;
345
  set resp.http.Set-Cookie = req.http.X-Varnish-Faked-Session +
346
+ "; expires=" + resp.http.X-Varnish-Cookie-Expires + "; path=/";
 
347
  if (req.http.Host) {
348
  set resp.http.Set-Cookie = resp.http.Set-Cookie +
349
  "; domain=" + regsub(req.http.Host, ":\d+$", "");
app/design/adminhtml/default/default/template/turpentine/varnish_management.phtml CHANGED
@@ -1,28 +1,24 @@
1
  <?php
 
2
  /**
3
- * Magento
 
4
  *
5
- * NOTICE OF LICENSE
 
 
 
6
  *
7
- * This source file is subject to the Academic Free License (AFL 3.0)
8
- * that is bundled with this package in the file LICENSE_AFL.txt.
9
- * It is also available through the world-wide-web at this URL:
10
- * http://opensource.org/licenses/afl-3.0.php
11
- * If you did not receive a copy of the license and are unable to
12
- * obtain it through the world-wide-web, please send an email
13
- * to license@magentocommerce.com so we can send you a copy immediately.
14
  *
15
- * DISCLAIMER
16
- *
17
- * Do not edit or add to this file if you wish to upgrade Magento to newer
18
- * versions in the future. If you wish to customize Magento for your
19
- * needs please refer to http://www.magentocommerce.com for more information.
20
- *
21
- * @category design
22
- * @package default_default
23
- * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
- * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
  */
 
26
  ?>
27
  <br />
28
  <div class="content-header">
@@ -36,7 +32,7 @@
36
  </tr>
37
  </table>
38
  </div>
39
- <table class="form-list">
40
  <tr>
41
  <td class="scope-label">
42
  <button
@@ -82,5 +78,44 @@
82
  ->__('Download the generated VCL file.')?>
83
  </td>
84
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  </table>
86
  <?php echo $this->getChildHtml(); ?>
 
 
 
 
 
 
1
  <?php
2
+
3
  /**
4
+ * Nexcess.net Turpentine Extension for Magento
5
+ * Copyright (C) 2012 Nexcess.net L.L.C.
6
  *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
  *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
 
 
 
16
  *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 
 
 
 
 
 
20
  */
21
+
22
  ?>
23
  <br />
24
  <div class="content-header">
32
  </tr>
33
  </table>
34
  </div>
35
+ <table class="form-list varnish-management">
36
  <tr>
37
  <td class="scope-label">
38
  <button
78
  ->__('Download the generated VCL file.')?>
79
  </td>
80
  </tr>
81
+ <?php if(Mage::helper( 'turpentine/varnish' )->isBypassEnabled() === false): ?>
82
+ <tr>
83
+ <td class="scope-label">
84
+ <button
85
+ onclick="setLocation('<?php echo $this->getSwitchNavigationUrl( 'default' ); ?>')"
86
+ type="button"
87
+ class="scalable delete">
88
+ <span><?php echo Mage::helper( 'turpentine/data' )
89
+ ->__('Activate Varnish Bypass') ?></span>
90
+ </button>
91
+ </td>
92
+ <td class="scope-label">
93
+ <?php echo Mage::helper( 'turpentine/data' )
94
+ ->__('Create a cookie to bypass Varnish only for your session.')?>
95
+ </td>
96
+ </tr>
97
+ <?php else: ?>
98
+ <tr>
99
+ <td class="scope-label">
100
+ <button
101
+ onclick="setLocation('<?php echo $this->getSwitchNavigationUrl( 'varnish' ); ?>')"
102
+ type="button"
103
+ class="scalable back">
104
+ <span><?php echo Mage::helper( 'turpentine/data' )
105
+ ->__('Deactivate Varnish Bypass') ?></span>
106
+ </button>
107
+ </td>
108
+ <td class="scope-label">
109
+ <?php echo Mage::helper( 'turpentine/data' )
110
+ ->__('Remove the bypass cookie and use again Varnish.')?>
111
+ </td>
112
+ </tr>
113
+ <?php endif; ?>
114
  </table>
115
  <?php echo $this->getChildHtml(); ?>
116
+
117
+ <style>
118
+ .varnish-management button {
119
+ width: 190px;
120
+ }
121
+ </style>
app/design/frontend/base/default/layout/turpentine_esi.xml CHANGED
@@ -24,6 +24,13 @@
24
  not be specified in the layout
25
  -->
26
  <default>
 
 
 
 
 
 
 
27
  <!--
28
  A default Magento site includes a logged in user's name in the welcome
29
  message and the number of items in the shopping cart so it must be
24
  not be specified in the layout
25
  -->
26
  <default>
27
+ <!--
28
+ New block used to warn users who choose to navigate without Varnish while it's activated.
29
+ -->
30
+ <reference name="after_body_start">
31
+ <block type="turpentine/notices" template="turpentine/notices.phtml" name="turpentine_notices" />
32
+ </reference>
33
+
34
  <!--
35
  A default Magento site includes a logged in user's name in the welcome
36
  message and the number of items in the shopping cart so it must be
app/design/frontend/base/default/template/turpentine/notices.phtml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Nexcess.net Turpentine Extension for Magento
4
+ * Copyright (C) 2012 Nexcess.net L.L.C.
5
+ *
6
+ * This program is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License along
17
+ * with this program; if not, write to the Free Software Foundation, Inc.,
18
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+ ?>
21
+
22
+ <?php if($this->helper( 'turpentine/varnish' )->shouldDisplayNotice()): ?>
23
+ <div class="varnish-global-notice">
24
+ <div class="notice-inner">
25
+ <p>
26
+ <strong><?php echo $this->__('The cookie that allows bypassing Varnish is present in your browser.'); ?></strong><br />
27
+ <?php echo $this->__('Remember that this navigation mode should be only activated for testing. You will suffer a decline in overall performance until you delete this cookie.'); ?>
28
+ </p>
29
+ </div>
30
+ </div>
31
+ <style>
32
+ .varnish-global-notice { border:1px solid #cfcfcf; border-width:0 0 1px; background:#ffff90; font-size:12px; line-height:1.25; text-align:center; color:#2f2f2f; }
33
+ .varnish-global-notice .notice-inner { width:860px; margin:0 auto; padding:12px 0 12px 0px; text-align:left; }
34
+ .varnish-global-notice .notice-inner p { margin:0; padding:10px; }
35
+ </style>
36
+ <?php endif; ?>
package.xml CHANGED
@@ -1 +1 @@
1
- <package><name>Nexcessnet_Turpentine</name><license uri="http://opensource.org/licenses/GPL-2.0">GPLv2</license><notes>Supports Magento v1.6 and later</notes><time>17:57:38</time><__packager>build_package.py v0.0.3</__packager><summary>Improves Magento support for Varnish caching and generates 2.1 and 3.0 compatible VCLs.</summary><stability>stable</stability><__commit_hash>e286d48365bc1dfde23f9a2c2b382f72faa92ee2</__commit_hash><version>0.5.3</version><extends /><contents><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file hash="a0bd4a5632b369b058c0ec5262e0cc49" name="turpentine.xml" /></dir><dir name="template"><dir name="turpentine"><file hash="b5cae58feecaec4b1c2e4558313c2a3f" name="varnish_management.phtml" /></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file hash="460fbf2fa75b7a0090e339852d87a9fc" name="turpentine_esi.xml" /></dir><dir name="template"><dir name="turpentine"><file hash="b268c48251ccfccf5c775d3e85513584" name="esi.phtml" /><file hash="1b337a1cbca5b87a77a3f2419a517d87" name="ajax.phtml" /></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file hash="58848d4d90973bfd63b466ea181352a5" name="Nexcessnet_Turpentine.xml" /></dir></target><target name="magecommunity"><dir name="Nexcessnet"><dir name="Turpentine"><dir name="controllers"><file hash="2985fe63d9ae6ba19b475bc0fe236b49" name="EsiController.php" /><dir name="Varnish"><file hash="9295d4020c36b22265cb43ecf8db9f36" name="ManagementController.php" /></dir></dir><dir name="Helper"><file hash="2d7286c589b7a3e2f8fe873bd12afe3c" name="Debug.php" /><file hash="2c1523f274f5fcd32c77cce27541274b" name="Varnish.php" /><file hash="21af9e9fa2914b6cbe943ca2afec1eba" name="Esi.php" /><file hash="104f1bf79a0a67a1127be7c92c2978f3" name="Data.php" /><file hash="61b69cb98039441a01207a1aae6131f0" name="Cron.php" /><file hash="8f0dd23f9a7b98d8254acf18b6750f1e" name="Ban.php" /></dir><dir name="Model"><file hash="c2cb79001524617febbfddf099d09f37" name="Session.php" /><dir name="Observer"><file hash="9d57fad69ff42b71c66ca26bc3372317" name="Debug.php" /><file hash="7244a8ce600e980d612409595b9b6b9b" name="Varnish.php" /><file hash="a87d99e6fc21143745c49fe6691e462a" name="Esi.php" /><file hash="a34e79218e8ca1fefad303b9399bda9d" name="Cron.php" /><file hash="7c164dc3b91790d513be1410f94f4071" name="Ban.php" /></dir><dir name="Config"><dir name="Select"><file hash="9348c5e58037fd97d89b84ccab4ef2d0" name="Toggle.php" /><file hash="dc472f34c25b1688cfa9fa206958c536" name="Version.php" /></dir></dir><dir name="Varnish"><file hash="fcb8a5582c6f920e910b417c671df6d2" name="Admin.php" /><dir name="Configurator"><file hash="970a058bf2a73a5774b004390fcfaa07" name="Version3.php" /><file hash="4fba0ac0b4837cabec5bbee428d229df" name="Version2.php" /><file hash="8075d99c4a59fffa37d733b7cd162ac6" name="Abstract.php" /></dir><dir name="Admin"><file hash="d135441e2ef2ae08e2a195b7c6488c7e" name="Socket.php" /></dir></dir><dir name="Shim"><dir name="Mage"><dir name="Core"><file hash="821bff6c2fb372e3ffb39abf6453b3f8" name="Layout.php" /><file hash="94d91f8ff1005ce3bf14c4935945563c" name="App.php" /><file hash="43754654bc3bbd046154573efd735dfa" name="Config.php" /></dir></dir></dir></dir><dir name="etc"><file hash="269e5229980f4d061d81c1c632a7d5cd" name="config.xml" /><file hash="5e025bfca6f27f4e54aceaab2c2290b2" name="system.xml" /></dir><dir name="misc"><file hash="f083d5fbf4634af60ed5bb257197834f" name="uuid.c" /><file hash="17814ff0b6061d5a9d1eedde7cdd0704" name="version-2.vcl" /><file hash="481444c10a17bcf05bd32a0216bd0c5a" name="version-3.vcl" /></dir><dir name="Block"><file hash="e517426e31404fb710c821d46085700f" name="Management.php" /><dir name="Core"><file hash="21fac182c4c12a173e27118a7025d725" name="Messages.php" /></dir><dir name="Catalog"><dir name="Product"><dir name="List"><file hash="a3cc4b92cb6a4956e28da798eb9e17df" name="Toolbar.php" /></dir></dir></dir></dir><dir name="sql" /></dir></dir></target></contents><dependencies><required><php><min>5.2.13</min><max>6.0.0</max></php></required></dependencies><authors><author><name>Chris Wells</name><user>nexcess_net</user><email>clwells@nexcess.net</email></author><author><name>Alex Headley</name><user>aheadley_nex</user><email>aheadley@nexcess.net</email></author></authors><date>2013-04-03</date><compatibile /><channel>community</channel><description>Turpentine is a Magento extension to improve Magento's compatibility with Varnish, a very-fast caching reverse-proxy. By default, Varnish doesn't cache requests with cookies and Magento sends the frontend cookie with every request causing a (near) zero hit-rate for Varnish's cache. Turpentine provides Varnish configuration files (VCLs) to work with Magento and modifies Magento's behaviour to significantly improve the cache hit rate.</description></package>
1
+ <package><name>Nexcessnet_Turpentine</name><license uri="http://opensource.org/licenses/GPL-2.0">GPLv2</license><notes>Supports Magento v1.6 and later</notes><time>18:00:48</time><__packager>build_package.py v0.0.3</__packager><summary>Improves Magento support for Varnish caching and generates 2.1 and 3.0 compatible VCLs.</summary><stability>stable</stability><__commit_hash>80a17eaa84c76c89cbb8bb04c78cf83429c3d084</__commit_hash><version>0.5.4</version><extends /><contents><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file hash="a0bd4a5632b369b058c0ec5262e0cc49" name="turpentine.xml" /></dir><dir name="template"><dir name="turpentine"><file hash="3c1bc5339a02d0539a84beeac0a2d9de" name="varnish_management.phtml" /></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file hash="abe5ef296ef7c06a672847c50b572473" name="turpentine_esi.xml" /></dir><dir name="template"><dir name="turpentine"><file hash="b268c48251ccfccf5c775d3e85513584" name="esi.phtml" /><file hash="50798888953fd1550e4347c39e395d0a" name="notices.phtml" /><file hash="1b337a1cbca5b87a77a3f2419a517d87" name="ajax.phtml" /></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file hash="58848d4d90973bfd63b466ea181352a5" name="Nexcessnet_Turpentine.xml" /></dir></target><target name="magecommunity"><dir name="Nexcessnet"><dir name="Turpentine"><dir name="controllers"><file hash="a815b132370cd9738e0139d8c04dc2a0" name="EsiController.php" /><dir name="Varnish"><file hash="30411372e1b8e2f7b7474bb7104eb38d" name="ManagementController.php" /></dir></dir><dir name="Helper"><file hash="2d7286c589b7a3e2f8fe873bd12afe3c" name="Debug.php" /><file hash="821797dc5da419ae46bc4cb0bf201b04" name="Varnish.php" /><file hash="6c70ee047ffb07d99a48fb2ebdc1723d" name="Esi.php" /><file hash="97c11b135bcb8789ed9e21596559659f" name="Data.php" /><file hash="9af5e8d9caa1d1b2182e105786ecce65" name="Cron.php" /><file hash="8f0dd23f9a7b98d8254acf18b6750f1e" name="Ban.php" /></dir><dir name="Model"><file hash="c2cb79001524617febbfddf099d09f37" name="Session.php" /><dir name="Observer"><file hash="9d57fad69ff42b71c66ca26bc3372317" name="Debug.php" /><file hash="7244a8ce600e980d612409595b9b6b9b" name="Varnish.php" /><file hash="a0ced6415261abf6d2221fdcf79bfa51" name="Esi.php" /><file hash="a34e79218e8ca1fefad303b9399bda9d" name="Cron.php" /><file hash="bb03f536d3dc2e9dc9efadcd36bda6e6" name="Ban.php" /></dir><dir name="Dummy"><file hash="df083cae5d3ad5774abaa5def3049348" name="Request.php" /></dir><dir name="Config"><dir name="Select"><file hash="9348c5e58037fd97d89b84ccab4ef2d0" name="Toggle.php" /><file hash="dc472f34c25b1688cfa9fa206958c536" name="Version.php" /></dir></dir><dir name="PageCache"><dir name="Container"><file hash="139e8a9bfa209316036e798fff654a8a" name="Notices.php" /></dir></dir><dir name="Varnish"><file hash="fcb8a5582c6f920e910b417c671df6d2" name="Admin.php" /><dir name="Configurator"><file hash="970a058bf2a73a5774b004390fcfaa07" name="Version3.php" /><file hash="4fba0ac0b4837cabec5bbee428d229df" name="Version2.php" /><file hash="627e6251d7bb64afe83f48ee256c16c9" name="Abstract.php" /></dir><dir name="Admin"><file hash="f3d6924ebb2d87ae1feb9717e3aee27e" name="Socket.php" /></dir></dir><dir name="Shim"><dir name="Mage"><dir name="Core"><file hash="821bff6c2fb372e3ffb39abf6453b3f8" name="Layout.php" /><file hash="94d91f8ff1005ce3bf14c4935945563c" name="App.php" /><file hash="43754654bc3bbd046154573efd735dfa" name="Config.php" /></dir></dir></dir></dir><dir name="etc"><file hash="fbcd96b3ecb2aa1986de82ce8c63d9c0" name="config.xml" /><file hash="e9d86f2aa678c844107ca209d012d7fb" name="system.xml" /><file hash="3b608fbcca3d307833d10604dff23966" name="cache.xml" /></dir><dir name="misc"><file hash="f083d5fbf4634af60ed5bb257197834f" name="uuid.c" /><file hash="181bb1fcaa152953b1377d9ef463c038" name="version-2.vcl" /><file hash="c18396094ee7e640ca9de47f37d8b7ed" name="version-3.vcl" /></dir><dir name="Block"><file hash="e9b03d651a8da9b1d32c4fd2f4781792" name="Management.php" /><file hash="390cf75d04b1b098cad562229b649c2d" name="Notices.php" /><dir name="Core"><file hash="44a880185b08b2d6d74ca94591c9ddca" name="Messages.php" /></dir><dir name="Catalog"><dir name="Product"><dir name="List"><file hash="a3cc4b92cb6a4956e28da798eb9e17df" name="Toolbar.php" /></dir></dir></dir></dir><dir name="sql" /></dir></dir></target></contents><dependencies><required><php><min>5.2.13</min><max>6.0.0</max></php></required></dependencies><authors><author><name>Chris Wells</name><user>nexcess_net</user><email>clwells@nexcess.net</email></author><author><name>Alex Headley</name><user>aheadley_nex</user><email>aheadley@nexcess.net</email></author></authors><date>2013-06-12</date><compatibile /><channel>community</channel><description>Turpentine is a Magento extension to improve Magento's compatibility with Varnish, a very-fast caching reverse-proxy. By default, Varnish doesn't cache requests with cookies and Magento sends the frontend cookie with every request causing a (near) zero hit-rate for Varnish's cache. Turpentine provides Varnish configuration files (VCLs) to work with Magento and modifies Magento's behaviour to significantly improve the cache hit rate.</description></package>