├── VERSION ├── Guides ├── images │ ├── .DS_Store │ └── guides │ │ ├── force-tls │ │ ├── force-tls.png │ │ ├── secure-url.png │ │ ├── force-tls-modal.png │ │ └── force-tls-success.png │ │ ├── installation │ │ ├── golive.png │ │ ├── wizard.png │ │ ├── saveconfig.png │ │ ├── successvcl.png │ │ ├── vclupload.png │ │ ├── choosefastly.png │ │ ├── newfeatures.png │ │ ├── account-api-key.png │ │ ├── show-service-id.png │ │ └── testcredentials.png │ │ ├── backend-settings │ │ ├── edit-backend.png │ │ └── shielding-configuration.png │ │ └── error-maintenance-page │ │ ├── set-html.png │ │ ├── new-error-page.png │ │ ├── default-error-page.png │ │ └── error-maintenance-page.png ├── ERROR-MAINTENANCE-PAGE.md ├── FORCE-TLS.md ├── ESI.md ├── BACKEND-SETTINGS.md └── INSTALLATION.md ├── app ├── etc │ ├── modules │ │ ├── .DS_Store │ │ └── Fastly_CDN.xml │ └── fastlycdn.xml ├── locale │ ├── de_DE │ │ └── .DS_Store │ └── en_US │ │ └── .DS_Store ├── code │ └── community │ │ └── Fastly │ │ └── CDN │ │ ├── etc │ │ ├── vcl_snippets │ │ │ ├── miss.vcl │ │ │ ├── pass.vcl │ │ │ ├── error.vcl │ │ │ ├── deliver.vcl │ │ │ ├── fetch.vcl │ │ │ └── recv.vcl │ │ ├── vcl_snippets_image_optimizations │ │ │ └── recv.vcl │ │ ├── vcl_snippets_force_tls │ │ │ └── recv.vcl │ │ └── vcl_snippets_error_page │ │ │ └── deliver.vcl │ │ ├── .DS_Store │ │ ├── Block │ │ ├── Adminhtml │ │ │ ├── System │ │ │ │ └── Config │ │ │ │ │ ├── Dialogs.php │ │ │ │ │ └── Fieldset │ │ │ │ │ ├── Backend.php │ │ │ │ │ ├── IoConfigBtn.php │ │ │ │ │ ├── ErrorPageBtn.php │ │ │ │ │ ├── ToggleIoBtn.php │ │ │ │ │ ├── ToggleTlsBtn.php │ │ │ │ │ ├── UploadVclBtn.php │ │ │ │ │ ├── TestConnection.php │ │ │ │ │ ├── TestConnectionBtn.php │ │ │ │ │ ├── EsiTTL.php │ │ │ │ │ ├── RouteTTL.php │ │ │ │ │ ├── Versioninfo.php │ │ │ │ │ └── StoreMap.php │ │ │ └── Cache │ │ │ │ └── Additional.php │ │ ├── Esi │ │ │ ├── GeoIp │ │ │ │ ├── Action.php │ │ │ │ └── Getcountry.php │ │ │ └── Catalog │ │ │ │ └── Product.php │ │ ├── Html │ │ │ └── Header.php │ │ └── Cookie │ │ │ ├── Formkey.php │ │ │ └── Environment.php │ │ ├── Model │ │ ├── Resource │ │ │ └── Mysql4 │ │ │ │ ├── Statistic.php │ │ │ │ ├── Statistic │ │ │ │ └── Collection.php │ │ │ │ ├── Cms │ │ │ │ └── Page │ │ │ │ │ ├── Store.php │ │ │ │ │ └── Store │ │ │ │ │ └── Collection.php │ │ │ │ ├── Catalog │ │ │ │ ├── Category │ │ │ │ │ ├── Product.php │ │ │ │ │ └── Product │ │ │ │ │ │ └── Collection.php │ │ │ │ └── Product │ │ │ │ │ └── Relation │ │ │ │ │ └── Collection.php │ │ │ │ └── Core │ │ │ │ └── Url │ │ │ │ └── Rewrite │ │ │ │ └── Collection.php │ │ ├── Esi │ │ │ ├── Processor │ │ │ │ ├── Default.php │ │ │ │ ├── Reports │ │ │ │ │ └── Product │ │ │ │ │ │ ├── Compared.php │ │ │ │ │ │ └── Viewed.php │ │ │ │ ├── Page │ │ │ │ │ └── Template │ │ │ │ │ │ └── Welcome.php │ │ │ │ ├── Abstract.php │ │ │ │ └── GeoIp │ │ │ │ │ ├── Action.php │ │ │ │ │ └── Getcountry.php │ │ │ └── Tag │ │ │ │ ├── Checkout │ │ │ │ └── Sidebar │ │ │ │ │ └── Cart.php │ │ │ │ ├── Wishlist │ │ │ │ └── Customer │ │ │ │ │ └── Sidebar.php │ │ │ │ ├── Catalog │ │ │ │ └── Product │ │ │ │ │ └── Compare │ │ │ │ │ └── Sidebar.php │ │ │ │ ├── GeoIp │ │ │ │ ├── Action.php │ │ │ │ └── Getcountry.php │ │ │ │ ├── Page │ │ │ │ ├── Template │ │ │ │ │ ├── Links.php │ │ │ │ │ └── Welcome.php │ │ │ │ └── Html │ │ │ │ │ └── Notices.php │ │ │ │ ├── Reports │ │ │ │ └── Product │ │ │ │ │ ├── Viewed.php │ │ │ │ │ └── Compared.php │ │ │ │ └── Abstract.php │ │ ├── Cms │ │ │ └── Page │ │ │ │ └── Store.php │ │ ├── Catalog │ │ │ ├── Product │ │ │ │ └── Relation.php │ │ │ └── Category │ │ │ │ └── Product.php │ │ ├── Processor.php │ │ ├── Control │ │ │ ├── Cms │ │ │ │ └── Page.php │ │ │ ├── Catalog │ │ │ │ ├── Category.php │ │ │ │ └── Product.php │ │ │ └── Abstract.php │ │ ├── Tag.php │ │ ├── Hash │ │ │ └── Parameters.php │ │ └── Config.php │ │ ├── Helper │ │ ├── Template.php │ │ ├── Control │ │ │ ├── Cms │ │ │ │ └── Page.php │ │ │ └── Catalog │ │ │ │ ├── Product.php │ │ │ │ └── Category.php │ │ ├── Tags.php │ │ ├── Esi.php │ │ ├── Webhooks.php │ │ └── Environment.php │ │ ├── sql │ │ └── fastlycdn_setup │ │ │ ├── install-1.0.1.php │ │ │ ├── upgrade-1.0.0-1.0.1.php │ │ │ └── install-0.1.0.php │ │ ├── Controller │ │ └── Router.php │ │ └── controllers │ │ └── EsiController.php └── design │ ├── frontend │ └── base │ │ └── default │ │ ├── layout │ │ ├── .DS_Store │ │ └── fastlycdn.xml │ │ └── template │ │ ├── .DS_Store │ │ └── fastlycdn │ │ ├── geoip │ │ ├── redirect.phtml │ │ ├── cookie.phtml │ │ └── dialog.phtml │ │ ├── cookie │ │ ├── environment.phtml │ │ └── formkey.phtml │ │ ├── catalog │ │ └── product.phtml │ │ └── page │ │ └── notices_hook.phtml │ └── adminhtml │ └── default │ └── default │ ├── template │ └── fastlycdn │ │ ├── system │ │ └── config │ │ │ ├── upload_vcl_btn.phtml │ │ │ ├── error_page_btn.phtml │ │ │ ├── io_config_btn.phtml │ │ │ ├── backends.phtml │ │ │ ├── toggle_tls_btn.phtml │ │ │ ├── test_connection_btn.phtml │ │ │ └── toggle_io_btn.phtml │ │ └── cache │ │ └── additional.phtml │ └── layout │ └── fastlycdn.xml ├── composer.json ├── update_version.sh ├── modman ├── LICENSE.txt ├── Release-Notes.md └── skin └── adminhtml └── default └── default └── css └── fastlycdn └── fastly.css /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.32 2 | -------------------------------------------------------------------------------- /Guides/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/.DS_Store -------------------------------------------------------------------------------- /app/etc/modules/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/app/etc/modules/.DS_Store -------------------------------------------------------------------------------- /app/locale/de_DE/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/app/locale/de_DE/.DS_Store -------------------------------------------------------------------------------- /app/locale/en_US/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/app/locale/en_US/.DS_Store -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets/miss.vcl: -------------------------------------------------------------------------------- 1 | # Deactivate gzip on origin 2 | unset bereq.http.Accept-Encoding; 3 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets/pass.vcl: -------------------------------------------------------------------------------- 1 | # Deactivate gzip on origin 2 | unset bereq.http.Accept-Encoding; 3 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/app/code/community/Fastly/CDN/.DS_Store -------------------------------------------------------------------------------- /Guides/images/guides/force-tls/force-tls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/force-tls/force-tls.png -------------------------------------------------------------------------------- /Guides/images/guides/force-tls/secure-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/force-tls/secure-url.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/golive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/golive.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/wizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/wizard.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/saveconfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/saveconfig.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/successvcl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/successvcl.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/vclupload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/vclupload.png -------------------------------------------------------------------------------- /Guides/images/guides/force-tls/force-tls-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/force-tls/force-tls-modal.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/choosefastly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/choosefastly.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/newfeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/newfeatures.png -------------------------------------------------------------------------------- /app/design/frontend/base/default/layout/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/app/design/frontend/base/default/layout/.DS_Store -------------------------------------------------------------------------------- /Guides/images/guides/force-tls/force-tls-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/force-tls/force-tls-success.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/account-api-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/account-api-key.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/show-service-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/show-service-id.png -------------------------------------------------------------------------------- /Guides/images/guides/installation/testcredentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/installation/testcredentials.png -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/app/design/frontend/base/default/template/.DS_Store -------------------------------------------------------------------------------- /Guides/images/guides/backend-settings/edit-backend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/backend-settings/edit-backend.png -------------------------------------------------------------------------------- /Guides/images/guides/error-maintenance-page/set-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/error-maintenance-page/set-html.png -------------------------------------------------------------------------------- /Guides/images/guides/error-maintenance-page/new-error-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/error-maintenance-page/new-error-page.png -------------------------------------------------------------------------------- /Guides/images/guides/backend-settings/shielding-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/backend-settings/shielding-configuration.png -------------------------------------------------------------------------------- /Guides/images/guides/error-maintenance-page/default-error-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/error-maintenance-page/default-error-page.png -------------------------------------------------------------------------------- /Guides/images/guides/error-maintenance-page/error-maintenance-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastly/fastly-magento/HEAD/Guides/images/guides/error-maintenance-page/error-maintenance-page.png -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets_image_optimizations/recv.vcl: -------------------------------------------------------------------------------- 1 | if ( req.url.ext ~ "(?i)^(gif|png|jpg|jpeg|webp)$" ) { 2 | 3 | set req.http.X-Fastly-Imageopto-Api = "fastly"; 4 | 5 | } 6 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets_force_tls/recv.vcl: -------------------------------------------------------------------------------- 1 | # Force SSL immediately to avoid magento module VCL stripping off 2 | # google campaign ids like gclid 3 | if (!req.http.Fastly-SSL) { 4 | error 801 "Force SSL"; 5 | } 6 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets_error_page/deliver.vcl: -------------------------------------------------------------------------------- 1 | # If we are about to serve a 5xx we need to restart then in vcl_recv error out to 2 | # get the holding page 3 | if ( resp.status >= 500 && resp.status < 600 && !req.http.ResponseObject ) { 4 | set req.http.ResponseObject = "970"; 5 | restart; 6 | } 7 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Dialogs.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/dialogs.phtml'); 12 | } 13 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastly/cdn", 3 | "type": "magento-module", 4 | "license": "BSD-3-Clause", 5 | "description":"Fastly CDN module for Magento 1.x", 6 | "version": "1.0.32", 7 | "authors":[ 8 | { 9 | "name":"Fastly", 10 | "email":"support@fastly.com" 11 | } 12 | ], 13 | "require": { 14 | "magento-hackathon/magento-composer-installer": "*" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Statistic.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/statistics', 'stat_id'); 8 | } 9 | 10 | public function _beforeSave(Mage_Core_Model_Abstract $object) 11 | { 12 | $object->setCreatedAt(Varien_Date::now()); 13 | return parent::_beforeSave($object); // TODO: Change the autogenerated stub 14 | } 15 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Statistic/Collection.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/statistic'); 8 | } 9 | 10 | /** 11 | * @param $action 12 | * @return Varien_Object 13 | */ 14 | public function getStatByAction($action) 15 | { 16 | return $this->addFieldToFilter('action', $action)->setOrder('created_at', 'DESC')->getFirstItem(); 17 | } 18 | } -------------------------------------------------------------------------------- /update_version.sh: -------------------------------------------------------------------------------- 1 | # Run this script before new release to embed version tag in the right places so 2 | # we can debug easier 3 | VERSION=`cat VERSION` 4 | 5 | sed -i "s/resp.http.Fastly-Magento-VCL-Uploaded = \".*\"/resp.http.Fastly-Magento-VCL-Uploaded = \"$VERSION\"/g" ./app/code/community/Fastly/CDN/etc/vcl_snippets/*.vcl 6 | sed -i "s/\"version\": \".*\"/\"version\": \"$VERSION\"/g" composer.json 7 | sed -i "s/\"Fastly-Module-Enabled\", \".*\"/\"Fastly-Module-Enabled\", \"$VERSION\"/g" app/code/community/Fastly/CDN/Helper/Cache.php 8 | sed -i "s|.*|$VERSION|g" app/code/community/Fastly/CDN/etc/config.xml 9 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets/error.vcl: -------------------------------------------------------------------------------- 1 | # geo ip request 2 | if (obj.status == 750) { 3 | set req.url = regsub(req.url, "(/fastlycdn/esi/getcountry/.*)", "/fastlycdn/esi/getcountryaction/?country_code=") obj.response; 4 | return (restart); 5 | } 6 | 7 | # geo ip country code 8 | if (obj.status == 755) { 9 | set obj.status = 200; 10 | synthetic obj.response; 11 | return(deliver); 12 | } 13 | 14 | # formkey request 15 | if (obj.status == 760) { 16 | set obj.status = 200; 17 | synthetic obj.response; 18 | return (deliver); 19 | } 20 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/system/config/upload_vcl_btn.phtml: -------------------------------------------------------------------------------- 1 | getButtonHtml() ?> 2 | 3 | 12 | 13 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/Backend.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/backends.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/system/config/error_page_btn.phtml: -------------------------------------------------------------------------------- 1 | isEnabled()): ?> 2 | getButtonHtml() ?> 3 | 4 |

