VclGenerator.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\PageCache\Model\Varnish;
  7. use Magento\PageCache\Model\VclGeneratorInterface;
  8. use Magento\PageCache\Model\VclTemplateLocatorInterface;
  9. class VclGenerator implements VclGeneratorInterface
  10. {
  11. /**
  12. * @var string|null
  13. */
  14. private $backendHost;
  15. /**
  16. * @var int|null
  17. */
  18. private $backendPort;
  19. /**
  20. * @var array
  21. */
  22. private $accessList;
  23. /**
  24. * @var int|null
  25. */
  26. private $gracePeriod;
  27. /**
  28. * @var VclTemplateLocatorInterface
  29. */
  30. private $vclTemplateLocator;
  31. /**
  32. * @var string
  33. */
  34. private $sslOffloadedHeader;
  35. /**
  36. * @var array
  37. */
  38. private $designExceptions;
  39. /**
  40. * VclGenerator constructor.
  41. *
  42. * @param VclTemplateLocatorInterface $vclTemplateLocator
  43. * @param string $backendHost
  44. * @param int $backendPort
  45. * @param array $accessList
  46. * @param int $gracePeriod
  47. * @param string $sslOffloadedHeader
  48. * @param array $designExceptions
  49. */
  50. public function __construct(
  51. VclTemplateLocatorInterface $vclTemplateLocator,
  52. $backendHost,
  53. $backendPort,
  54. $accessList,
  55. $gracePeriod,
  56. $sslOffloadedHeader,
  57. $designExceptions = []
  58. ) {
  59. $this->backendHost = $backendHost;
  60. $this->backendPort = $backendPort;
  61. $this->accessList = $accessList;
  62. $this->gracePeriod = $gracePeriod;
  63. $this->vclTemplateLocator = $vclTemplateLocator;
  64. $this->sslOffloadedHeader = $sslOffloadedHeader;
  65. $this->designExceptions = $designExceptions;
  66. }
  67. /**
  68. * Return generated varnish.vcl configuration file
  69. *
  70. * @param int $version
  71. * @return string
  72. * @api
  73. */
  74. public function generateVcl($version)
  75. {
  76. $template = $this->vclTemplateLocator->getTemplate($version);
  77. return strtr($template, $this->getReplacements());
  78. }
  79. /**
  80. * Prepare data for VCL config
  81. *
  82. * @return array
  83. */
  84. private function getReplacements()
  85. {
  86. return [
  87. '/* {{ host }} */' => $this->getBackendHost(),
  88. '/* {{ port }} */' => $this->getBackendPort(),
  89. '/* {{ ips }} */' => $this->getTransformedAccessList(),
  90. '/* {{ design_exceptions_code }} */' => $this->getRegexForDesignExceptions(),
  91. // http headers get transformed by php `X-Forwarded-Proto: https`
  92. // becomes $SERVER['HTTP_X_FORWARDED_PROTO'] = 'https'
  93. // Apache and Nginx drop all headers with underlines by default.
  94. '/* {{ ssl_offloaded_header }} */' => str_replace('_', '-', $this->getSslOffloadedHeader()),
  95. '/* {{ grace_period }} */' => $this->getGracePeriod(),
  96. ];
  97. }
  98. /**
  99. * Get regexs for design exceptions
  100. * Different browser user-agents may use different themes
  101. * Varnish supports regex with internal modifiers only so
  102. * we have to convert "/pattern/iU" into "(?Ui)pattern"
  103. *
  104. * @return string
  105. */
  106. private function getRegexForDesignExceptions()
  107. {
  108. $result = '';
  109. $tpl = "%s (req.http.user-agent ~ \"%s\") {\n"." hash_data(\"%s\");\n"." }";
  110. $expressions = $this->getDesignExceptions();
  111. if ($expressions) {
  112. $rules = array_values($expressions);
  113. foreach ($rules as $i => $rule) {
  114. if (preg_match('/^[\W]{1}(.*)[\W]{1}(\w+)?$/', $rule['regexp'], $matches)) {
  115. if (!empty($matches[2])) {
  116. $pattern = sprintf("(?%s)%s", $matches[2], $matches[1]);
  117. } else {
  118. $pattern = $matches[1];
  119. }
  120. $if = $i == 0 ? 'if' : ' elsif';
  121. $result .= sprintf($tpl, $if, $pattern, $rule['value']);
  122. }
  123. }
  124. }
  125. return $result;
  126. }
  127. /**
  128. * Get IPs access list that can purge Varnish configuration for config file generation
  129. * and transform it to appropriate view
  130. *
  131. * acl purge{
  132. * "127.0.0.1";
  133. * "127.0.0.2";
  134. *
  135. * @return string
  136. */
  137. private function getTransformedAccessList()
  138. {
  139. $tpl = " \"%s\";";
  140. $result = array_reduce(
  141. $this->getAccessList(),
  142. function ($ips, $ip) use ($tpl) {
  143. return $ips.sprintf($tpl, trim($ip)) . "\n";
  144. },
  145. ''
  146. );
  147. $result = rtrim($result, "\n");
  148. return $result;
  149. }
  150. /**
  151. * Get access list
  152. *
  153. * @return array
  154. */
  155. private function getAccessList()
  156. {
  157. return $this->accessList;
  158. }
  159. /**
  160. * Get backend host
  161. *
  162. * @return string
  163. */
  164. private function getBackendHost()
  165. {
  166. return $this->backendHost;
  167. }
  168. /**
  169. * Get backend post
  170. *
  171. * @return int
  172. */
  173. private function getBackendPort()
  174. {
  175. return $this->backendPort;
  176. }
  177. /**
  178. * Get grace period
  179. *
  180. * @return int
  181. */
  182. private function getGracePeriod()
  183. {
  184. return $this->gracePeriod;
  185. }
  186. /**
  187. * Get SSL Offloaded Header
  188. *
  189. * @return string
  190. */
  191. private function getSslOffloadedHeader()
  192. {
  193. return $this->sslOffloadedHeader;
  194. }
  195. /**
  196. * @return array
  197. */
  198. private function getDesignExceptions()
  199. {
  200. return $this->designExceptions;
  201. }
  202. }