Nexcessnet_Turpentine - Version 0.6.0

Version Notes

Supports Magento v1.6 and later

Download this release

Release Info

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


Code changes from version 0.5.5 to 0.6.0

app/code/community/Nexcessnet/Turpentine/Block/Core/Messages.php CHANGED
@@ -353,7 +353,7 @@ class Nexcessnet_Turpentine_Block_Core_Messages extends Mage_Core_Block_Messages
353
  * @return boolean
354
  */
355
  protected function _isEsiRequest() {
356
- return is_subclass_of( Mage::app()->getRequest(),
357
  'Nexcessnet_Turpentine_Model_Dummy_Request' );
358
  }
359
  }
353
  * @return boolean
354
  */
355
  protected function _isEsiRequest() {
356
+ return is_a( Mage::app()->getRequest(),
357
  'Nexcessnet_Turpentine_Model_Dummy_Request' );
358
  }
359
  }
app/code/community/Nexcessnet/Turpentine/Helper/Cron.php CHANGED
@@ -162,7 +162,9 @@ class Nexcessnet_Turpentine_Helper_Cron extends Mage_Core_Helper_Abstract {
162
  $baseUrl = $store->getBaseUrl( Mage_Core_Model_Store::URL_TYPE_LINK );
163
  $urls[] = $baseUrl;
164
  foreach( Mage::getModel( 'catalog/category' )
165
- ->getCollection( $storeId ) as $cat ) {
 
 
166
  $urls[] = $cat->getUrl();
167
  foreach( $cat->getProductCollection( $storeId )
168
  ->addUrlRewrite( $cat->getId() )
162
  $baseUrl = $store->getBaseUrl( Mage_Core_Model_Store::URL_TYPE_LINK );
163
  $urls[] = $baseUrl;
164
  foreach( Mage::getModel( 'catalog/category' )
165
+ ->getCollection( $storeId )
166
+ ->addIsActiveFilter()
167
+ as $cat ) {
168
  $urls[] = $cat->getUrl();
169
  foreach( $cat->getProductCollection( $storeId )
170
  ->addUrlRewrite( $cat->getId() )
app/code/community/Nexcessnet/Turpentine/Helper/Esi.php CHANGED
@@ -119,6 +119,15 @@ class Nexcessnet_Turpentine_Helper_Esi extends Mage_Core_Helper_Abstract {
119
  return self::ESI_HMAC_PARAM;
120
  }
121
 
 
 
 
 
 
 
 
 
 
122
  /**
123
  * Get whether ESI debugging is enabled or not
124
  *
@@ -309,6 +318,48 @@ class Nexcessnet_Turpentine_Helper_Esi extends Mage_Core_Helper_Abstract {
309
  ) );
310
  }
311
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  /**
313
  * Load the ESI cache clear events from the layout
314
  *
119
  return self::ESI_HMAC_PARAM;
120
  }
121
 
122
+ /**
123
+ * Get referrer param
124
+ *
125
+ * @return string
126
+ */
127
+ public function getEsiReferrerParam() {
128
+ return Mage_Core_Controller_Varien_Action::PARAM_NAME_BASE64_URL;
129
+ }
130
+
131
  /**
132
  * Get whether ESI debugging is enabled or not
133
  *
318
  ) );
319
  }
320
 
321
+ /**
322
+ * Generate an ESI tag to be replaced by the content from the given URL
323
+ *
324
+ * Generated tag looks like:
325
+ * <esi:include src="$url" />
326
+ *
327
+ * @param string $url url to pull content from
328
+ * @return string
329
+ */
330
+ public function buildEsiIncludeFragment( $url ) {
331
+ return sprintf( '<esi:include src="%s" />', $url );
332
+ }
333
+
334
+ /**
335
+ * Generate an ESI tag with content that is removed when ESI processed, and
336
+ * visible when not
337
+ *
338
+ * Generated tag looks like:
339
+ * <esi:remove>$content</esi>
340
+ *
341
+ * @param string $content content to be removed
342
+ * @return string
343
+ */
344
+ public function buildEsiRemoveFragment( $content ) {
345
+ return sprintf( '<esi:remove>%s</esi>', $content );
346
+ }
347
+
348
+ /**
349
+ * Get URL for grabbing form key via ESI
350
+ *
351
+ * @return string
352
+ */
353
+ public function getFormKeyEsiUrl() {
354
+ $urlOptions = array(
355
+ $this->getEsiTtlParam() => $this->getDefaultEsiTtl(),
356
+ $this->getEsiMethodParam() => 'esi',
357
+ $this->getEsiScopeParam() => 'global',
358
+ $this->getEsiCacheTypeParam() => 'private',
359
+ );
360
+ return Mage::getUrl( 'turpentine/esi/getFormKey', $urlOptions );
361
+ }
362
+
363
  /**
364
  * Load the ESI cache clear events from the layout
365
  *
app/code/community/Nexcessnet/Turpentine/Helper/Varnish.php CHANGED
@@ -162,11 +162,10 @@ class Nexcessnet_Turpentine_Helper_Varnish extends Mage_Core_Helper_Abstract {
162
  * @return boolean
163
  */
164
  public function isBypassEnabled() {
165
- $bypassEnabled = (bool)Mage::getModel( 'core/cookie' )->get(
166
- Mage::helper( 'turpentine/data' )->getBypassCookieName() ) ===
167
- $this->getSecretHandshake();
168
 
169
- return $bypassEnabled;
170
  }
171
 
172
  /**
@@ -177,4 +176,44 @@ class Nexcessnet_Turpentine_Helper_Varnish extends Mage_Core_Helper_Abstract {
177
  public function shouldDisplayNotice() {
178
  return $this->getVarnishEnabled() && $this->isBypassEnabled();
179
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
162
  * @return boolean
163
  */
164
  public function isBypassEnabled() {
165
+ $cookieName = Mage::helper( 'turpentine/data' )->getBypassCookieName();
166
+ $cookieValue = Mage::getModel( 'core/cookie' )->get( $cookieName );
 
167
 
168
+ return $cookieValue === $this->getSecretHandshake();
169
  }
170
 
171
  /**
176
  public function shouldDisplayNotice() {
177
  return $this->getVarnishEnabled() && $this->isBypassEnabled();
178
  }
179
+
180
+ public function getFormKeyFixupActionsList() {
181
+ $data = Mage::getStoreConfig(
182
+ 'turpentine_varnish/miscellaneous/formkey_fixup_actions' );
183
+ $actions = array_filter( explode( PHP_EOL, trim( $data ) ) );
184
+ return $actions;
185
+ }
186
+
187
+ /**
188
+ * Check if this is a version of Magento that needs the form_key fix.
189
+ * Relevant versions are:
190
+ *
191
+ * CE 1.8+
192
+ * EE 1.13+
193
+ *
194
+ * @return bool
195
+ */
196
+ public function csrfFixupNeeded() {
197
+ $result = false;
198
+ $isEnterprise = false; // ce
199
+ if( method_exists( 'Mage', 'getEdition' ) ) {
200
+ if( Mage::getEdition() === Mage::EDITION_ENTERPRISE ) {
201
+ $isEnterprise = true;
202
+ }
203
+ } else {
204
+ if( Mage::getConfig()->getModuleConfig( 'Enterprise_Enterprise' ) ) {
205
+ $isEnterprise = true;
206
+ }
207
+ }
208
+ if( $isEnterprise ) {
209
+ if( version_compare( Mage::getVersion(), '1.13', '>=' ) ) {
210
+ $result = true;
211
+ }
212
+ } else {
213
+ if( version_compare( Mage::getVersion(), '1.8', '>=' ) ) {
214
+ $result = true;
215
+ }
216
+ }
217
+ return $result;
218
+ }
219
  }
app/code/community/Nexcessnet/Turpentine/Model/Observer/Esi.php CHANGED
@@ -141,6 +141,43 @@ class Nexcessnet_Turpentine_Model_Observer_Esi extends Varien_Event_Observer {
141
  }
142
  }
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  /**
145
  * Encode block data in URL then replace with ESI template
146
  *
@@ -180,6 +217,8 @@ class Nexcessnet_Turpentine_Model_Observer_Esi extends Varien_Event_Observer {
180
  $dataParam = $esiHelper->getEsiDataParam();
181
  $methodParam = $esiHelper->getEsiMethodParam();
182
  $hmacParam = $esiHelper->getEsiHmacParam();
 
 
183
 
184
  $esiOptions = $this->_getDefaultEsiOptions( $esiOptions );
185
 
@@ -211,6 +250,12 @@ class Nexcessnet_Turpentine_Model_Observer_Esi extends Varien_Event_Observer {
211
  $urlOptions['_secure'] = Mage::app()->getStore()
212
  ->isCurrentlySecure();
213
  }
 
 
 
 
 
 
214
  $esiUrl = Mage::getUrl( 'turpentine/esi/getBlock', $urlOptions );
215
  $blockObject->setEsiUrl( $esiUrl );
216
  // avoid caching the ESI template output to prevent the double-esi-
141
  }
142
  }
143
 
144
+ /**
145
+ * Check the magento version and runtime env and set the replace_form_key
146
+ * flag if needed
147
+ *
148
+ * @param Varien_Object $eventObject
149
+ * @return null
150
+ */
151
+ public function setReplaceFormKeyFlag( $eventObject ) {
152
+ $esiHelper = Mage::helper( 'turpentine/esi' );
153
+ $varnishHelper = Mage::helper( 'turpentine/varnish' );
154
+ $request = Mage::app()->getRequest();
155
+ if( $esiHelper->shouldResponseUseEsi() &&
156
+ $varnishHelper->csrfFixupNeeded() &&
157
+ !$request->isPost() ) {
158
+ Mage::register( 'replace_form_key', true );
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Replace the form key placeholder with the ESI include fragment
164
+ *
165
+ * @param Varien_Object $eventObject
166
+ * @return null
167
+ */
168
+ public function replaceFormKeyPlaceholder( $eventObject ) {
169
+ if( Mage::registry( 'replace_form_key' ) ) {
170
+ $esiHelper = Mage::helper( 'turpentine/esi' );
171
+ $response = $eventObject->getResponse();
172
+ $responseBody = $response->getBody();
173
+ $responseBody = str_replace( '{{form_key_esi_placeholder}}',
174
+ $esiHelper->buildEsiIncludeFragment(
175
+ $esiHelper->getFormKeyEsiUrl() ),
176
+ $responseBody );
177
+ $response->setBody( $responseBody );
178
+ }
179
+ }
180
+
181
  /**
182
  * Encode block data in URL then replace with ESI template
183
  *
217
  $dataParam = $esiHelper->getEsiDataParam();
218
  $methodParam = $esiHelper->getEsiMethodParam();
219
  $hmacParam = $esiHelper->getEsiHmacParam();
220
+ $scopeParam = $esiHelper->getEsiScopeParam();
221
+ $referrerParam = $esiHelper->getEsiReferrerParam();
222
 
223
  $esiOptions = $this->_getDefaultEsiOptions( $esiOptions );
224
 
250
  $urlOptions['_secure'] = Mage::app()->getStore()
251
  ->isCurrentlySecure();
252
  }
253
+ if( $esiOptions[$scopeParam] == 'page' ) {
254
+ $urlOptions[$referrerParam] = Mage::helper('core')->urlEncode(
255
+ Mage::getUrl('*/*/*', array('_use_rewrite' => true, '_current' => true))
256
+ );
257
+ }
258
+
259
  $esiUrl = Mage::getUrl( 'turpentine/esi/getBlock', $urlOptions );
260
  $blockObject->setEsiUrl( $esiUrl );
261
  // avoid caching the ESI template output to prevent the double-esi-
app/code/community/Nexcessnet/Turpentine/Model/Shim/Mage/Core/App.php CHANGED
@@ -63,6 +63,9 @@ class Nexcessnet_Turpentine_Model_Shim_Mage_Core_App extends Mage_Core_Model_App
63
  $this->_shim_getConfig()->extend( $eventConfig, true );
64
  // this wouldn't work if PHP had a sane object model
65
  $this->_shim_getApp()->_events[$area][$eventName] = null;
 
 
 
66
  return $this;
67
  }
68
 
63
  $this->_shim_getConfig()->extend( $eventConfig, true );
64
  // this wouldn't work if PHP had a sane object model
65
  $this->_shim_getApp()->_events[$area][$eventName] = null;
66
+ /* clear the event area cache because by the time this gets executed all <global> events have already been
67
+ cached in Magento EE 1.11 */
68
+ $this->_shim_getConfigShim()->unsetEventAreaCache($area);
69
  return $this;
70
  }
71
 
app/code/community/Nexcessnet/Turpentine/Model/Shim/Mage/Core/Config.php CHANGED
@@ -37,4 +37,17 @@ class Nexcessnet_Turpentine_Model_Shim_Mage_Core_Config extends Mage_Core_Model_
37
  $config->_classNameCache[$groupType][$group][$class] = $className;
38
  return $prevValue;
39
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  }
37
  $config->_classNameCache[$groupType][$group][$class] = $className;
38
  return $prevValue;
39
  }
40
+
41
+ /**
42
+ * Clears event area cache so that Turpentine can dynamically add new event
43
+ * observers even after the first event was fired.
44
+ *
45
+ * @param $area string The config area to clear (e.g. 'global')
46
+ */
47
+ public function unsetEventAreaCache($area) {
48
+ if(version_compare(Mage::getVersion(),'1.11.0', '>=') // enterprise
49
+ || version_compare(Mage::getVersion(), '1.6.0', '>=')) // community
50
+ unset($this->_eventAreas[$area]);
51
+ }
52
+
53
  }
app/code/community/Nexcessnet/Turpentine/Model/Varnish/Admin.php CHANGED
@@ -21,6 +21,9 @@
21
 
22
  class Nexcessnet_Turpentine_Model_Varnish_Admin {
23
 
 
 
 
24
  /**
25
  * Flush all Magento URLs in Varnish cache
26
  *
@@ -43,7 +46,9 @@ class Nexcessnet_Turpentine_Model_Varnish_Admin {
43
  foreach( Mage::helper( 'turpentine/varnish' )->getSockets() as $socket ) {
44
  $socketName = $socket->getConnectionString();
45
  try {
46
- $socket->ban_url( $subPattern );
 
 
47
  } catch( Mage_Core_Exception $e ) {
48
  $result[$socketName] = $e->getMessage();
49
  continue;
@@ -104,6 +109,7 @@ class Nexcessnet_Turpentine_Model_Varnish_Admin {
104
  $vclName = Mage::helper( 'turpentine/data' )
105
  ->secureHash( microtime() );
106
  try {
 
107
  $socket->vcl_inline( $vclName, $vcl );
108
  sleep( 1 ); //this is probably not really needed
109
  $socket->vcl_use( $vclName );
@@ -127,4 +133,35 @@ class Nexcessnet_Turpentine_Model_Varnish_Admin {
127
  $cfgr = Nexcessnet_Turpentine_Model_Varnish_Configurator_Abstract::getFromSocket( $sockets[0] );
128
  return $cfgr;
129
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
21
 
22
  class Nexcessnet_Turpentine_Model_Varnish_Admin {
23
 
24
+ const MASK_ESI_SYNTAX = 0x2;
25
+ const URL_ESI_SYNTAX_FIX = 'https://github.com/nexcess/magento-turpentine/wiki/FAQ#wiki-i-upgraded-to-turpentine-06-and-are-the-add-to-cart-buttons-look-broken';
26
+
27
  /**
28
  * Flush all Magento URLs in Varnish cache
29
  *
46
  foreach( Mage::helper( 'turpentine/varnish' )->getSockets() as $socket ) {
47
  $socketName = $socket->getConnectionString();
48
  try {
49
+ // We don't use "ban_url" here, because we want to do lurker friendly bans.
50
+ // Lurker friendly bans get cleaned up, so they don't slow down Varnish.
51
+ $socket->ban( 'obj.http.X-Varnish-URL', '~', $subPattern );
52
  } catch( Mage_Core_Exception $e ) {
53
  $result[$socketName] = $e->getMessage();
54
  continue;
109
  $vclName = Mage::helper( 'turpentine/data' )
110
  ->secureHash( microtime() );
111
  try {
112
+ $this->_testEsiSyntaxParam( $socket );
113
  $socket->vcl_inline( $vclName, $vcl );
114
  sleep( 1 ); //this is probably not really needed
115
  $socket->vcl_use( $vclName );
133
  $cfgr = Nexcessnet_Turpentine_Model_Varnish_Configurator_Abstract::getFromSocket( $sockets[0] );
134
  return $cfgr;
135
  }
136
+
137
+ protected function _testEsiSyntaxParam( $socket ) {
138
+ $session = Mage::getSingleton( 'adminhtml/session' );
139
+ $helper = Mage::helper( 'turpentine/varnish' );
140
+ $result = false;
141
+
142
+ if( $helper->csrfFixupNeeded() ) {
143
+ $value = $socket->param_show( 'esi_syntax' );
144
+ if( preg_match( '~(\d)\s+\[bitmap\]~', $value['text'], $match ) ) {
145
+ $value = hexdec( $match[1] );
146
+ if( $value & self::MASK_ESI_SYNTAX ) { //bitwise intentional
147
+ // setting is correct, all is fine
148
+ $result = true;
149
+ } else {
150
+ $session->addWarning( 'Varnish <em>esi_syntax</em> param is ' .
151
+ 'not set correctly, please see <a target="_blank" href="' .
152
+ self::URL_ESI_SYNTAX_FIX . '">these instructions</a> ' .
153
+ 'to fix this warning.' );
154
+ }
155
+ } else {
156
+ // error
157
+ Mage::helper( 'turpentine/debug' )->logWarning(
158
+ 'Failed to parse param.show output to check esi_syntax value' );
159
+ $result = true;
160
+ }
161
+ } else {
162
+ $result = true;
163
+ }
164
+
165
+ return $result;
166
+ }
167
  }
app/code/community/Nexcessnet/Turpentine/Model/Varnish/Admin/Socket.php CHANGED
@@ -57,6 +57,8 @@
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()
57
  * @method array vcl_show()
58
  * @method array param_show()
59
  * @method array param_set()
60
+ * Warning: ban_url does a non-lurker-friendly ban. This means it is not cleaned
61
+ * up from the ban list. A long ban list will slow down Varnish.
62
  * @method array ban_url()
63
  * @method array ban()
64
  * @method array ban_list()
app/code/community/Nexcessnet/Turpentine/Model/Varnish/Configurator/Abstract.php CHANGED
@@ -211,19 +211,23 @@ abstract class Nexcessnet_Turpentine_Model_Varnish_Configurator_Abstract {
211
  }
212
 
213
  /**
214
- * Get the path part of each store's base URL
215
  *
216
  * @return array
217
  */
218
  protected function _getBaseUrlPaths() {
219
  $paths = array();
220
- foreach( Mage::app()->getStores() as $storeId => $store ) {
221
- $paths[] = parse_url( $store->getBaseUrl(
222
- Mage_Core_Model_Store::URL_TYPE_LINK, false ),
223
- PHP_URL_PATH );
224
- $paths[] = parse_url( $store->getBaseUrl(
225
- Mage_Core_Model_Store::URL_TYPE_LINK, true ),
226
- PHP_URL_PATH );
 
 
 
 
227
  }
228
  $paths = array_unique( $paths );
229
  usort( $paths, create_function( '$a, $b',
211
  }
212
 
213
  /**
214
+ * Get the path part of each store's base URL and static file URLs
215
  *
216
  * @return array
217
  */
218
  protected function _getBaseUrlPaths() {
219
  $paths = array();
220
+ $linkTypes = array( Mage_Core_Model_Store::URL_TYPE_LINK,
221
+ Mage_Core_Model_Store::URL_TYPE_JS,
222
+ Mage_Core_Model_Store::URL_TYPE_SKIN,
223
+ Mage_Core_Model_Store::URL_TYPE_MEDIA );
224
+ foreach( Mage::app()->getStores() as $store ) {
225
+ foreach( $linkTypes as $linkType ) {
226
+ $paths[] = parse_url( $store->getBaseUrl( $linkType , false ),
227
+ PHP_URL_PATH );
228
+ $paths[] = parse_url( $store->getBaseUrl( $linkType , true ),
229
+ PHP_URL_PATH );
230
+ }
231
  }
232
  $paths = array_unique( $paths );
233
  usort( $paths, create_function( '$a, $b',
app/code/community/Nexcessnet/Turpentine/controllers/EsiController.php CHANGED
@@ -30,6 +30,26 @@ class Nexcessnet_Turpentine_EsiController extends Mage_Core_Controller_Front_Act
30
  $this->getResponse()->setRedirect( Mage::getBaseUrl() );
31
  }
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  /**
34
  * Spit out the rendered block from the URL-encoded data
35
  *
@@ -69,7 +89,8 @@ 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
- if( $referer = Mage::helper( 'core/http' )->getHttpReferer() ) {
 
73
  $dummyRequest = Mage::helper( 'turpentine/esi' )
74
  ->getDummyRequest( $referer );
75
  } else {
30
  $this->getResponse()->setRedirect( Mage::getBaseUrl() );
31
  }
32
 
33
+ /**
34
+ * Spit out the form key for this session
35
+ *
36
+ * @return null
37
+ */
38
+ public function getFormKeyAction() {
39
+ $resp = $this->getResponse();
40
+ $resp->setBody(
41
+ Mage::getSingleton( 'core/session' )->real_getFormKey() );
42
+ $resp->setHeader( 'X-Turpentine-Cache', '1' );
43
+ $resp->setHeader( 'X-Turpentine-Flush-Events',
44
+ implode( ',', Mage::helper( 'turpentine/esi' )
45
+ ->getDefaultCacheClearEvents() ) );
46
+ $resp->setHeader( 'X-Turpentine-Block', 'form_key' );
47
+ Mage::register( 'turpentine_nocache_flag', false, true );
48
+
49
+ Mage::helper( 'turpentine/debug' )->logDebug( 'Generated form_key: %s',
50
+ $resp->getBody() );
51
+ }
52
+
53
  /**
54
  * Spit out the rendered block from the URL-encoded data
55
  *
89
  Mage::app()->setCurrentStore(
90
  Mage::app()->getStore( $esiData->getStoreId() ) );
91
  $appShim = Mage::getModel( 'turpentine/shim_mage_core_app' );
92
+ if( $referer = $this->_getRefererUrl() ) {
93
+ $referer = htmlspecialchars_decode( $referer );
94
  $dummyRequest = Mage::helper( 'turpentine/esi' )
95
  ->getDummyRequest( $referer );
96
  } else {
app/code/community/Nexcessnet/Turpentine/etc/config.xml CHANGED
@@ -20,7 +20,7 @@
20
  <config>
21
  <modules>
22
  <Nexcessnet_Turpentine>
23
- <version>0.5.5</version>
24
  </Nexcessnet_Turpentine>
25
  </modules>
26
  <default>
@@ -195,6 +195,10 @@
195
  <class>turpentine/observer_esi</class>
196
  <method>setFlagHeaders</method>
197
  </turpentine_esi_http_response_send_before>
 
 
 
 
198
  </observers>
199
  </http_response_send_before>
200
  <controller_action_layout_generate_blocks_after>
@@ -237,6 +241,10 @@
237
  <class>turpentine/observer_varnish</class>
238
  <method>addProductListToolbarRewrite</method>
239
  </turpentine_varnish_controller_front_init_before>
 
 
 
 
240
  </observers>
241
  </controller_front_init_before>
242
 
20
  <config>
21
  <modules>
22
  <Nexcessnet_Turpentine>
23
+ <version>0.6.0</version>
24
  </Nexcessnet_Turpentine>
25
  </modules>
26
  <default>
195
  <class>turpentine/observer_esi</class>
196
  <method>setFlagHeaders</method>
197
  </turpentine_esi_http_response_send_before>
198
+ <turpentine_esi_replace_form_key_placeholder>
199
+ <class>turpentine/observer_esi</class>
200
+ <method>replaceFormKeyPlaceholder</method>
201
+ </turpentine_esi_replace_form_key_placeholder>
202
  </observers>
203
  </http_response_send_before>
204
  <controller_action_layout_generate_blocks_after>
241
  <class>turpentine/observer_varnish</class>
242
  <method>addProductListToolbarRewrite</method>
243
  </turpentine_varnish_controller_front_init_before>
244
+ <turpentine_esi_set_replace_form_key_flag>
245
+ <class>turpentine/observer_esi</class>
246
+ <method>setReplaceFormKeyFlag</method>
247
+ </turpentine_esi_set_replace_form_key_flag>
248
  </observers>
249
  </controller_front_init_before>
250
 
app/code/community/Nexcessnet/Turpentine/misc/version-2.vcl CHANGED
@@ -139,7 +139,7 @@ sub vcl_recv {
139
  req.http.Cookie, ".*\bstore=([^;]*).*", "\1");
140
  }
141
  # looks like an ESI request, add some extra vars for further processing
142
- if (req.url ~ "/turpentine/esi/getBlock/") {
143
  set req.http.X-Varnish-Esi-Method = regsub(
144
  req.url, ".*/{{esi_method_param}}/(\w+)/.*", "\1");
145
  set req.http.X-Varnish-Esi-Access = regsub(
@@ -258,6 +258,10 @@ sub vcl_fetch {
258
  # set the grace period
259
  set req.grace = {{grace_period}}s;
260
 
 
 
 
 
261
  # if it's part of magento...
262
  if (req.url ~ "{{url_base_regex}}") {
263
  # we handle the Vary stuff ourselves for now, we'll want to actually
@@ -365,6 +369,8 @@ sub vcl_deliver {
365
  remove resp.http.X-Turpentine-Flush-Events;
366
  remove resp.http.X-Turpentine-Block;
367
  remove resp.http.X-Varnish-Session;
 
 
368
  # this header indicates the session that originally generated a cached
369
  # page. it *must* not be sent to a client in production with lax
370
  # session validation or that session can be hijacked
139
  req.http.Cookie, ".*\bstore=([^;]*).*", "\1");
140
  }
141
  # looks like an ESI request, add some extra vars for further processing
142
+ if (req.url ~ "/turpentine/esi/get(?:Block|FormKey)/") {
143
  set req.http.X-Varnish-Esi-Method = regsub(
144
  req.url, ".*/{{esi_method_param}}/(\w+)/.*", "\1");
145
  set req.http.X-Varnish-Esi-Access = regsub(
258
  # set the grace period
259
  set req.grace = {{grace_period}}s;
260
 
261
+ # Store the URL in the response object, we need this to do lurker friendly bans later
262
+ set beresp.http.X-Varnish-Host = req.http.host;
263
+ set beresp.http.X-Varnish-URL = req.url;
264
+
265
  # if it's part of magento...
266
  if (req.url ~ "{{url_base_regex}}") {
267
  # we handle the Vary stuff ourselves for now, we'll want to actually
369
  remove resp.http.X-Turpentine-Flush-Events;
370
  remove resp.http.X-Turpentine-Block;
371
  remove resp.http.X-Varnish-Session;
372
+ remove resp.http.X-Varnish-Host;
373
+ remove resp.http.X-Varnish-URL;
374
  # this header indicates the session that originally generated a cached
375
  # page. it *must* not be sent to a client in production with lax
376
  # session validation or that session can be hijacked
app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl CHANGED
@@ -140,7 +140,7 @@ sub vcl_recv {
140
  req.http.Cookie, ".*\bstore=([^;]*).*", "\1");
141
  }
142
  # looks like an ESI request, add some extra vars for further processing
143
- if (req.url ~ "/turpentine/esi/getBlock/") {
144
  set req.http.X-Varnish-Esi-Method = regsub(
145
  req.url, ".*/{{esi_method_param}}/(\w+)/.*", "\1");
146
  set req.http.X-Varnish-Esi-Access = regsub(
@@ -256,6 +256,10 @@ sub vcl_fetch {
256
  # set the grace period
257
  set req.grace = {{grace_period}}s;
258
 
 
 
 
 
259
  # if it's part of magento...
260
  if (req.url ~ "{{url_base_regex}}") {
261
  # we handle the Vary stuff ourselves for now, we'll want to actually
@@ -363,6 +367,8 @@ sub vcl_deliver {
363
  unset resp.http.X-Turpentine-Flush-Events;
364
  unset resp.http.X-Turpentine-Block;
365
  unset resp.http.X-Varnish-Session;
 
 
366
  # this header indicates the session that originally generated a cached
367
  # page. it *must* not be sent to a client in production with lax
368
  # session validation or that session can be hijacked
140
  req.http.Cookie, ".*\bstore=([^;]*).*", "\1");
141
  }
142
  # looks like an ESI request, add some extra vars for further processing
143
+ if (req.url ~ "/turpentine/esi/get(?:Block|FormKey)/") {
144
  set req.http.X-Varnish-Esi-Method = regsub(
145
  req.url, ".*/{{esi_method_param}}/(\w+)/.*", "\1");
146
  set req.http.X-Varnish-Esi-Access = regsub(
256
  # set the grace period
257
  set req.grace = {{grace_period}}s;
258
 
259
+ # Store the URL in the response object, to be able to do lurker friendly bans later
260
+ set beresp.http.X-Varnish-Host = req.http.host;
261
+ set beresp.http.X-Varnish-URL = req.url;
262
+
263
  # if it's part of magento...
264
  if (req.url ~ "{{url_base_regex}}") {
265
  # we handle the Vary stuff ourselves for now, we'll want to actually
367
  unset resp.http.X-Turpentine-Flush-Events;
368
  unset resp.http.X-Turpentine-Block;
369
  unset resp.http.X-Varnish-Session;
370
+ unset resp.http.X-Varnish-Host;
371
+ unset resp.http.X-Varnish-URL;
372
  # this header indicates the session that originally generated a cached
373
  # page. it *must* not be sent to a client in production with lax
374
  # session validation or that session can be hijacked
app/code/local/Mage/Core/Model/Session.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-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 Mage
22
+ * @package Mage_Core
23
+ * @copyright Copyright (c) 2013 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ /**
29
+ * Core session model
30
+ *
31
+ * @todo extend from Mage_Core_Model_Session_Abstract
32
+ *
33
+ * @method null|bool getCookieShouldBeReceived()
34
+ * @method Mage_Core_Model_Session setCookieShouldBeReceived(bool $flag)
35
+ * @method Mage_Core_Model_Session unsCookieShouldBeReceived()
36
+ */
37
+ class Mage_Core_Model_Session extends Mage_Core_Model_Session_Abstract
38
+ {
39
+ public function __construct($data=array())
40
+ {
41
+ $name = isset($data['name']) ? $data['name'] : null;
42
+ $this->init('core', $name);
43
+ }
44
+
45
+ /**
46
+ * Retrieve Session Form Key
47
+ *
48
+ * @return string A 16 bit unique key for forms
49
+ */
50
+ public function getFormKey()
51
+ {
52
+ if (Mage::registry('replace_form_key') &&
53
+ !Mage::app()->getRequest()->getParam('form_key', false)) {
54
+ // flag request for ESI processing
55
+ Mage::register('turpentine_esi_flag', true, true);
56
+ return '{{form_key_esi_placeholder}}';
57
+ } else {
58
+ return $this->real_getFormKey();
59
+ }
60
+ }
61
+
62
+ public function real_getFormKey()
63
+ {
64
+ if (!$this->getData('_form_key')) {
65
+ $this->setData('_form_key', Mage::helper('core')->getRandomString(16));
66
+ }
67
+ return $this->getData('_form_key');
68
+ }
69
+ }
package.xml CHANGED
@@ -1,2 +1,2 @@
1
  <?xml version='1.0' encoding='utf-8'?>
2
- <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>13:53:44</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>95bf21d410e48b9315afff44449c6475f94d64bc</__commit_hash><version>0.5.5</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="8bd4e7e4540ed816721907cb0ac03a02" 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="252356c9ea115fca63e52d54f67d755f" 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="30386eecb1914f4acfebbbeb1d961dbf" name="EsiController.php" /><dir name="Varnish"><file hash="f5e29a50bef74178fe041024fb4e43a9" name="ManagementController.php" /></dir></dir><dir name="Helper"><file hash="2d7286c589b7a3e2f8fe873bd12afe3c" name="Debug.php" /><file hash="164856b06e87dff0694cde08da4bb4a6" name="Varnish.php" /><file hash="6c70ee047ffb07d99a48fb2ebdc1723d" name="Esi.php" /><file hash="9aaf4cb5cf56bebda267fb8514547dec" name="Data.php" /><file hash="9af5e8d9caa1d1b2182e105786ecce65" name="Cron.php" /><file hash="6b637be4eac4c924fc1f02b2d49699c3" 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="fab188479779fa36715de8219d200da0" name="Esi.php" /><file hash="a34e79218e8ca1fefad303b9399bda9d" name="Cron.php" /><file hash="704cf901bd456b51c263becd0f260d64" name="Ban.php" /></dir><dir name="Dummy"><file hash="2fc1189ace2d0e7383041d16a31df16b" 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="ac5bbfdb2bdb563f1cf79efebb16705e" 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="e544276572efd1f7e9c76c79b5b2a304" name="config.xml" /><file hash="e9d86f2aa678c844107ca209d012d7fb" name="system.xml" /><file hash="3b608fbcca3d307833d10604dff23966" name="cache.xml" /></dir><dir name="misc"><file hash="ba5d5c7263cd90eea3785953e3549041" name="uuid.c" /><file hash="b25a97a8b6d06e2a467bb3939bb66215" name="version-2.vcl" /><file hash="3663d91aa451b42fd3c91bcd6fefe8b5" 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-11-20</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
  <?xml version='1.0' encoding='utf-8'?>
2
+ <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>13:57:40</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>65678044352a4b5de14c6d14835a325dee1c721e</__commit_hash><version>0.6.0</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="8bd4e7e4540ed816721907cb0ac03a02" 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="252356c9ea115fca63e52d54f67d755f" 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="5afff04f7038b852512ae32776e37ec9" name="EsiController.php" /><dir name="Varnish"><file hash="f5e29a50bef74178fe041024fb4e43a9" name="ManagementController.php" /></dir></dir><dir name="Helper"><file hash="2d7286c589b7a3e2f8fe873bd12afe3c" name="Debug.php" /><file hash="802e269b0c80131efbb070309fdc610f" name="Varnish.php" /><file hash="a31045d661a62dac444f82e44ed4f139" name="Esi.php" /><file hash="9aaf4cb5cf56bebda267fb8514547dec" name="Data.php" /><file hash="f2bfb5f67fe0418b832a015ef5c4498b" name="Cron.php" /><file hash="6b637be4eac4c924fc1f02b2d49699c3" 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="f2fd1a9d421b5152dd88b8736ba9c58d" name="Esi.php" /><file hash="a34e79218e8ca1fefad303b9399bda9d" name="Cron.php" /><file hash="704cf901bd456b51c263becd0f260d64" name="Ban.php" /></dir><dir name="Dummy"><file hash="2fc1189ace2d0e7383041d16a31df16b" 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="288a4907e8b4792254260b3a5d135e84" name="Admin.php" /><dir name="Configurator"><file hash="970a058bf2a73a5774b004390fcfaa07" name="Version3.php" /><file hash="4fba0ac0b4837cabec5bbee428d229df" name="Version2.php" /><file hash="806c7ae421823eb6e44346386a66ef41" name="Abstract.php" /></dir><dir name="Admin"><file hash="c3d44d59ece358553d2cfa8f92964d39" name="Socket.php" /></dir></dir><dir name="Shim"><dir name="Mage"><dir name="Core"><file hash="821bff6c2fb372e3ffb39abf6453b3f8" name="Layout.php" /><file hash="4a1aa246373520936f0e4b5b3a3baf25" name="App.php" /><file hash="9e5d87f0aa84c9fb1541db83aba69abd" name="Config.php" /></dir></dir></dir></dir><dir name="etc"><file hash="5cdfa22cce53bad0dc5b1f367195cbcf" name="config.xml" /><file hash="e9d86f2aa678c844107ca209d012d7fb" name="system.xml" /><file hash="3b608fbcca3d307833d10604dff23966" name="cache.xml" /></dir><dir name="misc"><file hash="ba5d5c7263cd90eea3785953e3549041" name="uuid.c" /><file hash="8c28ccb5767d8a2e88706fa782309960" name="version-2.vcl" /><file hash="a38f46823e75d2dbfb087b0405a6bf35" 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="d77d2858b7058095f8729f4123789fcc" 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><target name="magelocal"><dir name="Mage"><dir name="Core"><dir name="Model"><file hash="4d51274ab710e722706ce78b32944fd4" name="Session.php" /></dir></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>2014-03-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>