__('Please enable and configure the extension first. ') ?>

5 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/system/config/io_config_btn.phtml: -------------------------------------------------------------------------------- 1 | isEnabled()): ?> 2 | getButtonHtml() ?> 3 | 4 |

__('Please enable and configure the extension first. ') ?>

5 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Processor/Default.php: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 25 | 26 | true 27 | community 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Esi/GeoIp/Action.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/cms_page_store'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Catalog/Product/Relation.php: -------------------------------------------------------------------------------- 1 | _init('catalog/product_relation'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Catalog/Category/Product.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/catalog_category_product'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/Checkout/Sidebar/Cart.php: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 25 | 26 | 27 | Fastly_CDN_Model_Processor 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Processor/Page/Template/Welcome.php: -------------------------------------------------------------------------------- 1 | getLayout()->getBlock('header')->getOriginalWelcome(); 27 | return $output; 28 | } 29 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Cms/Page/Store.php: -------------------------------------------------------------------------------- 1 | _init('cms/page_store', 'store_id'); 30 | } 31 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets/deliver.vcl: -------------------------------------------------------------------------------- 1 | # Add an easy way to see whether custom Fastly VCL has been uploaded 2 | if ( req.http.Fastly-Debug ) { 3 | set resp.http.Fastly-Magento-VCL-Uploaded = "1.0.32"; 4 | } else { 5 | remove resp.http.Fastly-Module-Enabled; 6 | # remove Varnish/proxy header 7 | remove resp.http.X-Varnish; 8 | remove resp.http.Via; 9 | remove resp.http.X-Purge-URL; 10 | remove resp.http.X-Purge-Host; 11 | remove resp.http.Fastly-page-cacheable; 12 | } 13 | 14 | # Clean up Vary before handing off to the user 15 | if ( !req.http.Fastly-FF ) { 16 | set resp.http.Vary = regsub(resp.http.Vary, "Fastly-Cdn-Env,Https", "Cookie"); 17 | remove resp.http.surrogate-keys-set; 18 | } 19 | 20 | if (resp.http.x-esi && !req.http.Fastly-FF) { 21 | # Remove the ESI marker 22 | unset resp.http.x-esi; 23 | 24 | # Tell browsers not to cache the content 25 | set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"; 26 | } 27 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Catalog/Category/Product.php: -------------------------------------------------------------------------------- 1 | _init('catalog/category_product', 'category_id'); 30 | } 31 | } -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/geoip/redirect.phtml: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | README.md app/code/community/Fastly/CDN/README.md 2 | LICENSE.txt app/code/community/Fastly/CDN/LICENSE.txt 3 | composer.json app/code/community/Fastly/CDN/composer.json 4 | modman app/code/community/Fastly/CDN/modman 5 | app/code/community/Fastly/CDN/* app/code/community/Fastly/CDN/ 6 | app/design/adminhtml/default/default/layout/fastlycdn.xml app/design/adminhtml/default/default/layout/fastlycdn.xml 7 | app/design/adminhtml/default/default/template/fastlycdn/* app/design/adminhtml/default/default/template/fastlycdn/ 8 | app/design/frontend/base/default/layout/fastlycdn.xml app/design/frontend/base/default/layout/fastlycdn.xml 9 | app/design/frontend/base/default/template/fastlycdn/* app/design/frontend/base/default/template/fastlycdn/ 10 | app/etc/fastlycdn.xml app/etc/fastlycdn.xml 11 | app/etc/modules/Fastly_CDN.xml app/etc/modules/Fastly_CDN.xml 12 | app/locale/de_DE/Fastly_CDN.csv app/locale/de_DE/Fastly_CDN.csv 13 | app/locale/en_US/Fastly_CDN.csv app/locale/en_US/Fastly_CDN.csv 14 | skin/adminhtml/default/default/css/fastlycdn/fastly.css skin/adminhtml/default/default/css/fastlycdn/fastly.css 15 | skin/adminhtml/default/default/js/fastlycdn/fastly.js skin/adminhtml/default/default/js/fastlycdn/fastly.js 16 | 17 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/GeoIp/Action.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/io_config_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Generate button html 27 | * 28 | * @return string 29 | */ 30 | public function getButtonHtml() 31 | { 32 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 33 | ->setData(array( 34 | 'id' => "io_config_btn", 35 | 'label' => $this->helper('adminhtml')->__('Configure'), 36 | 'onclick' => "Fastly.initDialog('io-config-form'); return false;" 37 | )); 38 | 39 | return $button->toHtml(); 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/Page/Template/Links.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/error_page_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Generate button html 27 | * 28 | * @return string 29 | */ 30 | public function getButtonHtml() 31 | { 32 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 33 | ->setData(array( 34 | 'id' => "fastly_error_page_btn", 35 | 'label' => $this->helper('adminhtml')->__('Set HTML'), 36 | 'onclick' => "Fastly.initDialog('error-page-form'); return false;" 37 | )); 38 | 39 | return $button->toHtml(); 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/ToggleIoBtn.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/toggle_io_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Generate button html 27 | * 28 | * @return string 29 | */ 30 | public function getButtonHtml() 31 | { 32 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 33 | ->setData(array( 34 | 'id' => "fastly_toggle_io_btn", 35 | 'label' => $this->helper('adminhtml')->__('Enable/Disable'), 36 | 'onclick' => "Fastly.initDialog('toggle-io-form'); return false;" 37 | )); 38 | 39 | return $button->toHtml(); 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/ToggleTlsBtn.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/toggle_tls_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Generate button html 27 | * 28 | * @return string 29 | */ 30 | public function getButtonHtml() 31 | { 32 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 33 | ->setData(array( 34 | 'id' => "fastly_toggle_tls_btn", 35 | 'label' => $this->helper('adminhtml')->__('Force TLS'), 36 | 'onclick' => "Fastly.initDialog('toggle-tls-form'); return false;" 37 | )); 38 | 39 | return $button->toHtml(); 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/Page/Html/Notices.php: -------------------------------------------------------------------------------- 1 | getSelect() 32 | ->where('id_path = ?', "category/{$categoryId}"); 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/UploadVclBtn.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/upload_vcl_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Generate button html 27 | * 28 | * @return string 29 | */ 30 | public function getButtonHtml() 31 | { 32 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 33 | ->setData(array( 34 | 'id' => "fastly_upload_vcl_btn", 35 | 'label' => $this->helper('adminhtml')->__('Upload VCL to Fastly'), 36 | 'onclick' => "Fastly.initDialog('vcl-upload-form'); return false;" 37 | )); 38 | 39 | return $button->toHtml(); 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Template.php: -------------------------------------------------------------------------------- 1 | getNode('admin/routers/adminhtml/args/frontName')->asArray(); 17 | if(!$adminPath || !is_string($adminPath)) { 18 | $adminPath = 'admin'; 19 | } 20 | 21 | // Ignore Query params 22 | $queryParams = Mage::getStoreConfig(self::FASTLY_CDN_TEMPLATE_QUERY_PARAMS); 23 | $queryParams = explode(',', $queryParams); 24 | $queryParams = array_filter(array_map('trim', $queryParams)); 25 | $queryParams = implode('|', $queryParams); 26 | 27 | $replaceValues = array( 28 | '####ADMIN_PATH####' => $adminPath, 29 | '####QUERY_PARAMETERS####' => $queryParams//'utm_.*|gclid|gdftrk|_ga|mc_.*' 30 | ); 31 | 32 | foreach($replaceValues as $search => $replace) { 33 | $value = str_replace($search, $replace, $value); 34 | } 35 | 36 | return $value; 37 | } 38 | } -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/cookie/environment.phtml: -------------------------------------------------------------------------------- 1 | 22 | 29 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/cookie/formkey.phtml: -------------------------------------------------------------------------------- 1 | 22 | 29 | getCookieName(); 31 | $_formKeyValue = $this->getFormKeyValue(); 32 | ?> 33 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Cms/Page/Store/Collection.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/cms_page_store'); 30 | } 31 | 32 | /** 33 | * Add cms page id filter 34 | * 35 | * @param int $id 36 | * @return Fastly_CDN_Model_Resource_Mysql4_Cms_Page_Store_Collection 37 | */ 38 | public function addPageFilter($id) 39 | { 40 | $this->getSelect() 41 | ->where('page_id = ?', $id); 42 | return $this; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Processor.php: -------------------------------------------------------------------------------- 1 | 32 | * Mage_Core_Model_Cache::processRequest(). 33 | * 34 | * @param string $content 35 | * @return string | false 36 | */ 37 | public function extractContent($content) 38 | { 39 | return $content; 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Control/Cms/Page.php: -------------------------------------------------------------------------------- 1 | isEnabled() && $this->isPurge(); 34 | } 35 | 36 | /** 37 | * Returns true if category should be purged on save 38 | * 39 | * @return boolean 40 | */ 41 | public function isPurge() 42 | { 43 | return Mage::getStoreConfigFlag(self::XML_PATH_FASTLY_CDN_CACHE_PURGE); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Control/Catalog/Product.php: -------------------------------------------------------------------------------- 1 | isEnabled() && $this->isPurge(); 34 | } 35 | 36 | /** 37 | * Returns true if CMS page should be purged on save 38 | * 39 | * @return boolean 40 | */ 41 | public function isPurge() 42 | { 43 | return Mage::getStoreConfigFlag(self::XML_PATH_FASTLY_CDN_CACHE_PURGE); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Control/Catalog/Category.php: -------------------------------------------------------------------------------- 1 | isEnabled() && $this->isPurge(); 34 | } 35 | 36 | /** 37 | * Returns true if category should be purged on save 38 | * 39 | * @return boolean 40 | */ 41 | public function isPurge() 42 | { 43 | return Mage::getStoreConfigFlag(self::XML_PATH_FASTLY_CDN_CACHE_PURGE); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Fastly, Inc. (http://www.fastly.com) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Guides/ERROR-MAINTENANCE-PAGE.md: -------------------------------------------------------------------------------- 1 | # Set Error / Maintenance page guide 2 | 3 | The Fastly CDN will sometimes return a 503 error due to various issues that can occur. The generic text associated with a 503 error is “Service Unavailable” and it can mean variety of things. This default error response can be confusing to the customers and have a basic look and feel. 4 | 5 | This guide will show you how to set friendly or prettier 503 custom error page through Fastly module which will be served when: 6 | * When origin returns a response status greater than 500 7 | * When origin is down (i.e unhealthy, timeout, etc) 8 | 9 | To set custom Error page, go to: 10 | 11 | ``` 12 | Magento admin > System > Configuration > Services > Fastly CDN 13 | ``` 14 | 15 | Under the Fastly Configuration, click on the **Error/Maintenance page:** 16 | 17 | ![Error Maintenance page](images/guides/error-maintenance-page/error-maintenance-page.png "Error/Maintenance page") 18 | 19 | The modal window will pop up. Paste your custom HTML code into the HTML textarea and press the Upload button to save changes. 20 | 21 | ![Set HTML](images/guides/error-maintenance-page/set-html.png "Set HTML") 22 | 23 | Now when Fastly returns 503 error, instead of default error page which looks something like this: 24 | 25 | ![Default error page](images/guides/error-maintenance-page/default-error-page.png "Default error page") 26 | 27 | You will serve your custom error page: 28 | 29 | ![New error page](images/guides/error-maintenance-page/new-error-page.png "New error page") 30 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/TestConnection.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/test_connection_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Return ajax url for button 27 | * 28 | * @return string 29 | */ 30 | public function getAjaxCheckUrl() 31 | { 32 | return Mage::helper('adminhtml')->getUrl('*/fastlyCdn/testConnection'); 33 | } 34 | 35 | /** 36 | * Generate button html 37 | * 38 | * @return string 39 | */ 40 | public function getButtonHtml() 41 | { 42 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 43 | ->setData(array( 44 | 'id' => 'fastly_test_conn_btn', 45 | 'label' => $this->helper('adminhtml')->__('Test connection'), 46 | 'onclick' => 'javascript:check(); return false;' 47 | )); 48 | 49 | return $button->toHtml(); 50 | } 51 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/TestConnectionBtn.php: -------------------------------------------------------------------------------- 1 | setTemplate('fastlycdn/system/config/test_connection_btn.phtml'); 12 | } 13 | 14 | /** 15 | * Return element html 16 | * 17 | * @param Varien_Data_Form_Element_Abstract $element 18 | * @return string 19 | */ 20 | protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 21 | { 22 | return $this->_toHtml(); 23 | } 24 | 25 | /** 26 | * Return ajax url for button 27 | * 28 | * @return string 29 | */ 30 | public function getAjaxCheckUrl() 31 | { 32 | return Mage::helper('adminhtml')->getUrl('*/fastlyCdn/testConnection'); 33 | } 34 | 35 | /** 36 | * Generate button html 37 | * 38 | * @return string 39 | */ 40 | public function getButtonHtml() 41 | { 42 | $button = $this->getLayout()->createBlock('adminhtml/widget_button') 43 | ->setData(array( 44 | 'id' => 'fastly_test_conn_btn', 45 | 'label' => $this->helper('adminhtml')->__('Test connection'), 46 | 'onclick' => 'javascript:check(); return false;' 47 | )); 48 | 49 | return $button->toHtml(); 50 | } 51 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Catalog/Product/Relation/Collection.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/catalog_product_relation', 'catalog/product_relation'); 31 | } 32 | 33 | /** 34 | * Filters collection by child product id 35 | * 36 | * @param int $childId 37 | * @return Fastly_CDN_Model_Resource_Mysql4_Catalog_Product_Relation_Collection 38 | */ 39 | public function filterByChildId($childId) 40 | { 41 | $this->getSelect() 42 | ->where('child_id=?', $childId); 43 | return $this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Processor/Reports/Product/Viewed.php: -------------------------------------------------------------------------------- 1 | _getHelper()->getEsiParam(); 29 | if (empty($listData) === false) { 30 | $productIds = $listData->list; 31 | 32 | // filter current product ID from list 33 | if ($productId = $this->getProductId()) { 34 | $key = array_search($productId, $productIds); 35 | unset($productIds[$key]); 36 | } 37 | $block->setProductIds($productIds); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Resource/Mysql4/Catalog/Category/Product/Collection.php: -------------------------------------------------------------------------------- 1 | _init('fastlycdn/catalog_category_product'); 31 | } 32 | 33 | /** 34 | * Filter collection by product ids 35 | * 36 | * @param array $productIds 37 | * @return Fastly_CDN_Model_Resource_Mysql4_Catalog_Category_Product_Collection 38 | */ 39 | public function filterAllByProductIds(array $productIds) 40 | { 41 | $this->getSelect() 42 | ->where('product_id in (?)', $productIds) 43 | ->group('category_id'); 44 | return $this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Control/Cms/Page.php: -------------------------------------------------------------------------------- 1 | _canPurge()) { 35 | $surrogateKey = Fastly_CDN_Helper_Tags::SURROGATE_KEY_CMSPAGE_PREFIX . $page->getId(); 36 | $this->_getCacheControl()->cleanBySurrogateKey($surrogateKey); 37 | 38 | $this->_getSession()->addSuccess( 39 | Mage::helper('fastlycdn')->__('Fastly CDN for cms page "%s" has been purged.', $page->getTitle()) 40 | ); 41 | } 42 | 43 | return $this; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/system/config/backends.phtml: -------------------------------------------------------------------------------- 1 |
2 | isEnabled()): ?> 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
Name

