mirror of
https://github.com/mrclay/minify.git
synced 2025-08-14 01:54:11 +02:00
HTTP/ConditionalGet.php : + encoding option to allow ETags to vary with encoding (issue 91)
HTTP/Encoder.php : Vary is always sent (issue 101) Minify.php : Allow varying ETags based on encoding (issue 91) lots of unit test updates
This commit is contained in:
@@ -82,8 +82,11 @@ class HTTP_ConditionalGet {
|
|||||||
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
|
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
|
||||||
* will be sent with content. This is recommended.
|
* will be sent with content. This is recommended.
|
||||||
*
|
*
|
||||||
* 'eTag': (string) if given, this will be used as the ETag header rather
|
* 'encoding': (string) if set, the header "Vary: Accept-Encoding" will
|
||||||
* than values based on lastModifiedTime or contentHash.
|
* always be sent and a truncated version of the encoding will be appended
|
||||||
|
* to the ETag. E.g. "pub123456;gz". This will also trigger a more lenient
|
||||||
|
* checking of the client's If-None-Match header, as the encoding portion of
|
||||||
|
* the ETag will be stripped before comparison.
|
||||||
*
|
*
|
||||||
* 'contentHash': (string) if given, only the ETag header can be sent with
|
* 'contentHash': (string) if given, only the ETag header can be sent with
|
||||||
* content (only HTTP1.1 clients can conditionally GET). The given string
|
* content (only HTTP1.1 clients can conditionally GET). The given string
|
||||||
@@ -91,6 +94,10 @@ class HTTP_ConditionalGet {
|
|||||||
* resource changes (recommend md5()). This is not needed/used if
|
* resource changes (recommend md5()). This is not needed/used if
|
||||||
* lastModifiedTime is given.
|
* lastModifiedTime is given.
|
||||||
*
|
*
|
||||||
|
* 'eTag': (string) if given, this will be used as the ETag header rather
|
||||||
|
* than values based on lastModifiedTime or contentHash. Also the encoding
|
||||||
|
* string will not be appended to the given value as described above.
|
||||||
|
*
|
||||||
* 'invalidate': (bool) if true, the client cache will be considered invalid
|
* 'invalidate': (bool) if true, the client cache will be considered invalid
|
||||||
* without testing. Effectively this disables conditional GET.
|
* without testing. Effectively this disables conditional GET.
|
||||||
* (default false)
|
* (default false)
|
||||||
@@ -120,17 +127,28 @@ class HTTP_ConditionalGet {
|
|||||||
$_SERVER['REQUEST_TIME'] + $spec['maxAge']
|
$_SERVER['REQUEST_TIME'] + $spec['maxAge']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
$etagAppend = '';
|
||||||
|
if (isset($spec['encoding'])) {
|
||||||
|
$this->_stripEtag = true;
|
||||||
|
$this->_headers['Vary'] = 'Accept-Encoding';
|
||||||
|
if ('' !== $spec['encoding']) {
|
||||||
|
if (0 === strpos($spec['encoding'], 'x-')) {
|
||||||
|
$spec['encoding'] = substr($spec['encoding'], 2);
|
||||||
|
}
|
||||||
|
$etagAppend = ';' . substr($spec['encoding'], 0, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (isset($spec['lastModifiedTime'])) {
|
if (isset($spec['lastModifiedTime'])) {
|
||||||
$this->_setLastModified($spec['lastModifiedTime']);
|
$this->_setLastModified($spec['lastModifiedTime']);
|
||||||
if (isset($spec['eTag'])) { // Use it
|
if (isset($spec['eTag'])) { // Use it
|
||||||
$this->_setEtag($spec['eTag'], $scope);
|
$this->_setEtag($spec['eTag'], $scope);
|
||||||
} else { // base both headers on time
|
} else { // base both headers on time
|
||||||
$this->_setEtag($spec['lastModifiedTime'], $scope);
|
$this->_setEtag($spec['lastModifiedTime'] . $etagAppend, $scope);
|
||||||
}
|
}
|
||||||
} elseif (isset($spec['eTag'])) { // Use it
|
} elseif (isset($spec['eTag'])) { // Use it
|
||||||
$this->_setEtag($spec['eTag'], $scope);
|
$this->_setEtag($spec['eTag'], $scope);
|
||||||
} elseif (isset($spec['contentHash'])) { // Use the hash as the ETag
|
} elseif (isset($spec['contentHash'])) { // Use the hash as the ETag
|
||||||
$this->_setEtag($spec['contentHash'], $scope);
|
$this->_setEtag($spec['contentHash'] . $etagAppend, $scope);
|
||||||
}
|
}
|
||||||
$this->_headers['Cache-Control'] = "max-age={$maxAge}, {$scope}, must-revalidate";
|
$this->_headers['Cache-Control'] = "max-age={$maxAge}, {$scope}, must-revalidate";
|
||||||
// invalidate cache if disabled, otherwise check
|
// invalidate cache if disabled, otherwise check
|
||||||
@@ -248,12 +266,11 @@ class HTTP_ConditionalGet {
|
|||||||
protected $_headers = array();
|
protected $_headers = array();
|
||||||
protected $_lmTime = null;
|
protected $_lmTime = null;
|
||||||
protected $_etag = null;
|
protected $_etag = null;
|
||||||
|
protected $_stripEtag = false;
|
||||||
|
|
||||||
protected function _setEtag($hash, $scope)
|
protected function _setEtag($hash, $scope)
|
||||||
{
|
{
|
||||||
$this->_etag = '"' . $hash
|
$this->_etag = '"' . substr($scope, 0, 3) . $hash . '"';
|
||||||
. substr($scope, 0, 3)
|
|
||||||
. '"';
|
|
||||||
$this->_headers['ETag'] = $this->_etag;
|
$this->_headers['ETag'] = $this->_etag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,18 +303,30 @@ class HTTP_ConditionalGet {
|
|||||||
if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$cachedEtagList = get_magic_quotes_gpc()
|
$clientEtagList = get_magic_quotes_gpc()
|
||||||
? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
|
? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
|
||||||
: $_SERVER['HTTP_IF_NONE_MATCH'];
|
: $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||||
$cachedEtags = split(',', $cachedEtagList);
|
$clientEtags = split(',', $clientEtagList);
|
||||||
foreach ($cachedEtags as $cachedEtag) {
|
|
||||||
if (trim($cachedEtag) == $this->_etag) {
|
$compareTo = $this->normalizeEtag($this->_etag);
|
||||||
|
foreach ($clientEtags as $clientEtag) {
|
||||||
|
if ($this->normalizeEtag($clientEtag) === $compareTo) {
|
||||||
|
// respond with the client's matched ETag, even if it's not what
|
||||||
|
// we would've sent by default
|
||||||
|
$this->_headers['ETag'] = trim($clientEtag);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function normalizeEtag($etag) {
|
||||||
|
$etag = trim($etag);
|
||||||
|
return $this->_stripEtag
|
||||||
|
? preg_replace('/;\\w\\w"$/', '"', $etag)
|
||||||
|
: $etag;
|
||||||
|
}
|
||||||
|
|
||||||
protected function resourceNotModified()
|
protected function resourceNotModified()
|
||||||
{
|
{
|
||||||
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
||||||
@@ -308,6 +337,12 @@ class HTTP_ConditionalGet {
|
|||||||
// IE has tacked on extra data to this header, strip it
|
// IE has tacked on extra data to this header, strip it
|
||||||
$ifModifiedSince = substr($ifModifiedSince, 0, $semicolon);
|
$ifModifiedSince = substr($ifModifiedSince, 0, $semicolon);
|
||||||
}
|
}
|
||||||
return ($ifModifiedSince == self::gmtDate($this->_lmTime));
|
if ($ifModifiedSince == self::gmtDate($this->_lmTime)) {
|
||||||
|
// Apache 2.2's behavior. If there was no ETag match, send the
|
||||||
|
// non-encoded version of the ETag value.
|
||||||
|
$this->_headers['ETag'] = $this->normalizeEtag($this->_etag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,9 @@
|
|||||||
/**
|
/**
|
||||||
* Encode and send gzipped/deflated content
|
* Encode and send gzipped/deflated content
|
||||||
*
|
*
|
||||||
|
* The "Vary: Accept-Encoding" header is sent. If the client allows encoding,
|
||||||
|
* Content-Encoding and Content-Length are added.
|
||||||
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* // Send a CSS file, compressed if possible
|
* // Send a CSS file, compressed if possible
|
||||||
* $he = new HTTP_Encoder(array(
|
* $he = new HTTP_Encoder(array(
|
||||||
@@ -176,7 +179,7 @@ class HTTP_Encoder {
|
|||||||
*
|
*
|
||||||
* A syntax-aware scan is done of the Accept-Encoding, so the method must
|
* A syntax-aware scan is done of the Accept-Encoding, so the method must
|
||||||
* be non 0. The methods are favored in order of deflate, gzip, then
|
* be non 0. The methods are favored in order of deflate, gzip, then
|
||||||
* compress. Yes, deflate is always smaller and faster!
|
* compress. deflate is always smallest and generally faster!
|
||||||
*
|
*
|
||||||
* @param bool $allowCompress allow the older compress encoding
|
* @param bool $allowCompress allow the older compress encoding
|
||||||
*
|
*
|
||||||
@@ -229,8 +232,8 @@ class HTTP_Encoder {
|
|||||||
* Then the appropriate gz_* function is called to compress the content. If
|
* Then the appropriate gz_* function is called to compress the content. If
|
||||||
* this fails, false is returned.
|
* this fails, false is returned.
|
||||||
*
|
*
|
||||||
* If successful, the Content-Length header is updated, and Content-Encoding
|
* The header "Vary: Accept-Encoding" is added. If encoding is successful,
|
||||||
* and Vary headers are added.
|
* the Content-Length header is updated, and Content-Encoding is also added.
|
||||||
*
|
*
|
||||||
* @param int $compressionLevel given to zlib functions. If not given, the
|
* @param int $compressionLevel given to zlib functions. If not given, the
|
||||||
* class default will be used.
|
* class default will be used.
|
||||||
@@ -239,6 +242,7 @@ class HTTP_Encoder {
|
|||||||
*/
|
*/
|
||||||
public function encode($compressionLevel = null)
|
public function encode($compressionLevel = null)
|
||||||
{
|
{
|
||||||
|
$this->_headers['Vary'] = 'Accept-Encoding';
|
||||||
if (null === $compressionLevel) {
|
if (null === $compressionLevel) {
|
||||||
$compressionLevel = self::$compressionLevel;
|
$compressionLevel = self::$compressionLevel;
|
||||||
}
|
}
|
||||||
@@ -260,7 +264,6 @@ class HTTP_Encoder {
|
|||||||
}
|
}
|
||||||
$this->_headers['Content-Length'] = strlen($encoded);
|
$this->_headers['Content-Length'] = strlen($encoded);
|
||||||
$this->_headers['Content-Encoding'] = $this->_encodeMethod[1];
|
$this->_headers['Content-Encoding'] = $this->_encodeMethod[1];
|
||||||
$this->_headers['Vary'] = 'Accept-Encoding';
|
|
||||||
$this->_content = $encoded;
|
$this->_content = $encoded;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -94,7 +94,8 @@ class Minify {
|
|||||||
* 'quiet' : set to true to have serve() return an array rather than sending
|
* 'quiet' : set to true to have serve() return an array rather than sending
|
||||||
* any headers/output (default false)
|
* any headers/output (default false)
|
||||||
*
|
*
|
||||||
* 'encodeOutput' : to disable content encoding, set this to false (default true)
|
* 'encodeOutput' : set to false to disable content encoding, and not send
|
||||||
|
* the Vary header (default true)
|
||||||
*
|
*
|
||||||
* 'encodeMethod' : generally you should let this be determined by
|
* 'encodeMethod' : generally you should let this be determined by
|
||||||
* HTTP_Encoder (leave null), but you can force a particular encoding
|
* HTTP_Encoder (leave null), but you can force a particular encoding
|
||||||
@@ -197,11 +198,29 @@ class Minify {
|
|||||||
self::$_options['maxAge'] = 0;
|
self::$_options['maxAge'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// determine encoding
|
||||||
|
if (self::$_options['encodeOutput']) {
|
||||||
|
if (self::$_options['encodeMethod'] !== null) {
|
||||||
|
// controller specifically requested this
|
||||||
|
$contentEncoding = self::$_options['encodeMethod'];
|
||||||
|
} else {
|
||||||
|
// sniff request header
|
||||||
|
require_once 'HTTP/Encoder.php';
|
||||||
|
// depending on what the client accepts, $contentEncoding may be
|
||||||
|
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
||||||
|
// getAcceptedEncoding() with false leaves out compress as an option.
|
||||||
|
list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self::$_options['encodeMethod'] = ''; // identity (no encoding)
|
||||||
|
}
|
||||||
|
|
||||||
// check client cache
|
// check client cache
|
||||||
require_once 'HTTP/ConditionalGet.php';
|
require_once 'HTTP/ConditionalGet.php';
|
||||||
$cgOptions = array(
|
$cgOptions = array(
|
||||||
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
||||||
,'isPublic' => self::$_options['isPublic']
|
,'isPublic' => self::$_options['isPublic']
|
||||||
|
,'encoding' => self::$_options['encodeMethod']
|
||||||
);
|
);
|
||||||
if (self::$_options['maxAge'] > 0) {
|
if (self::$_options['maxAge'] > 0) {
|
||||||
$cgOptions['maxAge'] = self::$_options['maxAge'];
|
$cgOptions['maxAge'] = self::$_options['maxAge'];
|
||||||
@@ -226,23 +245,6 @@ class Minify {
|
|||||||
unset($cg);
|
unset($cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine encoding
|
|
||||||
if (self::$_options['encodeOutput']) {
|
|
||||||
if (self::$_options['encodeMethod'] !== null) {
|
|
||||||
// controller specifically requested this
|
|
||||||
$contentEncoding = self::$_options['encodeMethod'];
|
|
||||||
} else {
|
|
||||||
// sniff request header
|
|
||||||
require_once 'HTTP/Encoder.php';
|
|
||||||
// depending on what the client accepts, $contentEncoding may be
|
|
||||||
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
|
||||||
// getAcceptedEncoding() with false leaves out compress as an option.
|
|
||||||
list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self::$_options['encodeMethod'] = ''; // identity (no encoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::$_options['contentType'] === self::TYPE_CSS
|
if (self::$_options['contentType'] === self::TYPE_CSS
|
||||||
&& self::$_options['rewriteCssUris']) {
|
&& self::$_options['rewriteCssUris']) {
|
||||||
reset($controller->sources);
|
reset($controller->sources);
|
||||||
@@ -303,6 +305,8 @@ class Minify {
|
|||||||
: self::$_options['contentType'];
|
: self::$_options['contentType'];
|
||||||
if (self::$_options['encodeMethod'] !== '') {
|
if (self::$_options['encodeMethod'] !== '') {
|
||||||
$headers['Content-Encoding'] = $contentEncoding;
|
$headers['Content-Encoding'] = $contentEncoding;
|
||||||
|
}
|
||||||
|
if (self::$_options['encodeOutput']) {
|
||||||
$headers['Vary'] = 'Accept-Encoding';
|
$headers['Vary'] = 'Accept-Encoding';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__) . '/../../min/lib'));
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// emulate regularly updating document
|
// emulate regularly updating document
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__) . '/../../min/lib'));
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// generate content first (not ideal)
|
// generate content first (not ideal)
|
||||||
|
@@ -1,14 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__) . '/../../min/lib'));
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// emulate regularly updating document
|
// emulate regularly updating document
|
||||||
$every = 20;
|
$every = 20;
|
||||||
$lastModified = round(time()/$every)*$every - $every;
|
$lastModified = round(time()/$every)*$every - $every;
|
||||||
|
|
||||||
|
require 'HTTP/Encoder.php';
|
||||||
|
list($enc,) = HTTP_Encoder::getAcceptedEncoding();
|
||||||
|
|
||||||
$cg = new HTTP_ConditionalGet(array(
|
$cg = new HTTP_ConditionalGet(array(
|
||||||
'lastModifiedTime' => $lastModified
|
'lastModifiedTime' => $lastModified
|
||||||
|
,'encoding' => $enc
|
||||||
));
|
));
|
||||||
$cg->sendHeaders();
|
$cg->sendHeaders();
|
||||||
if ($cg->cacheIsValid) {
|
if ($cg->cacheIsValid) {
|
||||||
@@ -31,7 +35,6 @@ $content = get_content(array(
|
|||||||
,'explain' => $explain
|
,'explain' => $explain
|
||||||
));
|
));
|
||||||
|
|
||||||
require 'HTTP/Encoder.php';
|
|
||||||
$he = new HTTP_Encoder(array(
|
$he = new HTTP_Encoder(array(
|
||||||
'content' => get_content(array(
|
'content' => get_content(array(
|
||||||
'title' => $title
|
'title' => $title
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__) . '/../../min/lib'));
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// far expires
|
// far expires
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__) . '/../../min/lib'));
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// emulate regularly updating document
|
// emulate regularly updating document
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
ini_set('display_errors', 'on');
|
ini_set('display_errors', 'on');
|
||||||
|
|
||||||
require '../../config.php';
|
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__) . '/../../min/lib'));
|
||||||
require 'HTTP/Encoder.php';
|
require 'HTTP/Encoder.php';
|
||||||
|
|
||||||
if (!isset($_GET['test'])) {
|
if (!isset($_GET['test'])) {
|
||||||
|
@@ -16,8 +16,9 @@ function test_HTTP_ConditionalGet()
|
|||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => $gmtTime
|
,'ims' => $gmtTime
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Vary' => 'Accept-Encoding'
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime}\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
,'isValid' => true
|
,'isValid' => true
|
||||||
@@ -28,20 +29,35 @@ function test_HTTP_ConditionalGet()
|
|||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => $gmtTime . ';'
|
,'ims' => $gmtTime . ';'
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Vary' => 'Accept-Encoding'
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime}\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
,'isValid' => true
|
,'isValid' => true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'client has valid ETag'
|
'desc' => 'client has valid ETag (non-encoded version)'
|
||||||
,'inm' => "\"badEtagFoo\", \"{$lmTime}pri\""
|
,'inm' => "\"badEtagFoo\", \"pri{$lmTime}\""
|
||||||
,'ims' => null
|
,'ims' => null
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Vary' => 'Accept-Encoding'
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime}\""
|
||||||
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
|
,'isValid' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
,array(
|
||||||
|
'desc' => 'client has valid ETag (gzip version)'
|
||||||
|
,'inm' => "\"badEtagFoo\", \"pri{$lmTime};gz\""
|
||||||
|
,'ims' => null
|
||||||
|
,'exp' => array(
|
||||||
|
'Vary' => 'Accept-Encoding'
|
||||||
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime};gz\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
,'isValid' => true
|
,'isValid' => true
|
||||||
@@ -52,19 +68,21 @@ function test_HTTP_ConditionalGet()
|
|||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => null
|
,'ims' => null
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Vary' => 'Accept-Encoding'
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime};gz\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'isValid' => false
|
,'isValid' => false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'client has invalid ETag'
|
'desc' => 'client has invalid ETag'
|
||||||
,'inm' => '"' . ($lmTime - 300) . 'pri"'
|
,'inm' => '"pri' . ($lmTime - 300) . '"'
|
||||||
,'ims' => null
|
,'ims' => null
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Vary' => 'Accept-Encoding'
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime};gz\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'isValid' => false
|
,'isValid' => false
|
||||||
)
|
)
|
||||||
@@ -74,8 +92,9 @@ function test_HTTP_ConditionalGet()
|
|||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => gmdate('D, d M Y H:i:s \G\M\T', $lmTime - 300)
|
,'ims' => gmdate('D, d M Y H:i:s \G\M\T', $lmTime - 300)
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Vary' => 'Accept-Encoding'
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'Last-Modified' => $gmtTime
|
||||||
|
,'ETag' => "\"pri{$lmTime};gz\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'isValid' => false
|
,'isValid' => false
|
||||||
)
|
)
|
||||||
@@ -89,7 +108,7 @@ function test_HTTP_ConditionalGet()
|
|||||||
} else {
|
} else {
|
||||||
$_SERVER['HTTP_IF_NONE_MATCH'] = get_magic_quotes_gpc()
|
$_SERVER['HTTP_IF_NONE_MATCH'] = get_magic_quotes_gpc()
|
||||||
? addslashes($test['inm'])
|
? addslashes($test['inm'])
|
||||||
: $test['inm'];;
|
: $test['inm'];
|
||||||
}
|
}
|
||||||
if (null === $test['ims']) {
|
if (null === $test['ims']) {
|
||||||
unset($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
unset($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||||
@@ -100,6 +119,7 @@ function test_HTTP_ConditionalGet()
|
|||||||
|
|
||||||
$cg = new HTTP_ConditionalGet(array(
|
$cg = new HTTP_ConditionalGet(array(
|
||||||
'lastModifiedTime' => $lmTime
|
'lastModifiedTime' => $lmTime
|
||||||
|
,'encoding' => 'x-gzip'
|
||||||
));
|
));
|
||||||
$ret = $cg->getHeaders();
|
$ret = $cg->getHeaders();
|
||||||
$ret['isValid'] = $cg->cacheIsValid;
|
$ret['isValid'] = $cg->cacheIsValid;
|
||||||
|
@@ -128,6 +128,14 @@ function test_HTTP_Encoder()
|
|||||||
, "(off by ". abs($ret - $test['exp']) . " bytes)\n\n";
|
, "(off by ". abs($ret - $test['exp']) . " bytes)\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$_SERVER['HTTP_ACCEPT_ENCODING'] = 'identity';
|
||||||
|
$he = new HTTP_Encoder(array(
|
||||||
|
'content' => 'Hello'
|
||||||
|
));
|
||||||
|
$he->encode();
|
||||||
|
$headers = $he->getHeaders();
|
||||||
|
assertTrue(isset($headers['Vary']), 'HTTP_Encoder : Vary always sent');
|
||||||
}
|
}
|
||||||
|
|
||||||
test_HTTP_Encoder();
|
test_HTTP_Encoder();
|
||||||
|
@@ -26,8 +26,9 @@ function test_Minify()
|
|||||||
,'content' => '',
|
,'content' => '',
|
||||||
'headers' => array(
|
'headers' => array(
|
||||||
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $_SERVER['REQUEST_TIME'] + 1800),
|
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $_SERVER['REQUEST_TIME'] + 1800),
|
||||||
|
'Vary' => 'Accept-Encoding',
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"pub{$lastModified}\"",
|
||||||
'Cache-Control' => 'max-age=1800, public, must-revalidate',
|
'Cache-Control' => 'max-age=1800, public, must-revalidate',
|
||||||
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
||||||
)
|
)
|
||||||
@@ -47,10 +48,9 @@ function test_Minify()
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
! class_exists('HTTP_Encoder', false)
|
! class_exists('Minify_CSS', false)
|
||||||
&& ! class_exists('Minify_CSS', false)
|
|
||||||
&& ! class_exists('Minify_Cache', false)
|
&& ! class_exists('Minify_Cache', false)
|
||||||
,'Minify : encoding, cache, and minifier classes aren\'t loaded for 304s'
|
,'Minify : cache, and minifier classes aren\'t loaded for 304s'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test minifying JS and serving with Expires header
|
// Test minifying JS and serving with Expires header
|
||||||
@@ -67,8 +67,9 @@ function test_Minify()
|
|||||||
,'content' => $content
|
,'content' => $content
|
||||||
,'headers' => array (
|
,'headers' => array (
|
||||||
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow),
|
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow),
|
||||||
|
'Vary' => 'Accept-Encoding',
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"pub{$lastModified}\"",
|
||||||
'Cache-Control' => 'max-age=86400, public, must-revalidate',
|
'Cache-Control' => 'max-age=86400, public, must-revalidate',
|
||||||
'Content-Length' => strlen($content),
|
'Content-Length' => strlen($content),
|
||||||
'Content-Type' => 'application/x-javascript; charset=UTF-8',
|
'Content-Type' => 'application/x-javascript; charset=UTF-8',
|
||||||
@@ -181,8 +182,9 @@ function test_Minify()
|
|||||||
,'statusCode' => 200
|
,'statusCode' => 200
|
||||||
,'content' => $expectedContent
|
,'content' => $expectedContent
|
||||||
,'headers' => array (
|
,'headers' => array (
|
||||||
|
'Vary' => 'Accept-Encoding',
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"pub{$lastModified}\"",
|
||||||
'Cache-Control' => 'max-age=0, public, must-revalidate',
|
'Cache-Control' => 'max-age=0, public, must-revalidate',
|
||||||
'Content-Length' => strlen($expectedContent),
|
'Content-Length' => strlen($expectedContent),
|
||||||
'Content-Type' => 'text/css; charset=UTF-8',
|
'Content-Type' => 'text/css; charset=UTF-8',
|
||||||
|
Reference in New Issue
Block a user