Rewrite OutputPage::addVaryHeader
authorGergő Tisza <tgr.huwiki@gmail.com>
Tue, 8 Sep 2015 21:59:45 +0000 (14:59 -0700)
committerGergő Tisza <tgr.huwiki@gmail.com>
Wed, 9 Sep 2015 22:01:45 +0000 (15:01 -0700)
Rewrite OutputPage::addVaryHeader which had a very confusing
structure.

There is one breaking change: the $option argument was declared
as array|null, but the function accepted everything and showed
inconsistent behavior; e.g.

    $op->addVaryHeader( 'Foo', 'bar' )

resulted in 'X-Vary-Options: Foo;bar' but

    $op->addVaryHeader( 'Foo' )
    $op->addVaryHeader( 'Foo', 'bar' )

resulted in 'X-Vary-Options: Foo'. With the patch, non-array
arguments (other than null) result in an error.

Change-Id: Id31d95fe27b01b00ec8a1d7a3996275fc0aacf3c

includes/OutputPage.php
tests/phpunit/includes/OutputPageTest.php

index 75dbd4c..12651d7 100644 (file)
@@ -2015,17 +2015,14 @@ class OutputPage extends ContextSource {
         *  - "list-contains=$XXX" varies on whether the header value as a
         *    comma-separated list contains $XXX as one of the list items.
         */
-       public function addVaryHeader( $header, $option = null ) {
+       public function addVaryHeader( $header, array $option = null ) {
                if ( !array_key_exists( $header, $this->mVaryHeader ) ) {
-                       $this->mVaryHeader[$header] = (array)$option;
-               } elseif ( is_array( $option ) ) {
-                       if ( is_array( $this->mVaryHeader[$header] ) ) {
-                               $this->mVaryHeader[$header] = array_merge( $this->mVaryHeader[$header], $option );
-                       } else {
-                               $this->mVaryHeader[$header] = $option;
-                       }
+                       $this->mVaryHeader[$header] = array();
+               }
+               if ( !is_array( $option ) ) {
+                       $option = array();
                }
-               $this->mVaryHeader[$header] = array_unique( (array)$this->mVaryHeader[$header] );
+               $this->mVaryHeader[$header] = array_unique( array_merge( $this->mVaryHeader[$header], $option ) );
        }
 
        /**
index ee2b278..f0d905e 100644 (file)
@@ -259,6 +259,86 @@ class OutputPageTest extends MediaWikiTestCase {
                $actualHtml = implode( "\n", $links['html'] );
                $this->assertEquals( $expectedHtml, $actualHtml );
        }
+
+       /**
+        * @dataProvider provideVaryHeaders
+        * @covers OutputPage::addVaryHeader
+        * @covers OutputPage::getVaryHeader
+        * @covers OutputPage::getXVO
+        */
+       public function testVaryHeaders( $calls, $vary, $xvo ) {
+               // get rid of default Vary fields
+               $outputPage = $this->getMockBuilder( 'OutputPage' )
+                       ->setConstructorArgs( array( new RequestContext() ) )
+                       ->setMethods( array( 'getCacheVaryCookies' ) )
+                       ->getMock();
+               $outputPage->expects( $this->any() )
+                       ->method( 'getCacheVaryCookies' )
+                       ->will( $this->returnValue( array() ) );
+               TestingAccessWrapper::newFromObject( $outputPage )->mVaryHeader = array();
+
+               foreach ( $calls as $call ) {
+                       call_user_func_array( array( $outputPage, 'addVaryHeader' ), $call );
+               }
+               $this->assertEquals( $vary, $outputPage->getVaryHeader(), 'Vary:' );
+               $this->assertEquals( $xvo, $outputPage->getXVO(), 'X-Vary-Options:' );
+       }
+
+       public function provideVaryHeaders() {
+               // note: getXVO() automatically adds Vary: Cookie
+               return array(
+                       array( // single header
+                               array(
+                                       array( 'Cookie' ),
+                               ),
+                               'Vary: Cookie',
+                               'X-Vary-Options: Cookie',
+                       ),
+                       array( // non-unique headers
+                               array(
+                                       array( 'Cookie' ),
+                                       array( 'Accept-Language' ),
+                                       array( 'Cookie' ),
+                               ),
+                               'Vary: Cookie, Accept-Language',
+                               'X-Vary-Options: Cookie,Accept-Language',
+                       ),
+                       array( // two headers with single options
+                               array(
+                                       array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+                                       array( 'Accept-Language', array( 'string-contains=en' ) ),
+                               ),
+                               'Vary: Cookie, Accept-Language',
+                               'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
+                       ),
+                       array( // one header with multiple options
+                               array(
+                                       array( 'Cookie', array( 'string-contains=phpsessid', 'string-contains=userId' ) ),
+                               ),
+                               'Vary: Cookie',
+                               'X-Vary-Options: Cookie;string-contains=phpsessid;string-contains=userId',
+                       ),
+                       array( // Duplicate option
+                               array(
+                                       array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+                                       array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+                                       array( 'Accept-Language', array( 'string-contains=en', 'string-contains=en' ) ),
+
+
+                               ),
+                               'Vary: Cookie, Accept-Language',
+                               'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
+                       ),
+                       array( // Same header, different options
+                               array(
+                                       array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+                                       array( 'Cookie', array( 'string-contains=userId' ) ),
+                               ),
+                               'Vary: Cookie',
+                               'X-Vary-Options: Cookie;string-contains=phpsessid;string-contains=userId',
+                       ),
+               );
+       }
 }
 
 /**