__('Loading...'); ?>

17 |
18 | 27 | 28 | 37 | 38 |

__('Please enable and configure the extension first. ') ?>

39 | 40 |
-------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/system/config/toggle_tls_btn.phtml: -------------------------------------------------------------------------------- 1 | getButtonHtml() ?> 2 | 3 | 4 | Current state: 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 31 | 32 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/EsiTTL.php: -------------------------------------------------------------------------------- 1 | addColumn( 28 | 'regexp', array( 29 | 'label' => Mage::helper('adminhtml')->__('Block'), 30 | 'style' => 'width:180px') 31 | ); 32 | $this->addColumn( 33 | 'value', array( 34 | 'label' => Mage::helper('adminhtml')->__('TTL'), 35 | 'style' => 'width:60px') 36 | ); 37 | $this->_addAfter = false; 38 | $this->_addButtonLabel = Mage::helper('adminhtml')->__('Add block'); 39 | parent::__construct(); 40 | } 41 | 42 | protected function _toHtml() 43 | { 44 | return '
' . parent::_toHtml() . '
'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/RouteTTL.php: -------------------------------------------------------------------------------- 1 | addColumn( 28 | 'regexp', array( 29 | 'label' => Mage::helper('adminhtml')->__('Route'), 30 | 'style' => 'width:120px') 31 | ); 32 | $this->addColumn( 33 | 'value', array( 34 | 'label' => Mage::helper('adminhtml')->__('TTL'), 35 | 'style' => 'width:120px') 36 | ); 37 | $this->_addAfter = false; 38 | $this->_addButtonLabel = Mage::helper('adminhtml')->__('Add route'); 39 | parent::__construct(); 40 | } 41 | 42 | protected function _toHtml() 43 | { 44 | return '
' . parent::_toHtml() . '
'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/catalog/product.phtml: -------------------------------------------------------------------------------- 1 | 22 | 29 | getProductId()): ?> 30 | getCookieName(); ?> 31 | 48 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/Reports/Product/Viewed.php: -------------------------------------------------------------------------------- 1 | _getHelper()->isStrictRenderingEnabled()) { 36 | if (($product = Mage::registry('current_product')) && ($product instanceof Mage_Catalog_Model_Product)) { 37 | return array('product_id' => $product->getId()); 38 | } 39 | } 40 | return parent::_getAdditionalQueryParams(); 41 | } 42 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/Reports/Product/Compared.php: -------------------------------------------------------------------------------- 1 | _getHelper()->isStrictRenderingEnabled()) { 36 | if (($product = Mage::registry('current_product')) && ($product instanceof Mage_Catalog_Model_Product)) { 37 | return array('product_id' => $product->getId()); 38 | } 39 | } 40 | return parent::_getAdditionalQueryParams(); 41 | } 42 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Html/Header.php: -------------------------------------------------------------------------------- 1 | canUseEsi()) { 38 | $esiTagModel = Mage::getModel( 39 | 'fastlycdn/esi_tag_page_template_welcome', 40 | array(Mage::helper('fastlycdn')->getLayoutNameParam() => 'page/template_welcome') 41 | ); 42 | 43 | $esiTag = $esiTagModel->getEsiIncludeTag($this); 44 | 45 | return $esiTag; 46 | } 47 | 48 | // no esi - use default behaviour 49 | return $this->getOriginalWelcome(); 50 | } 51 | 52 | 53 | public function getOriginalWelcome() 54 | { 55 | return parent::getWelcome(); 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Esi/Catalog/Product.php: -------------------------------------------------------------------------------- 1 | getId(); 33 | } 34 | return false; 35 | } 36 | 37 | /** 38 | * Get maximum count of products allowed in the list 39 | * @return int 40 | */ 41 | public function getLimit() 42 | { 43 | return Mage::getStoreConfig(Mage_Reports_Block_Product_Viewed::XML_PATH_RECENTLY_VIEWED_COUNT); 44 | } 45 | 46 | /** 47 | * Get cookie name for viewed product ID list 48 | * @return string 49 | */ 50 | public function getCookieName() 51 | { 52 | return Mage::helper('fastlycdn')->generateCookieName( 53 | Fastly_CDN_Model_Esi_Tag_Reports_Product_Viewed::COOKIE_NAME 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/system/config/test_connection_btn.phtml: -------------------------------------------------------------------------------- 1 | 28 | 29 | getButtonHtml() ?> 30 | 31 | 41 | 42 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Tag.php: -------------------------------------------------------------------------------- 1 | ' . 35 | Mage::helper('fastlycdn')->__( 36 | 'Fastly CDN version: %s', 37 | Mage::getConfig()->getNode('modules/Fastly_CDN/version') 38 | ) . '
' . 39 | Mage::helper('fastlycdn')->__( 40 | 'To contact Fastly support please click here.', 41 | 'mailto:support@fastly.com?subject=[Magento%20Module%20Support]' . 42 | '&body=Installed%20Version%20' .Mage::getConfig()->getNode('modules/Fastly_CDN/version') 43 | ) . 44 | ''; 45 | 46 | return $info; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/layout/fastlycdn.xml: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 25 | 26 | 27 | 28 | skin_js 29 | js/fastlycdn/fastly.js 30 | 31 | 32 | skin_css 33 | css/fastlycdn/fastly.css 34 | 35 | 36 | lib/prototype/windows/themes/magento.css 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Guides/FORCE-TLS.md: -------------------------------------------------------------------------------- 1 | # Force TLS guide 2 | 3 | This guide will show how to setup Secure base URL in Magento and turn on Force TLS option. 4 | For this, you will need to have a TLS certificate. You can read [here](https://docs.fastly.com/guides/securing-communications/) on how to order a TLS certificate through Fastly and then set it up. 5 | 6 | Once you're ready, go to: 7 | 8 | ``` 9 | Magento admin > System > Configuration > General > Web 10 | ``` 11 | 12 | Click on the **Secure** tab and enter your **Secure Base URL**. Also, set **Use Secure URLs in Frontend** and **Use Secure URLs in Admin** options to **Yes**. 13 | 14 | ![Secure URL](images/guides/force-tls/secure-url.png "Secure URL") 15 | 16 | Once you're done, press the Save config button in the upper right corner. 17 | 18 | ### Allowing only TLS connections to your site 19 | 20 | If you want to only allow TLS on your site, we have you covered. 21 | There is an option built into the Fastly module that will allow you to force unencrypted requests over to TLS. It works by returning a 301 Moved Permanently response to any unencrypted request, which redirects to the TLS equivalent. For instance, making a request for http://www.example.com/foo.jpeg would redirect to https://www.example.com/foo.jpeg. 22 | 23 | To enable Force TLS option, go to: 24 | 25 | ``` 26 | Magento admin > System > Configuration > Services > Fastly CDN 27 | ``` 28 | 29 | Under the **General Settings** tab, press the Force TLS button. 30 | 31 | ![Force TLS button](images/guides/force-tls/force-tls.png "Force TLS button") 32 | 33 | The modal window with the following content will pop up, press the **Upload** button in the upper right corner: 34 | 35 | ![Force TLS modal](images/guides/force-tls/force-tls-modal.png "Force TLS modal") 36 | 37 | Once done, the modal windows will close and you will see a success message. Also, the current state will change to **enabled**. 38 | 39 | ![Force TLS success](images/guides/force-tls/force-tls-success.png "Success") 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Tags.php: -------------------------------------------------------------------------------- 1 | getButtonHtml() ?> 2 | 3 | 4 | Current state: 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 31 | 32 | 41 | 42 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Cookie/Formkey.php: -------------------------------------------------------------------------------- 1 | addData(array( 28 | 'cache_lifetime' => null 29 | )); 30 | } 31 | 32 | 33 | /** 34 | * Return environment cookie name 35 | * 36 | * @return string 37 | */ 38 | public function getCookieName() 39 | { 40 | return Fastly_CDN_Helper_Esi::FORMKEY_COOKIE; 41 | } 42 | 43 | /** 44 | * Return the form key esi tag 45 | * 46 | * @return string 47 | */ 48 | public function getFormKeyValue() 49 | { 50 | // try to use form key from session 51 | $session = Mage::getSingleton('core/session'); 52 | $formKey = $session->getData('_form_key'); 53 | 54 | // or create new one via esi 55 | if (empty($formKey)) { 56 | $formKey = Mage::helper('fastlycdn/esi')->getFormKeyEsiTag(); 57 | } 58 | 59 | return $formKey; 60 | } 61 | 62 | /** 63 | * Return the cookie lifetime 64 | * 65 | * @return int 66 | */ 67 | public function getCookieLifetime() 68 | { 69 | return Mage::getModel('core/cookie')->getLifetime() * 1000; 70 | } 71 | } -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/geoip/cookie.phtml: -------------------------------------------------------------------------------- 1 | 22 | 30 | 34 | isGeoIpEnabled()): ?> 35 | getGeoIpCookieName(); ?> 36 | 49 | 50 | getChildHtml('fastlycdn.geoip_getcountry'); ?> 51 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/sql/fastlycdn_setup/install-1.0.1.php: -------------------------------------------------------------------------------- 1 | getConnection(); 9 | 10 | $installer->startSetup(); 11 | 12 | /** 13 | * Create table 'fastly_statistics' 14 | */ 15 | 16 | $table = $connection->newTable($installer->getTable('fastlycdn/statistics') 17 | )->addColumn( 18 | 'stat_id', 19 | Varien_Db_Ddl_Table::TYPE_INTEGER, 20 | null, 21 | ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 22 | 'Stat id' 23 | )->addColumn( 24 | 'action', 25 | Varien_Db_Ddl_Table::TYPE_TEXT, 26 | 30, 27 | ['nullable' => false], 28 | 'Fastly action' 29 | )->addColumn( 30 | 'sent', 31 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 32 | null, 33 | ['nullable' => false, 'default' => 0], 34 | '1 = Curl req. sent | 0 = Curl req. not sent' 35 | )->addColumn( 36 | 'state', 37 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 38 | null, 39 | ['nullable' => false, 'default' => 0], 40 | '1 = configured | 0 = not_configured' 41 | )->addColumn( 42 | 'created_at', 43 | Varien_Db_Ddl_Table::TYPE_DATETIME, 44 | null, 45 | [], 46 | 'Action date' 47 | ); 48 | $connection->createTable($table); 49 | 50 | /** 51 | * Insert Installed action into the statistic table 52 | */ 53 | 54 | $tableName = $installer->getTable('fastly_statistics'); 55 | 56 | if($connection->isTableExists($tableName) == true) { 57 | 58 | $statistic = Mage::getModel('fastlycdn/statistic'); 59 | $cid = $statistic->generateCid(); 60 | Mage::getConfig()->saveConfig('system/full_page_cache/fastly/current_version', Mage::getConfig()->getNode('modules/Fastly_CDN/version')); 61 | Mage::getConfig()->saveConfig('system/full_page_cache/fastly/fastly_ga_cid', $cid); 62 | 63 | $sendInstalledReq = $statistic->sendInstalledReq(); 64 | 65 | $installedData = array( 66 | 'action' => $statistic::FASTLY_INSTALLED_FLAG, 67 | 'created_at' => Varien_Date::now(), 68 | 'sent' => $sendInstalledReq 69 | ); 70 | 71 | $statistic->setData($installedData); 72 | $statistic->save(); 73 | } 74 | 75 | $installer->endSetup(); -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/sql/fastlycdn_setup/upgrade-1.0.0-1.0.1.php: -------------------------------------------------------------------------------- 1 | getConnection(); 9 | 10 | $installer->startSetup(); 11 | 12 | /** 13 | * Create table 'fastly_statistics' 14 | */ 15 | 16 | $table = $connection->newTable($installer->getTable('fastlycdn/statistics') 17 | )->addColumn( 18 | 'stat_id', 19 | Varien_Db_Ddl_Table::TYPE_INTEGER, 20 | null, 21 | ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 22 | 'Stat id' 23 | )->addColumn( 24 | 'action', 25 | Varien_Db_Ddl_Table::TYPE_TEXT, 26 | 30, 27 | ['nullable' => false], 28 | 'Fastly action' 29 | )->addColumn( 30 | 'sent', 31 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 32 | null, 33 | ['nullable' => false, 'default' => 0], 34 | '1 = Curl req. sent | 0 = Curl req. not sent' 35 | )->addColumn( 36 | 'state', 37 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 38 | null, 39 | ['nullable' => false, 'default' => 0], 40 | '1 = configured | 0 = not_configured' 41 | )->addColumn( 42 | 'created_at', 43 | Varien_Db_Ddl_Table::TYPE_DATETIME, 44 | null, 45 | [], 46 | 'Action date' 47 | ); 48 | $connection->createTable($table); 49 | 50 | /** 51 | * Insert Installed action into the statistic table 52 | */ 53 | 54 | $tableName = $installer->getTable('fastly_statistics'); 55 | 56 | if($connection->isTableExists($tableName) == true) { 57 | 58 | $statistic = Mage::getModel('fastlycdn/statistic'); 59 | $cid = $statistic->generateCid(); 60 | Mage::getConfig()->saveConfig('system/full_page_cache/fastly/current_version', Mage::getConfig()->getNode('modules/Fastly_CDN/version')); 61 | Mage::getConfig()->saveConfig('system/full_page_cache/fastly/fastly_ga_cid', $cid); 62 | 63 | $sendInstalledReq = $statistic->sendInstalledReq(); 64 | 65 | $installedData = array( 66 | 'action' => $statistic::FASTLY_INSTALLED_FLAG, 67 | 'created_at' => Varien_Date::now(), 68 | 'sent' => $sendInstalledReq 69 | ); 70 | 71 | $statistic->setData($installedData); 72 | $statistic->save(); 73 | } 74 | 75 | $installer->endSetup(); -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/page/notices_hook.phtml: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | isUserNotAllowSaveCookie()): ?> 25 | generateCookieName( 28 | Fastly_CDN_Model_Esi_Tag_Page_Html_Notices::COOKIE_NAME 29 | ); 30 | ?> 31 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Control/Catalog/Category.php: -------------------------------------------------------------------------------- 1 | _canPurge()) { 35 | $this->_purgeById($category->getId()); 36 | if ($categoryName = $category->getName()) { 37 | $this->_getSession()->addSuccess( 38 | Mage::helper('fastlycdn')->__('Fastly CDN for "%s" has been purged.', $categoryName) 39 | ); 40 | } 41 | } 42 | return $this; 43 | } 44 | 45 | /** 46 | * Purge Category by id 47 | * 48 | * @param int $id 49 | * @return Fastly_CDN_Model_Control_Catalog_Category 50 | */ 51 | public function purgeById($id) 52 | { 53 | if ($this->_canPurge()) { 54 | $this->_purgeById($id); 55 | } 56 | return $this; 57 | } 58 | 59 | /** 60 | * Purge Category by id 61 | * 62 | * @param int $id 63 | * @return Fastly_CDN_Model_Control_Catalog_Category 64 | */ 65 | protected function _purgeById($id) 66 | { 67 | $surrogateKey = Fastly_CDN_Helper_Tags::SURROGATE_KEY_CATEGORY_PREFIX . $id; 68 | $this->_getCacheControl()->cleanBySurrogateKey($surrogateKey); 69 | 70 | return $this; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Hash/Parameters.php: -------------------------------------------------------------------------------- 1 | _domains; 39 | } 40 | 41 | /** 42 | * @param array $domains 43 | * 44 | * @return $this 45 | */ 46 | public function setDomains(array $domains) 47 | { 48 | $this->_domains = $domains; 49 | return $this; 50 | } 51 | 52 | /** 53 | * @return string 54 | */ 55 | public function getType() 56 | { 57 | return !empty($this->_type) ? $this->_type : '.*'; 58 | } 59 | 60 | /** 61 | * @param string $type 62 | * 63 | * @return $this 64 | */ 65 | public function setType($type) 66 | { 67 | $this->_type = $type; 68 | return $this; 69 | } 70 | 71 | /** 72 | * @return string 73 | */ 74 | public function getRegexp() 75 | { 76 | return !empty($this->_regexp) ? $this->_regexp : '.*'; 77 | } 78 | 79 | /** 80 | * @param string $regexp 81 | * 82 | * @return $this 83 | */ 84 | public function setRegexp($regexp) 85 | { 86 | $this->_regexp = $regexp; 87 | return $this; 88 | } 89 | 90 | public function isWildcard() 91 | { 92 | return empty($this->_domains) && empty($this->_regexp) && empty($this->_type); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/layout/fastlycdn.xml: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | js_cssprototype/windows/themes/default.css 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Release-Notes.md: -------------------------------------------------------------------------------- 1 | # Fastly_Cdn Release Notes 2 | 3 | ## 1.0.32 4 | 5 | - Enable processing of ESIs inside CDATA 6 | 7 | ## 1.0.31 8 | 9 | - Fix for https://github.com/fastly/fastly-magento/issues/50 10 | 11 | ## 1.0.30 12 | 13 | - Add FormKey validation 14 | 15 | ## 1.0.29 16 | 17 | - Add VCL to protect against inadvertent gzipping ESIs 18 | 19 | 20 | ## 1.0.28 21 | 22 | - Add Image Optimization UI 23 | 24 | ## 1.0.27 25 | 26 | - Fix for the ESI FASTLY_CDN-cookie replacement logic https://github.com/fastly/fastly-magento/commit/0575218ceba5bc2dba8b8d37c0aa132f6319c727 27 | 28 | ## 1.0.26 29 | 30 | - Change sales_order_view to sales_order_ to handle all routes https://github.com/fastly/fastly-magento/pull/46 31 | - Fix ESI include path, fix translate warnings https://github.com/fastly/fastly-magento/pull/45 32 | 33 | ## 1.0.25 34 | 35 | - Minor VCL changes 36 | 37 | ## 1.0.24 38 | 39 | - Add code to make sure user doesn't enable FPC in conjunction with Fastly module as that leads to bad behavior 40 | https://github.com/fastly/fastly-magento/pull/43 41 | 42 | ## 1.0.23. 43 | 44 | - Fix inability to do purge all via Fastly UI 45 | - insert js css via layout update https://github.com/fastly/fastly-magento/pull/42 46 | 47 | ## 1.0.22 48 | 49 | - Validate error/maintenance page is smaller than 65535 characters https://github.com/fastly/fastly-magento/pull/41 50 | - Add marker to every HTML page generated by Magento so that only those pages are processed by ESI 51 | 52 | ## 1.0.21 53 | 54 | - added support for replacing admin path and query string parametars in vcl templates https://github.com/fastly/fastly-magento/pull/38 55 | 56 | ## 1.0.20 57 | 58 | - Minor VCL fix to make sure 404 images don't end up overwriting user cookies 59 | 60 | ## 1.0.19 61 | 62 | - No changes except a fix for composer.json 63 | 64 | ## 1.0.18 65 | 66 | - Webhooks support 67 | - Fix for Sales View Order ESI tag error https://github.com/fastly/fastly-magento/pull/37 68 | 69 | ## 1.0.17 70 | 71 | - Minor VCL tweaks 72 | 73 | ## 1.0.16 74 | 75 | - Fix for a case where a Fastly service version doesn't have any ACLs or Dictionaries 76 | 77 | ## 1.0.15 78 | 79 | - Add ability to manage Edge Dictionaries and Edge ACLs directly from the Magento Admin UI 80 | 81 | ## 1.0.14 82 | 83 | - Change quotes for ESI includes from " to ' due to modules like ngx_pagespeed corrupting HTML with " present 84 | 85 | ## 1.0.13 86 | 87 | - New documentation guides 88 | - Minor VCL updates 89 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/fastlycdn/geoip/dialog.phtml: -------------------------------------------------------------------------------- 1 | 22 | 29 | getChildHtml('esiPopup')); ?> 30 | 31 | 34 | 35 | 49 | 50 | 71 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/Cache/Additional.php: -------------------------------------------------------------------------------- 1 | getUrl('*/fastlyCdn/cleanStore'); 38 | } 39 | 40 | /** 41 | * Get clean cache url 42 | * 43 | * @return string 44 | */ 45 | public function getCleanContentTypeUrl() 46 | { 47 | return $this->getUrl('*/fastlyCdn/cleanContentType'); 48 | } 49 | 50 | /** 51 | * Returns Quick Purge URL 52 | * 53 | * @return string 54 | */ 55 | public function getQuickPurgeUrl() 56 | { 57 | return $this->getUrl('*/fastlyCdn/quickPurge'); 58 | } 59 | 60 | /** 61 | * Check if block can be displayed 62 | * 63 | * @return bool 64 | */ 65 | public function canShowButton() 66 | { 67 | return Mage::helper('fastlycdn')->isEnabled(); 68 | } 69 | 70 | /** 71 | * Get store selection 72 | * 73 | * @return string 74 | */ 75 | public function getStoreOptions() 76 | { 77 | $stores = Mage::getModel('adminhtml/system_config_source_store')->toOptionArray(); 78 | return $stores; 79 | } 80 | 81 | /** 82 | * Get content types 83 | */ 84 | public function getContentTypeOptions() 85 | { 86 | foreach (Mage::getModel('fastlycdn/control')->getContentTypes() as $value => $label) { 87 | $options[] = array('value' => $value, 'label' => $label); 88 | } 89 | return $options; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Control/Abstract.php: -------------------------------------------------------------------------------- 1 | _helperName) { 44 | return false; 45 | } 46 | return Mage::helper($this->_helperName)->canPurge(); 47 | } 48 | 49 | /** 50 | * Get fastlyCDN control model 51 | * 52 | * @return Fastly_CDN_Model_Control 53 | */ 54 | protected function _getCacheControl() 55 | { 56 | return Mage::helper('fastlycdn')->getCacheControl(); 57 | } 58 | 59 | /** 60 | * Get url rewrite collection 61 | * 62 | * @return Fastly_CDN_Model_Resource_Mysql4_Core_Url_Rewrite_Collection 63 | */ 64 | protected function _getUrlRewriteCollection() 65 | { 66 | return Mage::getResourceModel('fastlycdn/core_url_rewrite_collection'); 67 | } 68 | 69 | /** 70 | * Get product relation collection 71 | * 72 | * @return Fastly_CDN_Model_Resource_Mysql4_Catalog_Product_Relation_Collection 73 | */ 74 | protected function _getProductRelationCollection() 75 | { 76 | return Mage::getResourceModel('fastlycdn/catalog_product_relation_collection'); 77 | } 78 | 79 | /** 80 | * Get catalog category product relation collection 81 | * 82 | * @return Fastly_CDN_Model_Resource_Mysql4_Catalog_Product_Relation_Collection 83 | */ 84 | protected function _getCategoryProductRelationCollection() 85 | { 86 | return Mage::getResourceModel('fastlycdn/catalog_category_product_collection'); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Esi.php: -------------------------------------------------------------------------------- 1 | '; 28 | 29 | /** 30 | * return if used magento version uses form keys 31 | * 32 | * @return bool 33 | */ 34 | public function hasFormKey() 35 | { 36 | $session = Mage::getSingleton('core/session'); 37 | 38 | return method_exists($session, 'getFormKey'); 39 | } 40 | 41 | /** 42 | * generate esi tag for form keys 43 | * 44 | * @return string 45 | */ 46 | public function getFormKeyEsiTag() 47 | { 48 | $url = Mage::getUrl( 49 | self::ESI_FORMKEY_URL, 50 | array( 51 | '_nosid' => true, 52 | '_secure' => false 53 | ) 54 | ); 55 | $esiTag = self::ESI_INCLUDE_OPEN . preg_replace("/^https/", "http", $url) . self::ESI_INCLUDE_CLOSE; 56 | 57 | return $esiTag; 58 | } 59 | 60 | /** 61 | * Replace form key with esi tag 62 | * 63 | * @param string $content 64 | * @return string 65 | */ 66 | public function replaceFormKey($content) 67 | { 68 | /** @var $session Mage_Core_Model_Session */ 69 | $session = Mage::getSingleton('core/session'); 70 | 71 | // replace all occurrences of form key with esi tag 72 | $content = str_replace( 73 | $session->getFormKey(), 74 | $this->getFormKeyEsiTag(), 75 | $content 76 | ); 77 | 78 | return $content; 79 | } 80 | 81 | /** 82 | * Return the form key value stored in a cookie 83 | * or false if it is not set 84 | * 85 | * @return string|false 86 | */ 87 | public function getCookieFormKey() 88 | { 89 | return Mage::getSingleton('core/cookie')->get(self::FORMKEY_COOKIE); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Guides/ESI.md: -------------------------------------------------------------------------------- 1 | # ESI example implementation 2 | 3 | We'll explain how to customize ESI fragments by implementing a sample `deliverycountdown/deliveryCountdown` fragment. 4 | 5 | First you will need to insert code below in `config.xml`. It needs to be placed inside parent XML node for `fastlycdn_esi_tags`: 6 | 7 | ``` 8 | 9 | deliverycountdown/deliveryCountdown 10 | Fastly_CDN_Model_Esi_Tag_DeliveryCountDown 11 | 12 | ``` 13 | 14 | Block node contains type of your block and `esi_tag` custom php class which is in charge of replacing block HTML output with ESI tags. 15 | 16 | In custom class (used in `esi_tag` node) `Fastly_CDN_Model_Esi_Tag_DeliveryCountDown` you should declare two constants: 17 | 18 | `COOKIE_NAME` and `ESI_URL` 19 | 20 | Your custom class should something like this 21 | 22 | ``` 23 | class Fastly_CDN_Model_Esi_Tag_DeliveryCountDown 24 | extends Fastly_CDN_Model_Esi_Tag_Abstract 25 | { 26 | const COOKIE_NAME = 'deliverycountdown'; 27 | const ESI_URL = 'fastlycdn/esi/deliverycountdown'; 28 | } 29 | ``` 30 | 31 | After you configure it, ESI directives should be present in HTML source and if ESI debug is on you should see the red 32 | box with ESI URL. 33 | 34 | ## Possible issues with ESI directives 35 | 36 | If you don’t see the ESI directives please investigate following 37 | 38 | 1. If caching is turned on, flush cache then check parent blocks 39 | 2. Check does your custom block fire event `core_block_abstract_to_html_after`. All logic for implementation of 40 | ESI is in observer `Fastly_CDN_Model_Observer` and in method `replaceBlockByEsiTag` 41 | 42 | 43 | ## Example of properly configured ESI 44 | 45 | When ESI is properly configured then page HTML should look like the example below (this is example for cart block): 46 | 47 | ``` 48 | 49 | 50 |
51 | 52 |

53 | My Cart 54 |

55 |
56 |
57 |
58 |

You have no items in your shopping cart.

59 |
60 |
61 | 62 |
63 | 64 | 65 | ``` 66 | 67 | OPTIONAL: You may possible need to configure Fastly VCL snippets for specific ESI call. 68 | -------------------------------------------------------------------------------- /Guides/BACKEND-SETTINGS.md: -------------------------------------------------------------------------------- 1 | # Backend settings guide 2 | 3 | This guide will show you how to how to fine tune Fastly’s service performance by configuring Origin shielding and timeout settings. 4 | 5 | ### Origin shielding 6 | 7 | Origin shielding is Fastly’s service feature which reduces the load on your origin server by routing all requests to a specfic **Point of Presence** (POP) which you have designated as a shield node to your origin. 8 | 9 | #### How shielding works 10 | 11 | With shielding enabled, when the first request for content arrives at one of the POP’s, for e.g. **POP A**, POP A doesn’t have that content cached. The request is passed to the **Shield POP** which also doesn’t have the content cached and passes request to the customers **Origin server** to fetch the content and store it in cache. The cached content is then passed to the POP A and served to the user. 12 | 13 | Now, when another request arrives at **POP B** instead of POP A, POP B will pass request to the Shield POP, and since the Shield POP already has a cached copy from the first request, no future requests for the content would be passed along to the customer’s origin server until the shield POP’s cached copy of it expires. 14 | 15 | ### Backend timeouts 16 | 17 | A backend is an address (IP or domain) from which Fastly pulls content. Backend timeouts define how long will Fastly wait for backend operations to complete. 18 | 19 | You can set three different timeouts: 20 | 21 | * Connect timeout – how long to wait for a timeout in milliseconds. (default: 1000ms) 22 | * First byte timeout – limits how long the processing time of the backend may be. (default: 10000ms) 23 | * Between bytes timeout – limits how long we will wait between for two subsequent successful reads on the backend connection. (default: 15000ms) 24 | 25 | 26 | ### Fastly configuration 27 | 28 | You can configure Origin shielding and Backend timeout in the Fastly module by going to: 29 | 30 | ``` 31 | Magento admin > System > Configuration > Services > Fastly CDN 32 | ``` 33 | 34 | Under the Fastly CDN Configuration, click on the **Backend settings:** 35 | 36 | ![Edit backend](images/guides/backend-settings/edit-backend.png "Edit backend") 37 | 38 | There you will see a list of backends. Click on the Edit button next to the backend for which you want to configure **Shielding.** 39 | 40 | The modal window will pop up with the following content: 41 | 42 | ![Shield configuration](images/guides/backend-settings/shielding-configuration.png "Shield configuration") 43 | 44 | For the Shield value you should select Datacenter close to your backend. As for backend timeout settings, it’s best to leave default values or set them according to your needs. Press the Upload button in the upper right corner to apply your changes. 45 | 46 | That’s it, you have successfully fine tuned your Fastly service. -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Cookie/Environment.php: -------------------------------------------------------------------------------- 1 | addData(array( 34 | 'cache_lifetime' => false, 35 | 'cache_tags' => array(Mage_Core_Model_Store::CACHE_TAG), 36 | )); 37 | } 38 | 39 | /** 40 | * @return Fastly_CDN_Helper_Environment 41 | */ 42 | protected function _getHelper() 43 | { 44 | if (is_null($this->_helper)) { 45 | $this->_helper = Mage::helper('fastlycdn/environment'); 46 | } 47 | return $this->_helper; 48 | } 49 | 50 | /** 51 | * Get key pieces for caching block content 52 | * 53 | * @return array 54 | */ 55 | public function getCacheKeyInfo() 56 | { 57 | $cacheId = array( 58 | 'FASTLYCDN_COOKIE_ENVIRONMENT_', 59 | Mage::app()->getStore()->getId(), 60 | Mage::getDesign()->getPackageName(), 61 | Mage::getDesign()->getTheme('template'), 62 | Mage::getSingleton('customer/session')->getCustomerGroupId(), 63 | Mage::app()->getStore()->getCurrentCurrencyCode(), 64 | 'template' => $this->getTemplate(), 65 | 'name' => $this->getNameInLayout(), 66 | ); 67 | return $cacheId; 68 | } 69 | 70 | /** 71 | * Return value for environment cookie if current env differs from default 72 | * 73 | * @return string 74 | */ 75 | public function getEnvironmentHash() 76 | { 77 | return $this->_getHelper()->getEnvironmentHash(); 78 | } 79 | 80 | /** 81 | * Return cookie lifetime for environment cookie 82 | * 83 | * @return int 84 | */ 85 | public function getCookieLifetime() 86 | { 87 | return $this->_getHelper()->getCookieLiftime(); 88 | } 89 | 90 | /** 91 | * Return environment cookie name 92 | * 93 | * @return string 94 | */ 95 | public function getCookieName() 96 | { 97 | return $this->_getHelper()->getCookieName(); 98 | } 99 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Processor/Abstract.php: -------------------------------------------------------------------------------- 1 | getLayoutName()) { 35 | $block = Mage::app()->getLayout()->getBlock($layoutName); 36 | $this->_initBlock($block); 37 | $this->_block = $block; 38 | } 39 | } 40 | 41 | /** 42 | * Initializes block environment. 43 | * 44 | * @param mixed $block 45 | * @return void 46 | */ 47 | protected function _initBlock($block) 48 | { 49 | return $this; 50 | } 51 | 52 | /** 53 | * Return block HTML 54 | * 55 | * @see Mage_Core_Block_Abstract::toHtml 56 | * @return string 57 | */ 58 | public function getHtml() 59 | { 60 | $content = ''; 61 | if ($this->_block instanceof Mage_Core_Block_Abstract) { 62 | $debug = $this->_getHelper()->isEsiDebugEnabled(); 63 | if ($debug) { 64 | $content .= '
'; 65 | } 66 | 67 | $content .= $this->_block->toHtml(); 68 | 69 | if ($debug) { 70 | $content .= '
'; 71 | } 72 | } 73 | return $content; 74 | } 75 | 76 | /** 77 | * @return Fastly_CDN_Helper_Data 78 | */ 79 | protected function _getHelper() 80 | { 81 | return Mage::helper('fastlycdn'); 82 | } 83 | 84 | /** 85 | * Return TTL for given block. 86 | * 87 | * @param $block string 88 | * @return int 89 | */ 90 | public function getEsiBlockTtl($block) 91 | { 92 | $ttl = null; 93 | 94 | // get block specific ttl 95 | $esiBlockTtls = unserialize(Mage::getStoreConfig(self::XML_PATH_FASTLY_CDN_ESI_BLOCK_TTL)); 96 | if (is_array($esiBlockTtls)) { 97 | foreach ($esiBlockTtls as $esiBlock) { 98 | if ($esiBlock['regexp'] == $block) { 99 | $ttl = $esiBlock['value']; 100 | } 101 | } 102 | } 103 | 104 | // ttl not set for block - use default 105 | if (is_null($ttl)) { 106 | $ttl = Mage::getStoreConfig(self::XML_PATH_FASTLY_CDN_ESI_DEFAULT_TTL); 107 | } 108 | 109 | return (int)$ttl; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /skin/adminhtml/default/default/css/fastlycdn/fastly.css: -------------------------------------------------------------------------------- 1 | .overlay_dialog { 2 | background-color: #666666; 3 | filter:alpha(opacity=60); 4 | -moz-opacity: 0.6; 5 | opacity: 0.6; 6 | } 7 | 8 | .overlay___invisible__ { 9 | background-color: #666666; 10 | filter:alpha(opacity=0); 11 | -moz-opacity: 0; 12 | opacity: 0; 13 | } 14 | 15 | .dialog_nw { 16 | width: 9px; 17 | height: 23px; 18 | background: transparent url(default/top_left.gif) no-repeat 0 0; 19 | } 20 | 21 | .dialog_n { 22 | background: transparent url(default/top_mid.gif) repeat-x 0 0; 23 | height: 23px; 24 | } 25 | 26 | .dialog_ne { 27 | width: 9px; 28 | height: 23px; 29 | background: transparent url(default/top_right.gif) no-repeat 0 0; 30 | } 31 | 32 | .dialog_e { 33 | width: 2px; 34 | background: transparent url(default/center_right.gif) repeat-y 0 0; 35 | } 36 | 37 | .dialog_w { 38 | width: 2px; 39 | background: transparent url(default/center_left.gif) repeat-y 0 0; 40 | } 41 | 42 | .dialog_sw { 43 | width: 9px; 44 | height: 19px; 45 | background: transparent url(default/bottom_left.gif) no-repeat 0 0; 46 | } 47 | 48 | .dialog_s { 49 | background: transparent url(default/bottom_mid.gif) repeat-x 0 0; 50 | height: 19px; 51 | } 52 | 53 | .dialog_se { 54 | width: 9px; 55 | height: 19px; 56 | background: transparent url(default/bottom_right.gif) no-repeat 0 0; 57 | } 58 | 59 | .dialog_sizer { 60 | width: 9px; 61 | height: 19px; 62 | background: transparent url(default/sizer.gif) no-repeat 0 0; 63 | cursor:se-resize; 64 | } 65 | 66 | .dialog_close { 67 | width: 14px; 68 | height: 14px; 69 | background: transparent url(default/close.gif) no-repeat 0 0; 70 | position:absolute; 71 | top:5px; 72 | left:8px; 73 | cursor:pointer; 74 | z-index:2000; 75 | } 76 | 77 | .dialog_minimize { 78 | width: 14px; 79 | height: 15px; 80 | background: transparent url(default/minimize.gif) no-repeat 0 0; 81 | position:absolute; 82 | top:5px; 83 | left:28px; 84 | cursor:pointer; 85 | z-index:2000; 86 | } 87 | 88 | .dialog_maximize { 89 | width: 14px; 90 | height: 15px; 91 | background: transparent url(default/maximize.gif) no-repeat 0 0; 92 | position:absolute; 93 | top:5px; 94 | left:49px; 95 | cursor:pointer; 96 | z-index:2000; 97 | } 98 | 99 | .dialog_title { 100 | float:left; 101 | height:14px; 102 | font-family: Tahoma, Arial, sans-serif; 103 | font-size:12px; 104 | text-align:center; 105 | width:100%; 106 | color:#000; 107 | } 108 | 109 | .dialog_content { 110 | overflow:auto; 111 | color: #DDD; 112 | font-family: Tahoma, Arial, sans-serif; 113 | font-size: 10px; 114 | background-color:#123; 115 | } 116 | 117 | .top_draggable, .bottom_draggable { 118 | cursor:move; 119 | } 120 | 121 | .status_bar { 122 | font-size:12px; 123 | } 124 | .status_bar input{ 125 | font-size:12px; 126 | } 127 | 128 | .wired_frame { 129 | display: block; 130 | position: absolute; 131 | border: 1px #000 dashed; 132 | } 133 | 134 | /* DO NOT CHANGE THESE VALUES*/ 135 | .dialog { 136 | display: block; 137 | position: absolute; 138 | } 139 | 140 | .dialog table.table_window { 141 | border-collapse: collapse; 142 | border-spacing: 0; 143 | width: 100%; 144 | margin: 0px; 145 | padding:0px; 146 | } 147 | 148 | .dialog table.table_window td , .dialog table.table_window th { 149 | padding: 0; 150 | } 151 | 152 | .dialog .title_window { 153 | -moz-user-select:none; 154 | } 155 | 156 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Config.php: -------------------------------------------------------------------------------- 1 | _esiTags)) { 39 | foreach (Mage::getConfig()->getNode('fastlycdn_esi_tags')->children() as $key => $config) { 40 | $this->_esiTags[(string)$key] = array( 41 | 'block' => (string)$config->block, 42 | 'esiTag' => (string)$config->esi_tag, 43 | 'processor' => (string)$config->processor 44 | ); 45 | } 46 | } 47 | return $this->_esiTags; 48 | } 49 | 50 | /** 51 | * Get ESI Tag model by block type 52 | * 53 | * @param string $blockType 54 | * @return string 55 | */ 56 | public function getEsiTagClassByBlockType($blockType) 57 | { 58 | $config = $this->getEsiTags(); 59 | foreach ($config as $esiTag) { 60 | if ($esiTag['block'] == $blockType) { 61 | return $esiTag['esiTag']; 62 | } 63 | } 64 | return false; 65 | } 66 | 67 | /** 68 | * Get ESI processor by config key 69 | * 70 | * @param string $configKey 71 | * @return 72 | */ 73 | public function getEsiProcessorConfig($configKey) 74 | { 75 | $esiTags = $this->getEsiTags(); 76 | 77 | if (isset($esiTags[$configKey])) { 78 | return $esiTags[$configKey]; 79 | } 80 | return false; 81 | } 82 | 83 | public function getVclSnippets($path = 'vcl_snippets', $specificFile = null) 84 | { 85 | $snippetsData = array(); 86 | 87 | $moduleEtcPath = Mage::getModuleDir('etc', 'Fastly_CDN') . DS . $path . DS; 88 | $fileReader = new Varien_Io_File(); 89 | $fileReader->open(array('path' => $moduleEtcPath)); 90 | if (!$specificFile) { 91 | $snippets = $fileReader->ls(); 92 | if(is_array($snippets)) 93 | { 94 | foreach ($snippets as $snippet) { 95 | if ($snippet['filetype'] != 'vcl') { 96 | continue; 97 | } 98 | $snippetFilePath = $moduleEtcPath . $snippet['text']; 99 | $type = explode('.', $snippet['text'])[0]; 100 | $snippetsData[$type] = $fileReader->read($snippetFilePath); 101 | } 102 | } 103 | } else { 104 | $snippetFilePath = $moduleEtcPath . '/' . $specificFile; 105 | $type = explode('.', $specificFile)[0]; 106 | $snippetsData[$type] = $fileReader->read($snippetFilePath); 107 | } 108 | 109 | return $snippetsData; 110 | } 111 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Processor/GeoIp/Action.php: -------------------------------------------------------------------------------- 1 | _getHelper()->isGeoIpEnabled()) { 39 | $layout = Mage::app()->getLayout(); 40 | if (Mage::getStoreConfigFlag(self::XML_PATH_GEOIP_SHOW_DIALOG)) { 41 | // show a dialog from CMS block 42 | if ($cmsBlockId = $this->_getMapping(self::XML_PATH_GEOIP_MAP_CMS_BLOCKS, 'cms')) { 43 | $cmsBlock = $layout->createBlock('cms/block')->setBlockId($cmsBlockId); 44 | $output = $layout->createBlock('core/template') 45 | ->setTemplate('fastlycdn/geoip/dialog.phtml') 46 | ->setChild('esiPopup', $cmsBlock) 47 | ->toHtml(); 48 | } 49 | } else { 50 | // redirect to another store via JavaScript 51 | if ($redirectTo = $this->_getMapping(self::XML_PATH_GEOIP_MAP_REDIRECT, 'store')) { 52 | $store = Mage::getModel('core/store')->load($redirectTo); 53 | /* @var $store Mage_Core_Model_Store */ 54 | if ($store->getId()) { 55 | $redirectUrl = $store->getUrl('', array('_nosid' => true)); 56 | $output = $layout->createBlock('core/template') 57 | ->setTemplate('fastlycdn/geoip/redirect.phtml') 58 | ->setRedirectUrl($redirectUrl) 59 | ->toHtml(); 60 | } 61 | } 62 | } 63 | } 64 | 65 | return $output; 66 | } 67 | 68 | /** 69 | * get the mapping for a county code 70 | * 71 | * @param string $xmlPath configuration path for mapping 72 | * @param string $key column name of mapping value 73 | * 74 | * @return bool|string 75 | */ 76 | protected function _getMapping($xmlPath, $key) { 77 | if ($countryCode = Mage::app()->getRequest()->getParam('country_code')) { 78 | if ($map = Mage::getStoreConfig($xmlPath)) { 79 | $map = unserialize($map); 80 | 81 | if (isset($map['country'])) { 82 | // check for direct match 83 | foreach ($map['country'] as $i => $country) { 84 | if (strtolower($country) == strtolower($countryCode)) { 85 | return $map[$key][$i]; 86 | } 87 | } 88 | // check for wildcard 89 | foreach ($map['country'] as $i => $country) { 90 | if ($country == '*') { 91 | return $map[$key][$i]; 92 | } 93 | } 94 | } 95 | } 96 | } 97 | return false; 98 | } 99 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Webhooks.php: -------------------------------------------------------------------------------- 1 | isEnabled()) { 83 | return; 84 | } 85 | 86 | $urlEndpoint = $this->getWebhookUrl(); 87 | $username = $this->getWebookUsername(); 88 | $channel = '#' . $this->getWebHookChannel(); 89 | $messagePrefix = $this->getWebhookMessagePrefix(); 90 | $storeName = Mage::app()->getStore()->getName(); 91 | $storeUrl = Mage::app()->getStore()->getUrl(); 92 | $message = $messagePrefix . ' ' . $message.' on <'.$storeUrl.'|Store> | '.$storeName; 93 | $headers = array('Content-type: application/json'); 94 | 95 | $body = json_encode(array( 96 | 'text' => $message, 97 | 'username' => $username, 98 | 'channel' => $channel, 99 | 'icon_emoji' => ':airplane:' 100 | )); 101 | 102 | $curl = new Varien_Http_Adapter_Curl(); 103 | $curl->setConfig(array( 104 | 'timeout' => 2 105 | )); 106 | $curl->write(Zend_Http_Client::POST, $urlEndpoint, '1.1', $headers, $body); 107 | if ($curl->read()) { 108 | if ($curl->getInfo(CURLINFO_HTTP_CODE) != 200) { 109 | $response = $curl->read(); 110 | Mage::log('Failed to send message to the following Webhook: ' . $urlEndpoint . ' - Response: ' . $response); 111 | } 112 | } 113 | 114 | $curl->close(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Helper/Environment.php: -------------------------------------------------------------------------------- 1 | getDefaultStoreView(); 41 | $defaultLimit = Mage::getStoreConfig('catalog/frontend/list_per_page'); 42 | 43 | $defaultSettings = array( 44 | 'storeId' => $defaultStore->getId(), 45 | 'currency' => $defaultStore->getDefaultCurrencyCode(), 46 | 'customerGroup' => Mage_Customer_Model_Group::NOT_LOGGED_IN_ID, 47 | 'limit' => $defaultLimit, 48 | ); 49 | 50 | // get current store settings 51 | $currentStore = Mage::app()->getStore(); 52 | $currentSettings = array( 53 | 'storeId' => $currentStore->getId(), 54 | 'currency' => $currentStore->getCurrentCurrencyCode(), 55 | 'customerGroup' => Mage::getSingleton('customer/session')->getCustomerGroupId(), 56 | 'limit' => $this->_getCurrentLimit($defaultLimit), 57 | ); 58 | 59 | $cookieValue = ''; 60 | // only set cookie value if not in default environment 61 | if (array_diff($defaultSettings, $currentSettings)) { 62 | $cookieValue = md5(serialize($currentSettings)); 63 | } 64 | 65 | return $cookieValue; 66 | } 67 | 68 | /** 69 | * Return cookie lifetime in ms 70 | * 71 | * @return int 72 | */ 73 | public function getCookieLiftime() 74 | { 75 | return (intval($this->_getCookie()->getLifetime() * 1000)); 76 | } 77 | 78 | /** 79 | * Sets environment cookie 80 | * 81 | * @return void 82 | */ 83 | public function setEnvironmentCookie() 84 | { 85 | if ($envHash = $this->getEnvironmentHash()) { 86 | $this->_getCookie()->set( 87 | self::ENVIRONMENT_COOKIE, 88 | $envHash, 89 | $this->getCookieLiftime() 90 | ); 91 | } else { 92 | $this->_getCookie()->delete(self::ENVIRONMENT_COOKIE); 93 | } 94 | } 95 | 96 | /** 97 | * Return the name of the cookie 98 | * 99 | * @return string 100 | */ 101 | public function getCookieName() 102 | { 103 | return self::ENVIRONMENT_COOKIE; 104 | } 105 | 106 | /** 107 | * @return Mage_Core_Model_Cookie 108 | */ 109 | protected function _getCookie() 110 | { 111 | return Mage::getSingleton('core/cookie'); 112 | } 113 | 114 | /** 115 | * Return current pagination limit 116 | * 117 | * @param int $defaultLimit 118 | * 119 | * @return int 120 | */ 121 | protected function _getCurrentLimit($defaultLimit) 122 | { 123 | $currentLimit = Mage::getSingleton('catalog/session')->getLimitPage(); 124 | if (is_null($currentLimit) === false) { 125 | return $currentLimit; 126 | } 127 | 128 | return $defaultLimit; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/fastlycdn/cache/additional.phtml: -------------------------------------------------------------------------------- 1 | 22 | 23 | canShowButton()): ?> 24 |
25 | getBlockHtml('formkey')?> 26 | 27 | 28 | 31 | 38 | 41 | 42 |
29 | 30 | 32 | 37 | 39 | __('Remove selected cache items in Fastly CDN by content type. This removes the selected content type for all stores.')?> 40 |
43 |
44 | 45 |
46 | getBlockHtml('formkey')?> 47 | 48 | 49 | 52 | 59 | 62 | 63 |
50 | 51 | 53 | 58 | 60 | __('Remove Magento generated content from selected store in Fastly CDN. This only removes store related information, not images, css or js.')?> 61 |
64 |
65 | 66 |
67 | getBlockHtml('formkey')?> 68 | 69 | 70 | 73 | 76 | 79 | 80 |
71 | 72 | 74 | 75 | 77 | __('Purge URL in Fastly CDN.')?> 78 |
81 |
82 | 83 | 88 | 89 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Controller/Router.php: -------------------------------------------------------------------------------- 1 | getEvent()->getFront(); 32 | /* @var $front Mage_Core_Controller_Varien_Front */ 33 | $front->addRouter('fastlyCDN', $this); 34 | } 35 | 36 | /** 37 | * Validate and Match Cms Page and modify request 38 | * 39 | * @param Zend_Controller_Request_Http $request 40 | * @return bool 41 | */ 42 | public function match(Zend_Controller_Request_Http $request) 43 | { 44 | $front = $this->getFront(); 45 | $path = trim($request->getPathInfo(), '/'); 46 | 47 | if ($path) { 48 | $p = explode('/', $path); 49 | } 50 | 51 | // get module name 52 | if ($request->getModuleName()) { 53 | $module = $request->getModuleName(); 54 | } else { 55 | if (!empty($p[0])) { 56 | $module = $p[0]; 57 | } 58 | } 59 | 60 | if ($module != 'fastlycdn') { 61 | return false; 62 | } 63 | 64 | // we only handle Fastly CDN requests 65 | $realModule = 'Fastly_CDN'; 66 | 67 | $request->setRouteName($this->getRouteByFrontName($module)); 68 | 69 | // get controller name 70 | if ($request->getControllerName()) { 71 | $controller = $request->getControllerName(); 72 | } else { 73 | if (!empty($p[1])) { 74 | $controller = $p[1]; 75 | } else { 76 | $controller = $front->getDefault('controller'); 77 | $request->setAlias( 78 | Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS, 79 | ltrim($request->getOriginalPathInfo(), '/') 80 | ); 81 | } 82 | } 83 | 84 | // get action name 85 | if (empty($action)) { 86 | if ($request->getActionName()) { 87 | $action = $request->getActionName(); 88 | } else { 89 | $action = !empty($p[2]) ? $p[2] : $front->getDefault('action'); 90 | } 91 | } 92 | 93 | $controllerClassName = $this->_validateControllerClassName($realModule, $controller); 94 | if (!$controllerClassName) { 95 | return false; 96 | } 97 | 98 | // instantiate controller class 99 | $controllerInstance = Mage::getControllerInstance($controllerClassName, $request, $front->getResponse()); 100 | 101 | if (!$controllerInstance->hasAction($action)) { 102 | $action = 'processor'; 103 | } 104 | 105 | // set values only after all the checks are done 106 | $request->setModuleName($module); 107 | $request->setControllerName($controller); 108 | $request->setActionName($action); 109 | $request->setControllerModule($realModule); 110 | 111 | // set parameters from pathinfo 112 | for ($i = 3, $l = sizeof($p); $i < $l; $i += 2) { 113 | $request->setParam($p[$i], isset($p[$i+1]) ? urldecode($p[$i+1]) : ''); 114 | } 115 | 116 | // dispatch action 117 | $request->setDispatched(true); 118 | $controllerInstance->dispatch($action); 119 | 120 | return true; 121 | } 122 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Processor/GeoIp/Getcountry.php: -------------------------------------------------------------------------------- 1 | getRemoteAddr()) { 36 | // reduce multiple ip list to only first ip 37 | if (strpos($clientIP, ',')) { 38 | list($clientIP) = explode(',', $clientIP); 39 | } 40 | 41 | // try to get current country code 42 | if (function_exists('geoip_country_code_by_name')) { 43 | // by ip address 44 | $clientCountry = @geoip_country_code_by_name($clientIP); 45 | } else { 46 | // try to use the accepted language instead 47 | // this is based on customer browser settings 48 | // !!! this is not the country but the language !!! 49 | $clientCountry = $this->_getAcceptedLanguages(); 50 | } 51 | } 52 | 53 | if($clientCountry) { 54 | // normalize client country to ISO 3166 55 | if(!is_array($clientCountry)) { 56 | $clientCountry = array($clientCountry); 57 | } 58 | $countries = array(); 59 | foreach($clientCountry as $country) { 60 | $country = substr($country, 0, 2); 61 | if (!in_array($country, $countries)) { 62 | $countries[] = $country; 63 | } 64 | } 65 | 66 | // build ESI tag 67 | $esiUrl = Mage::app()->getStore()->getUrl( 68 | 'fastlycdn/esi/getcountryaction', 69 | array( 70 | '_query' => array( 71 | 'country_code' => strtoupper($countries[0]) 72 | ), 73 | '_nosid' => true 74 | ) 75 | ); 76 | $output = Fastly_CDN_Helper_Esi::ESI_INCLUDE_OPEN 77 | . preg_replace("/^https/", "http", $esiUrl) 78 | . Fastly_CDN_Helper_Esi::ESI_INCLUDE_CLOSE; 79 | } 80 | 81 | return $output; 82 | } 83 | 84 | /** 85 | * get the list of accepted languages from the browser 86 | * 87 | * @return array 88 | */ 89 | protected function _getAcceptedLanguages() 90 | { 91 | $acceptedLanguages = array(); 92 | 93 | if ($acceptLanguage = Mage::helper('core/http')->getHttpAcceptLanguage()) { 94 | // iterate over accepted languages 95 | $languageList = explode(',', $acceptLanguage); 96 | foreach ($languageList as $accept) { 97 | // extract language parts 98 | // we only deal with the primary language tag 99 | if (preg_match('/([a-z]+)(;q=([0-9.]+))?/', trim($accept), $parts)) { 100 | $acceptedLanguages[] = $parts[1]; 101 | $quality[] = (isset($parts[3]) ? (float)$parts[3] : 1.0); 102 | } 103 | } 104 | 105 | // order the codes by quality 106 | array_multisort($quality, SORT_NUMERIC, SORT_DESC, $acceptedLanguages); 107 | } 108 | 109 | return $acceptedLanguages; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Guides/INSTALLATION.md: -------------------------------------------------------------------------------- 1 | # Installation guide 2 | 3 | This guide will show you how to install and configure Fastly CDN extension for Magento 1. 4 | 5 | You may choose between two installation methods – composer installation and manual installation by downloading the zip file. 6 | 7 | We will go with a second approach - manually downloading the [zip file](https://github.com/fastly/fastly-magento/releases]). 8 | 9 | 1. Download the zip archive of this repository to a temporary location on your server and extract it. 10 | 2. Copy the contents of the app directory in the archive to the app directory of your Magento instance. 11 | 3. Go to the Magento backend and open the Cache Management (System -> Cache Management) and refresh the configuration and layout cache. 12 | 3. Due to Magento's permission system, please log out and log in again before continuing with the next step. 13 | 14 | If you want to install via composer, you can read step by step instructions [here](../README.md#installation-using-composerjson). 15 | 16 | That’s it, you have successfully installed the Fastly CDN extension. Let’s move to configuration. 17 | 18 | ###Configuration 19 | 20 | In order to use the Fastly Cdn extension, you will have to [register a free Fastly account](https://www.fastly.com/signup). 21 | 22 | Once you register and verify your account, login to Fastly: 23 | 24 | ![Fastly Wizard](images/guides/installation/wizard.png "Fastly Wizard") 25 | 26 | You will see a welcome wizard with two input fields which you should fill with: 27 | 28 | * Your website domain for Fastly to use when routing requests 29 | * The hostname (or IP address) and port number for your origin server 30 | 31 | On the next screen, Fastly is offering you to enable gzip, logging and health check of your origin – you can enable this later. Click continue. 32 | 33 | ![New Features](images/guides/installation/newfeatures.png "New Features") 34 | 35 | On the final screen, you will have to **point your CNAME to Fastly.** Doing this, you will direct traffic from the Internet through Fastly instead of immediately through your store. You can read more here on how to achieve this. 36 | 37 | ![Go Live](images/guides/installation/golive.png "Go Live") 38 | 39 | Once you’ve finished with pointing your CNAME to Fastly, let’s configure Magento. 40 | 41 | Login to you Magento admin and go to: 42 | ``` 43 | System > Configuration > Services > Fastly CDN 44 | ``` 45 | 46 | Under the **General Settings** tab, set **Enable cache module** to **Yes** and then enter your **Fastly Service ID*** and **Fastly API key****. 47 | 48 | ![Choose Fastly](images/guides/installation/choosefastly.png "Choose Fastly") 49 | 50 | **To find out you Service ID, login to the Fastly dashboard, locate your **Service name** and click on the **Show Service ID** link.* 51 | 52 | ![Show Service Id](images/guides/installation/show-service-id.png "Show Service Id") 53 | 54 | ***To find out your API key, while in the Fastly dashboard, select **Account** from the user menu and scroll way down to the bottom of the page. In the **Account API Key** area, click the **Show** button.* 55 | 56 | ![API key](images/guides/installation/account-api-key.png "API key") 57 | 58 | You can press the **Test credentials** button just to make sure that you have entered valid credentials. 59 | 60 | ![Test Credentials](images/guides/installation/testcredentials.png "Test Credentials") 61 | 62 | If you have received a success message, press the **Save Config** button. 63 | 64 | ![Save config](images/guides/installation/saveconfig.png "Clear cache") 65 | 66 | The final step is to upload the **VCL to Fastly.** You can do this by pressing the **Upload VCL to Fastly** button. 67 | 68 | The modal window will pop up, make sure that the **Activate VCL after upload** is ticked and press the **Upload** button in the top right corner: 69 | 70 | ![VCL upload](images/guides/installation/vclupload.png "VCL upload") 71 | 72 | Once the upload process is done, the modal window will automatically close and the success message will show: 73 | 74 | ![Success VCL](images/guides/installation/successvcl.png "Success VCL") 75 | 76 | That’s it, you have successfully configured your Magento store with the Fastly CDN. 77 | 78 | ### General settings 79 | 80 | You can read more about general settings [here](../README.md#31-general-settings). 81 | 82 | ### Purging 83 | 84 | You can purge Fastly CDN content through the Magento admin by going to System > Cache Management. You can purge content by the following options: 85 | 86 | * Purge by content type 87 | * Purge by store 88 | * Purge a URL 89 | * Purge all 90 | 91 | You can read more about purging [here](../README.md#4-cache-cleaning-purge-requests). 92 | 93 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/sql/fastlycdn_setup/install-0.1.0.php: -------------------------------------------------------------------------------- 1 | getCollection()->addFieldToFilter('identifier', $data['identifier']); 32 | 33 | foreach($_blocks as $_block) { 34 | $block = Mage::getModel('cms/block')->load($_block->getId()); 35 | if (count(array_intersect($block->getStores(), $data['stores'])) == count($block->getStores())) { 36 | $found = true; 37 | 38 | foreach ($data as $key => $value) { 39 | $block->setData($key, $value); 40 | } 41 | $block->save(); 42 | 43 | break; 44 | } 45 | } 46 | 47 | if ($found == false) { 48 | Mage::getModel('cms/block')->setData($data)->save(); 49 | } 50 | } 51 | } 52 | 53 | $installer = $this; 54 | /* @var $installer Mage_Core_Model_Resource_Setup */ 55 | 56 | $installer->startSetup(); 57 | 58 | $cmsBlockGeoIp_EN = ' 59 | 65 |
66 | 67 |

Notice

68 |

This shop will not sell to your country.
Please visit one of our other online shops.

69 | 70 | 71 |
72 | '; 73 | 74 | $cmsBlockGeoIp_DE = ' 75 | 81 |
82 | 83 |

Notice

84 |

Dieser Shop liefert nicht in Ihr Land.
Bitte besuchen Sie einen unserer anderen Online-Shops.

85 | 86 | 87 |
88 | '; 89 | 90 | /** 91 | * add CMS blocks for GeoIP modal windows 92 | */ 93 | saveCmsBlocks(array( 94 | array( 95 | 'title' => 'Fastly CDN GeoIp dialog in English', 96 | 'identifier' => 'fastly_cdn_geoip_dialog_EN', 97 | 'content' => $cmsBlockGeoIp_EN, 98 | 'is_active' => 1, 99 | 'stores' => array(0) 100 | ), 101 | array( 102 | 'title' => 'Fastly CDN GeoIp dialog in German', 103 | 'identifier' => 'fastly_cdn_geoip_dialog_DE', 104 | 'content' => $cmsBlockGeoIp_DE, 105 | 'is_active' => 1, 106 | 'stores' => array(0) 107 | ), 108 | )); 109 | 110 | 111 | $installer->endSetup(); 112 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets/fetch.vcl: -------------------------------------------------------------------------------- 1 | if (beresp.status >= 500 && beresp.status < 600) { 2 | /* deliver stale if the object is available */ 3 | if (stale.exists) { 4 | return(deliver_stale); 5 | } 6 | 7 | if (req.restarts < 1 && (req.request == "GET" || req.request == "HEAD")) { 8 | restart; 9 | } 10 | 11 | /* else go to vcl_error to deliver a synthetic */ 12 | error beresp.status beresp.response; 13 | 14 | } 15 | 16 | if (beresp.http.X-Esi) { 17 | # enable ESI feature for Magento response by default 18 | esi; 19 | if (!beresp.http.Vary ~ "Fastly-Cdn-Env,Https") { 20 | if (beresp.http.Vary) { 21 | set beresp.http.Vary = beresp.http.Vary ",Fastly-Cdn-Env,Https"; 22 | } else { 23 | set beresp.http.Vary = "Fastly-Cdn-Env,Https"; 24 | } 25 | } 26 | # Since varnish doesn't compress ESIs we need to hint to the HTTP/2 terminators to 27 | # compress it 28 | set beresp.http.x-compress-hint = "on"; 29 | } else { 30 | # enable gzip for all static content 31 | if (http_status_matches(beresp.status, "200,404") && (beresp.http.content-type ~ "^(application\/x\-javascript|text\/css|text\/html|application\/javascript|text\/javascript|application\/json|application\/vnd\.ms\-fontobject|application\/x\-font\-opentype|application\/x\-font\-truetype|application\/x\-font\-ttf|application\/xml|font\/eot|font\/opentype|font\/otf|image\/svg\+xml|image\/vnd\.microsoft\.icon|text\/plain)\s*($|;)" || req.url.ext ~ "(?i)(css|js|html|eot|ico|otf|ttf|json)" ) ) { 32 | # always set vary to make sure uncompressed versions dont always win 33 | if (!beresp.http.Vary ~ "Accept-Encoding") { 34 | if (beresp.http.Vary) { 35 | set beresp.http.Vary = beresp.http.Vary ", Accept-Encoding"; 36 | } else { 37 | set beresp.http.Vary = "Accept-Encoding"; 38 | } 39 | } 40 | if (req.http.Accept-Encoding == "gzip") { 41 | set beresp.gzip = true; 42 | } 43 | } 44 | } 45 | 46 | # Just in case the Request Setting for x-pass is missing 47 | if (req.http.x-pass) { 48 | return (pass); 49 | } 50 | 51 | # Force any responses with private, no-cache or no-store in Cache-Control to pass 52 | if (beresp.http.Cache-Control ~ "private|no-cache|no-store") { 53 | set req.http.Fastly-Cachetype = "PRIVATE"; 54 | return (pass); 55 | } 56 | 57 | # Varnish sets default TTL if none of these are present. Assume if they are not present that we don't want to cache 58 | if (!beresp.http.Expires && !beresp.http.Surrogate-Control ~ "max-age" && !beresp.http.Cache-Control ~ "(s-maxage|max-age)") { 59 | set beresp.ttl = 0s; 60 | set beresp.cacheable = false; 61 | } 62 | 63 | # If origin provides TTL for an object we cache it 64 | if ( beresp.ttl > 0s && (req.request == "GET" || req.request == "HEAD") && !req.http.x-pass ) { 65 | # Don't cache cookies - this is here because Magento sets cookies even for anonymous users 66 | # which busts cache 67 | unset beresp.http.set-cookie; 68 | 69 | # If surrogate keys have been set do not set them again 70 | if ( !beresp.http.surrogate-keys-set ) { 71 | if (beresp.http.x-esi) { 72 | # init surrogate keys 73 | if (beresp.http.Surrogate-Key) { 74 | set beresp.http.Surrogate-Key = beresp.http.Surrogate-Key " text"; 75 | } else { 76 | set beresp.http.Surrogate-Key = "text"; 77 | } 78 | } else if (beresp.http.Content-Type ~ "(image|script|css)") { 79 | # set surrogate keys by content type if they are image/script or CSS 80 | if (beresp.http.Surrogate-Key) { 81 | set beresp.http.Surrogate-Key = beresp.http.Surrogate-Key " " re.group.1; 82 | } else { 83 | set beresp.http.Surrogate-Key = re.group.1; 84 | } 85 | } 86 | 87 | set beresp.http.surrogate-keys-set = "1"; 88 | } 89 | 90 | } 91 | 92 | # If for whatever reason we get a 404 on static asset requests make sure we strip out set-cookies. Otherwise we run 93 | # the risk of resetting the session since we strip out user cookies for static paths 94 | if (beresp.status == 404 && req.url.path ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico|webp|svg)$") { 95 | unset beresp.http.set-cookie; 96 | } 97 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Control/Catalog/Product.php: -------------------------------------------------------------------------------- 1 | _canPurge()) { 37 | $idsToPurge = array(); 38 | $categoryIdsToPurge = array(); 39 | $idsToPurge[] = $product->getId(); 40 | $this->_getSession()->addSuccess( 41 | Mage::helper('fastlycdn')->__('Fastly CDN for "%s" has been purged.', $product->getName()) 42 | ); 43 | 44 | if ($purgeParentProducts) { 45 | // purge parent products 46 | $productRelationCollection = $this->_getProductRelationCollection() 47 | ->filterByChildId($product->getId()); 48 | foreach ($productRelationCollection as $productRelation) { 49 | $idsToPurge[] = $productRelation->getParentId(); 50 | } 51 | // purge categories of parent products 52 | if ($purgeCategories) { 53 | $categoryProductCollection = $this->_getCategoryProductRelationCollection() 54 | ->filterAllByProductIds($productRelationCollection->getAllIds()); 55 | 56 | foreach ($categoryProductCollection as $categoryProduct) { 57 | $categoryIdsToPurge[] = $categoryProduct->getCategoryId(); 58 | } 59 | } 60 | } 61 | 62 | $this->_purgeByIds($idsToPurge); 63 | 64 | if ($purgeCategories) { 65 | foreach ($product->getCategoryCollection() as $category) { 66 | $categoryIdsToPurge[] = $category->getId(); 67 | } 68 | $this->_getSession()->addSuccess( 69 | Mage::helper('fastlycdn')->__('Fastly CDN for the product\'s categories has been purged.') 70 | ); 71 | } 72 | 73 | $this->_purgeCategoriesByIds($categoryIdsToPurge); 74 | } 75 | return $this; 76 | } 77 | 78 | /** 79 | * Purge product by id 80 | * 81 | * @param int $id 82 | * @param bool $purgeParentProducts 83 | * @param bool $purgeCategories 84 | * @return Fastly_CDN_Model_Control_Catalog_Product 85 | */ 86 | public function purgeById($id, $purgeParentProducts = false, $purgeCategories = false) 87 | { 88 | $product = Mage::getModel('catalog/product')->load($id); 89 | return $this->purge($product, $purgeParentProducts, $purgeCategories); 90 | } 91 | 92 | /** 93 | * Purge product by ids 94 | * 95 | * @param $ids 96 | * 97 | * @return Fastly_CDN_Model_Control_Catalog_Product 98 | */ 99 | protected function _purgeCategoriesByIds($ids) 100 | { 101 | foreach ($ids as $id) { 102 | $surrogateKey = Fastly_CDN_Helper_Tags::SURROGATE_KEY_CATEGORY_PREFIX . $id; 103 | $this->_getCacheControl()->cleanBySurrogateKey($surrogateKey); 104 | } 105 | } 106 | 107 | /** 108 | * Purge product by ids 109 | * 110 | * @param $ids 111 | * 112 | * @return Fastly_CDN_Model_Control_Catalog_Product 113 | */ 114 | protected function _purgeByIds($ids) 115 | { 116 | foreach ($ids as $id) { 117 | $surrogateKey = Fastly_CDN_Helper_Tags::SURROGATE_KEY_PRODUCT_PREFIX . $id; 118 | $this->_getCacheControl()->cleanBySurrogateKey($surrogateKey); 119 | } 120 | 121 | return $this; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/controllers/EsiController.php: -------------------------------------------------------------------------------- 1 | _getHelper()->getActionFromRequest()) { 33 | 34 | $processor = $this->_getHelper()->getProcessorByAction($action); 35 | if ($processor === false) { 36 | $processor = self::DEFAULT_PROCESSOR_NAME; 37 | } 38 | /* @var $processor Fastly_CDN_Model_Esi_Processor_Abstract */ 39 | 40 | $this->_prepareLayout(); 41 | 42 | $requestParams = $this->getRequest()->getParams(); 43 | $this->_emulateSecureRequest($requestParams); 44 | 45 | $processorModel = Mage::getModel($processor, $requestParams); 46 | // get block content 47 | if ($processorModel instanceof Fastly_CDN_Model_Esi_Processor_Abstract) { 48 | $content = $processorModel->getHtml(); 49 | } 50 | 51 | Mage::helper('fastlycdn/cache')->setTtlHeader($processorModel->getEsiBlockTtl($action)); 52 | Mage::register(Fastly_CDN_Helper_Cache::REGISTRY_VAR_FASTLY_CDN_CONTROL_HEADERS_SET_FLAG, 1); 53 | 54 | } else { 55 | $content = Mage::helper('fastlycdn')->__('No Fastly CDN ESI action given'); 56 | } 57 | 58 | $this->getResponse()->setBody($content); 59 | } 60 | 61 | /** 62 | * @return Fastly_CDN_Helper_Data 63 | */ 64 | protected function _getHelper() 65 | { 66 | return Mage::helper('fastlycdn'); 67 | } 68 | 69 | /** 70 | * Layout necessary layout handles 71 | * 72 | * @return void 73 | */ 74 | protected function _prepareLayout() 75 | { 76 | if ($layoutHandles = $this->getRequest()->getParam($this->_getHelper()->getLayoutHandlesParam())) { 77 | // set fake category and product 78 | Mage::register('current_category', Mage::getModel('catalog/category')); 79 | Mage::register('product', Mage::getModel('catalog/product')); 80 | 81 | // if current product id exists, register current product 82 | if($currentProductId = $this->getRequest()->getParam($this->_getHelper()->getCurrentProductIdParam())) { 83 | $currentProduct = Mage::getModel('catalog/product') 84 | ->setStoreId(Mage::app()->getStore()->getId()) 85 | ->load($currentProductId); 86 | 87 | Mage::register('current_product', $currentProduct); 88 | } 89 | 90 | // add handles 91 | $update = $this->getLayout()->getUpdate(); 92 | $existingHandles = $update->getHandles(); 93 | 94 | foreach (explode(',', $layoutHandles) as $handle) { 95 | if (!in_array($handle, $existingHandles)) { 96 | $update->addHandle($handle); 97 | } 98 | } 99 | 100 | // update layout blocks 101 | $this->loadLayoutUpdates(); 102 | $this->generateLayoutXml()->generateLayoutBlocks(); 103 | } else { 104 | $this->loadLayout(); 105 | } 106 | } 107 | 108 | /** 109 | * If is_secure param is set emulate secure request to get correct URLs in block 110 | * 111 | * @see Mage_Core_Model_Store::isCurrentlySecure 112 | * @param array request parameters 113 | * @return void 114 | */ 115 | protected function _emulateSecureRequest(Array $params) 116 | { 117 | $isSecureParam = $this->_getHelper()->getIsSecureParam(); 118 | if (isset($params[$isSecureParam]) && $params[$isSecureParam] === '1') { 119 | // hard set HTTPS server environment variable to "on" 120 | $_SERVER['HTTPS'] = 'on'; 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Model/Esi/Tag/Abstract.php: -------------------------------------------------------------------------------- 1 | '; 25 | const ESI_REMOVE_END_TAG = ''; 26 | const COOKIE_NAME = ''; 27 | const ESI_URL = ''; 28 | 29 | /** 30 | * Return ESI include tag with params for this block. 31 | * 32 | * @param Mage_Core_Block_Abstract 33 | * @return string 34 | */ 35 | public function getEsiIncludeTag(Mage_Core_Block_Abstract $block) 36 | { 37 | $esiTag = ''; 38 | 39 | if (($esiUrl = $this->_getEsiUrl()) && ($cookieName = $this->_getEsiCookieName())) { 40 | 41 | // check if current product exists in registry and obtain current product id 42 | $currentProductId = null; 43 | 44 | if(Mage::registry('current_product')) { 45 | $currentProductId = Mage::registry('current_product')->getId(); 46 | } 47 | 48 | // set ESI parameters to determine block properties in URL 49 | $query = array( 50 | $this->_getHelper()->getLayoutNameParam() => $this->getLayoutName(), 51 | $this->_getHelper()->getEsiDataParam() => $cookieName, 52 | $this->_getHelper()->getLayoutHandlesParam() => $this->_getLayoutHandles($block), 53 | $this->_getHelper()->getIsSecureParam() => Mage::app()->getStore()->isCurrentlySecure() ? '1' : '0', 54 | $this->_getHelper()->getCurrentProductIdParam() => $currentProductId 55 | ); 56 | 57 | // add additional (block specific) query params 58 | if ($additionalQueryParams = $this->_getAdditionalQueryParams()) { 59 | $query = array_merge($query, $additionalQueryParams); 60 | } 61 | 62 | $url = Mage::getUrl($esiUrl, array('_nosid' => true, '_query' => $query)); 63 | 64 | // make url relative 65 | $url = str_replace(Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB), '/', $url); 66 | 67 | $esiTag = Fastly_CDN_Helper_Esi::ESI_INCLUDE_OPEN 68 | . preg_replace("/^https/", "http", $url) 69 | . Fastly_CDN_Helper_Esi::ESI_INCLUDE_CLOSE; 70 | 71 | // add plain ESI include URL for debugging 72 | if ($this->_getHelper()->isEsiDebugEnabled()) { 73 | $esiTag .= '' . $url . ''; 74 | } 75 | } 76 | 77 | return $esiTag; 78 | } 79 | 80 | /** 81 | * @return string 82 | */ 83 | public function getStartRemoveTag() 84 | { 85 | return self::ESI_REMOVE_START_TAG; 86 | } 87 | 88 | /** 89 | * @return string 90 | */ 91 | public function getEndRemoveTag() 92 | { 93 | return self::ESI_REMOVE_END_TAG; 94 | } 95 | 96 | /** 97 | * @return string 98 | */ 99 | protected function _getEsiUrl() 100 | { 101 | return $this::ESI_URL; 102 | } 103 | 104 | /** 105 | * @return string 106 | */ 107 | protected function _getEsiCookieName() 108 | { 109 | return $this::COOKIE_NAME; 110 | } 111 | 112 | /** 113 | * Get active layout handles 114 | * 115 | * @param Mage_Core_Block_Abstract 116 | * @return array 117 | */ 118 | protected function _getLayoutHandles(Mage_Core_Block_Abstract $block) 119 | { 120 | // get all layout handles of current page 121 | $handles = $block->getLayout()->getUpdate()->getHandles(); 122 | 123 | /** 124 | * skip these layout handles as they are causing to many unnecessary ESI block variants when added to the URL. 125 | */ 126 | $skipHandles = array('CATEGORY_', 'PRODUCT_', 'STORE_', 'customer_', 'THEME_', 'SHORTCUT_', 'page_','cms_', 'catalogsearch_', 'sales_order_'); 127 | foreach ($handles as $key => $val) { 128 | // remove category handle 129 | foreach ($skipHandles as $skipHandle) { 130 | if (strpos($val, $skipHandle) === 0) { 131 | unset($handles[$key]); 132 | } 133 | } 134 | } 135 | 136 | return implode(',', $handles); 137 | } 138 | 139 | /** 140 | * @return Fastly_CDN_Helper_Data 141 | */ 142 | protected function _getHelper() 143 | { 144 | return Mage::helper('fastlycdn'); 145 | } 146 | 147 | /** 148 | * @return null|array 149 | */ 150 | protected function _getAdditionalQueryParams() 151 | { 152 | return null; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/Block/Adminhtml/System/Config/Fieldset/StoreMap.php: -------------------------------------------------------------------------------- 1 | setElement($element); 35 | 36 | $html = ''; 37 | $html .= $this->_getRowTemplateHtml(-1); 38 | $html .= ''; 39 | 40 | $html .= '
'; 41 | $html .= ''; 42 | 43 | $html .= ''; 44 | $html .= ''; 45 | $html .= ''; 46 | $html .= ''; 47 | $html .= ''; 48 | 49 | if ($this->_getValue('store')) { 50 | foreach ($this->_getValue('store') as $i=>$f) { 51 | if ($i) { 52 | $html .= $this->_getRowTemplateHtml($i); 53 | } 54 | } 55 | } 56 | $html .= '
'.$this->__('Country').''.$this->__('Store').' 
'; 57 | $html .= $this->_getAddRowButtonHtml('fastlycdn_geoip_map_redirect', 58 | 'fastlycdn_geoip_map_redirect_template', $this->__('Add mapping')); 59 | $html .= '
'; 60 | 61 | return $html; 62 | } 63 | 64 | /** 65 | * @param int $i 66 | * @return string 67 | */ 68 | protected function _getRowTemplateHtml($i=0) 69 | { 70 | $html = ''; 71 | 72 | $html .= ''; 73 | $html .= ''; 74 | $html .= ''; 75 | 76 | $html .= ''; 77 | $html .= ''; 83 | $html .= ''; 84 | 85 | $html .= ''; 86 | $html .= $this->_getRemoveRowButtonHtml(); 87 | $html .= ''; 88 | 89 | $html .= ''; 90 | 91 | return $html; 92 | } 93 | 94 | /** 95 | * @return mixed 96 | */ 97 | protected function _getStore() 98 | { 99 | return Mage::getModel('Mage_Adminhtml_Model_System_Config_Source_Store')->toOptionArray(); 100 | } 101 | 102 | /** 103 | * @return string 104 | */ 105 | protected function _getDisabled() 106 | { 107 | return $this->getElement()->getDisabled() ? ' disabled' : ''; 108 | } 109 | 110 | /** 111 | * @param $key 112 | * @return mixed 113 | */ 114 | protected function _getValue($key) 115 | { 116 | return $this->getElement()->getData('value/'.$key); 117 | } 118 | 119 | /** 120 | * @param $key 121 | * @param $value 122 | * @return string 123 | */ 124 | protected function _getSelected($key, $value) 125 | { 126 | return $this->getElement()->getData('value/'.$key)==$value ? 'selected="selected"' : ''; 127 | } 128 | 129 | /** 130 | * @param $container 131 | * @param $template 132 | * @param string $title 133 | * @return mixed 134 | */ 135 | protected function _getAddRowButtonHtml($container, $template, $title='Add') 136 | { 137 | if (!isset($this->_addRowButtonHtml[$container])) { 138 | $this->_addRowButtonHtml[$container] = $this->getLayout()->createBlock('adminhtml/widget_button') 139 | ->setType('button') 140 | ->setClass('add '.$this->_getDisabled()) 141 | ->setLabel($this->__($title)) 142 | ->setOnClick("Element.insert($('".$container."'), {bottom: $('".$template."').innerHTML})") 143 | ->setDisabled($this->_getDisabled()) 144 | ->toHtml(); 145 | } 146 | return $this->_addRowButtonHtml[$container]; 147 | } 148 | 149 | /** 150 | * @param string $selector 151 | * @param string $title 152 | * @return array 153 | */ 154 | protected function _getRemoveRowButtonHtml($selector='tr', $title='Delete') 155 | { 156 | if (!$this->_removeRowButtonHtml) { 157 | $this->_removeRowButtonHtml = $this->getLayout()->createBlock('adminhtml/widget_button') 158 | ->setType('button') 159 | ->setClass('delete v-middle '.$this->_getDisabled()) 160 | ->setLabel($this->__($title)) 161 | ->setOnClick("Element.remove($(this).up('".$selector."'))") 162 | ->setDisabled($this->_getDisabled()) 163 | ->toHtml(); 164 | } 165 | return $this->_removeRowButtonHtml; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/code/community/Fastly/CDN/etc/vcl_snippets/recv.vcl: -------------------------------------------------------------------------------- 1 | # Fixup for Varnish ESI not dealing with https:// absolute URLs well 2 | if (req.is_esi_subreq && req.url ~ "/https://([^/]+)(/.*)$") { 3 | set req.http.Host = re.group.1; 4 | set req.url = re.group.2; 5 | } 6 | 7 | # Pass any checkout, cart or customer/myaccount urls 8 | if (req.url.path ~ "/(cart|checkout|customer)") { 9 | set req.http.x-pass = "1"; 10 | # Pass all admin actions 11 | } else if (req.url.path ~ "^/(index\.php/)?####ADMIN_PATH####/") { 12 | set req.http.x-pass = "1"; 13 | # bypass language switcher 14 | } else if (req.url.qs ~ "(?i)___from_store=.*&___store=.*") { 15 | set req.http.x-pass = "1"; 16 | } 17 | 18 | # set HTTPS header for offloaded TLS 19 | if (req.http.Fastly-SSL) { 20 | set req.http.Https = "on"; 21 | } 22 | 23 | if (req.http.cookie:FASTLY_CDN_ENV) { 24 | set req.http.Fastly-Cdn-Env = req.http.cookie:FASTLY_CDN_ENV; 25 | } else { 26 | unset req.http.Fastly-Cdn-Env; 27 | } 28 | 29 | ############################################################################################################ 30 | # Following code block controls purge by URL. By default we want to protect all URL purges. In general this 31 | # is addressed by adding Fastly-Purge-Requires-Auth request header in vcl_recv however this runs the risk of 32 | # exposing API tokens if user attempts to purge non-https URLs. For this reason inside the Magento module 33 | # we use X-Purge-Token. Unfortunately this breaks purge from the Fastly UI. Therefore in the next code block 34 | # we check for presence of X-Purge-Token. If it's not present we force the Fastly-Purge-Requires-Auth 35 | if (req.request == "FASTLYPURGE") { 36 | # extract token signature and expiration 37 | if (req.http.X-Purge-Token && req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) { 38 | 39 | declare local var.X-Exp STRING; 40 | declare local var.X-Sig STRING; 41 | /* extract token expiration and signature */ 42 | set var.X-Exp = re.group.1; 43 | set var.X-Sig = re.group.2; 44 | 45 | /* validate signature */ 46 | if (var.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path var.X-Exp), "^0x", "")) { 47 | /* check that expiration time has not elapsed */ 48 | if (time.is_after(now, std.integer2time(std.atoi(var.X-Exp)))) { 49 | error 410; 50 | } 51 | } else { 52 | error 403; 53 | } 54 | } else { 55 | set req.http.Fastly-Purge-Requires-Auth = "1"; 56 | } 57 | } 58 | 59 | # disable ESI processing on Origin Shield 60 | if (req.http.Fastly-FF) { 61 | set req.esi = false; 62 | # Needed for proper handling of stale while revalidated when shielding is involved 63 | set req.max_stale_while_revalidate = 0s; 64 | } else { 65 | set esi.allow_inside_cdata = true; 66 | } 67 | 68 | # static files are always cacheable. remove SSL flag and cookie 69 | if (req.url.path ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico|webp|svg)$") { 70 | unset req.http.Https; 71 | unset req.http.Cookie; 72 | } 73 | 74 | # formkey lookup 75 | if (req.url.path ~ "/fastlycdn/getformkey/") { 76 | # check if we have a formkey cookie and that it's validly formed 77 | if (req.http.Cookie:FASTLY_CDN_FORMKEY && 78 | std.strlen(req.http.Cookie:FASTLY_CDN_FORMKEY) < 40 && req.http.Cookie:FASTLY_CDN_FORMKEY ~ "^[a-zA-Z0-9-_]*$" ) { 79 | set req.http.Formkey = req.http.Cookie:FASTLY_CDN_FORMKEY; 80 | } else { 81 | # create formkey 82 | set req.http.seed = req.http.Cookie client.ip remote.port client.geo.longitude client.geo.latitude client.geo.postal_code; 83 | set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", ""); 84 | } 85 | error 760 req.http.Formkey; 86 | } 87 | 88 | # client.geo lookup 89 | if (req.url.path ~ "fastlycdn/esi/getcountry/") { 90 | # check if GeoIP has been already processed by client 91 | if (req.http.Cookie:FASTLY_CDN_GEOIP_PROCESSED) { 92 | error 200 ""; 93 | } else { 94 | # modify req.url and restart request processing 95 | error 750 client.geo.country_code; 96 | } 97 | } 98 | 99 | # client.geo get country code 100 | if (req.url.path ~ "fastlycdn/esi/getcountrycode/") { 101 | # create and set req.http.X-Country-Code 102 | error 755 client.geo.country_code; 103 | } 104 | 105 | # check for ESI calls 106 | if (req.url.qs ~ "esi_data=") { 107 | # check for valid cookie data 108 | declare local var.esi_data_field STRING; 109 | declare local var.cookie_data STRING; 110 | # Based on esi_data value requested we will need to search for cookie FASTLY_CDN- e.g. FASTLY_CDN-customer_quote 111 | set var.esi_data_field = "FASTLY_CDN-" subfield(req.url.qs, "esi_data", "&"); 112 | # We can't use variables in either subfield or regex so we need to use this workaround 113 | # to extract value of cookie that we compiled in esi_data_field 114 | set var.cookie_data = std.strstr(req.http.Cookie,var.esi_data_field); 115 | set var.cookie_data = regsub(var.cookie_data,"^[^=]*=([^;]*).*","\1"); 116 | # If found a value we replace the query string with the contents of that cookie 117 | if ( var.cookie_data != "" ) { 118 | set req.url = querystring.set(req.url, "esi_data", var.cookie_data); 119 | } 120 | } 121 | 122 | # Per suggestions in https://github.com/sdinteractive/SomethingDigital_PageCacheParams 123 | # we'll strip out query parameters used in Google AdWords, Mailchimp tracking 124 | set req.http.Magento-Original-URL = req.url; 125 | set req.url = querystring.regfilter(req.url, "^(####QUERY_PARAMETERS####)"); 126 | # Sort the query arguments to increase cache hit ratio with query arguments that 127 | # may be out of order however only on URLs that are not being passed. 128 | if ( !req.http.x-pass ) { 129 | set req.url = boltsort.sort(req.url); 130 | } 131 | --------------------------------------------------------------------------------