Esempio n. 1
0
 /**
  * Check selected RFC 7232 precondition headers
  *
  * RFC 7232 envisions a particular model where you send your request to "a
  * resource", and for write requests that you can read "the resource" by
  * changing the method to GET. When the API receives a GET request, it
  * works out even though "the resource" from RFC 7232's perspective might
  * be many resources from MediaWiki's perspective. But it totally fails for
  * a POST, since what HTTP sees as "the resource" is probably just
  * "/api.php" with all the interesting bits in the body.
  *
  * Therefore, we only support RFC 7232 precondition headers for GET (and
  * HEAD). That means we don't need to bother with If-Match and
  * If-Unmodified-Since since they only apply to modification requests.
  *
  * And since we don't support Range, If-Range is ignored too.
  *
  * @since 1.26
  * @param ApiBase $module Api module being used
  * @return bool True on success, false should exit immediately
  */
 protected function checkConditionalRequestHeaders($module)
 {
     if ($this->mInternalMode) {
         // No headers to check in internal mode
         return true;
     }
     if ($this->getRequest()->getMethod() !== 'GET' && $this->getRequest()->getMethod() !== 'HEAD') {
         // Don't check POSTs
         return true;
     }
     $return304 = false;
     $ifNoneMatch = array_diff($this->getRequest()->getHeader('If-None-Match', WebRequest::GETHEADER_LIST) ?: array(), array(''));
     if ($ifNoneMatch) {
         if ($ifNoneMatch === array('*')) {
             // API responses always "exist"
             $etag = '*';
         } else {
             $etag = $module->getConditionalRequestData('etag');
         }
     }
     if ($ifNoneMatch && $etag !== null) {
         $test = substr($etag, 0, 2) === 'W/' ? substr($etag, 2) : $etag;
         $match = array_map(function ($s) {
             return substr($s, 0, 2) === 'W/' ? substr($s, 2) : $s;
         }, $ifNoneMatch);
         $return304 = in_array($test, $match, true);
     } else {
         $value = trim($this->getRequest()->getHeader('If-Modified-Since'));
         // Some old browsers sends sizes after the date, like this:
         //  Wed, 20 Aug 2003 06:51:19 GMT; length=5202
         // Ignore that.
         $i = strpos($value, ';');
         if ($i !== false) {
             $value = trim(substr($value, 0, $i));
         }
         if ($value !== '') {
             try {
                 $ts = new MWTimestamp($value);
                 if ($ts->getTimestamp(TS_RFC2822) === $value || $ts->format('l, d-M-y H:i:s') . ' GMT' === $value || $ts->format('D M j H:i:s Y') === $value || $ts->format('D M  j H:i:s Y') === $value) {
                     $lastMod = $module->getConditionalRequestData('last-modified');
                     if ($lastMod !== null) {
                         // Mix in some MediaWiki modification times
                         $modifiedTimes = array('page' => $lastMod, 'user' => $this->getUser()->getTouched(), 'epoch' => $this->getConfig()->get('CacheEpoch'));
                         if ($this->getConfig()->get('UseSquid')) {
                             // T46570: the core page itself may not change, but resources might
                             $modifiedTimes['sepoch'] = wfTimestamp(TS_MW, time() - $this->getConfig()->get('SquidMaxage'));
                         }
                         Hooks::run('OutputPageCheckLastModified', array(&$modifiedTimes));
                         $lastMod = max($modifiedTimes);
                         $return304 = wfTimestamp(TS_MW, $lastMod) <= $ts->getTimestamp(TS_MW);
                     }
                 }
             } catch (TimestampException $e) {
                 // Invalid timestamp, ignore it
             }
         }
     }
     if ($return304) {
         $this->getRequest()->response()->statusHeader(304);
         // Avoid outputting the compressed representation of a zero-length body
         MediaWiki\suppressWarnings();
         ini_set('zlib.output_compression', 0);
         MediaWiki\restoreWarnings();
         wfClearOutputBuffers();
         return false;
     }
     return true;
 }