installed plugin W3 Total Cache
version 2.3.2
This commit is contained in:
139
wp-content/plugins/w3-total-cache/lib/Google/Http/Batch.php
Normal file
139
wp-content/plugins/w3-total-cache/lib/Google/Http/Batch.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Chirag Shah <chirags@google.com>
|
||||
*/
|
||||
class W3TCG_Google_Http_Batch
|
||||
{
|
||||
/** @var string Multipart Boundary. */
|
||||
private $boundary;
|
||||
|
||||
/** @var array service requests to be executed. */
|
||||
private $requests = array();
|
||||
|
||||
/** @var W3TCG_Google_Client */
|
||||
private $client;
|
||||
|
||||
private $expected_classes = array();
|
||||
|
||||
private $base_path;
|
||||
|
||||
public function __construct(W3TCG_Google_Client $client, $boundary = false)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->base_path = $this->client->getBasePath();
|
||||
$this->expected_classes = array();
|
||||
$boundary = (false == $boundary) ? mt_rand() : $boundary;
|
||||
$this->boundary = str_replace('"', '', $boundary);
|
||||
}
|
||||
|
||||
public function add(W3TCG_Google_Http_Request $request, $key = false)
|
||||
{
|
||||
if (false == $key) {
|
||||
$key = mt_rand();
|
||||
}
|
||||
|
||||
$this->requests[$key] = $request;
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$body = '';
|
||||
|
||||
/** @var W3TCG_Google_Http_Request $req */
|
||||
foreach ($this->requests as $key => $req) {
|
||||
$body .= "--{$this->boundary}\n";
|
||||
$body .= $req->toBatchString($key) . "\n";
|
||||
$this->expected_classes["response-" . $key] = $req->getExpectedClass();
|
||||
}
|
||||
|
||||
$body = rtrim($body);
|
||||
$body .= "\n--{$this->boundary}--";
|
||||
|
||||
$url = $this->base_path . '/batch';
|
||||
$httpRequest = new W3TCG_Google_Http_Request($url, 'POST');
|
||||
$httpRequest->setRequestHeaders(
|
||||
array('Content-Type' => 'multipart/mixed; boundary=' . $this->boundary)
|
||||
);
|
||||
|
||||
$httpRequest->setPostBody($body);
|
||||
$response = $this->client->getIo()->makeRequest($httpRequest);
|
||||
|
||||
return $this->parseResponse($response);
|
||||
}
|
||||
|
||||
public function parseResponse(W3TCG_Google_Http_Request $response)
|
||||
{
|
||||
$contentType = $response->getResponseHeader('content-type');
|
||||
$contentType = explode(';', $contentType);
|
||||
$boundary = false;
|
||||
foreach ($contentType as $part) {
|
||||
$part = (explode('=', $part, 2));
|
||||
if (isset($part[0]) && 'boundary' == trim($part[0])) {
|
||||
$boundary = $part[1];
|
||||
}
|
||||
}
|
||||
|
||||
$body = $response->getResponseBody();
|
||||
if ($body) {
|
||||
$body = str_replace("--$boundary--", "--$boundary", $body);
|
||||
$parts = explode("--$boundary", $body);
|
||||
$responses = array();
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$part = trim($part);
|
||||
if (!empty($part)) {
|
||||
list($metaHeaders, $part) = explode("\r\n\r\n", $part, 2);
|
||||
$metaHeaders = $this->client->getIo()->getHttpResponseHeaders($metaHeaders);
|
||||
|
||||
$status = substr($part, 0, strpos($part, "\n"));
|
||||
$status = explode(" ", $status);
|
||||
$status = $status[1];
|
||||
|
||||
list($partHeaders, $partBody) = $this->client->getIo()->ParseHttpResponse($part, false);
|
||||
$response = new W3TCG_Google_Http_Request("");
|
||||
$response->setResponseHttpCode($status);
|
||||
$response->setResponseHeaders($partHeaders);
|
||||
$response->setResponseBody($partBody);
|
||||
|
||||
// Need content id.
|
||||
$key = $metaHeaders['content-id'];
|
||||
|
||||
if (isset($this->expected_classes[$key]) &&
|
||||
strlen($this->expected_classes[$key]) > 0) {
|
||||
$class = $this->expected_classes[$key];
|
||||
$response->setExpectedClass($class);
|
||||
}
|
||||
|
||||
try {
|
||||
$response = W3TCG_Google_Http_REST::decodeHttpResponse($response);
|
||||
$responses[$key] = $response;
|
||||
} catch (W3TCG_Google_Service_Exception $e) {
|
||||
// Store the exception as the response, so succesful responses
|
||||
// can be processed.
|
||||
$responses[$key] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implement the caching directives specified in rfc2616. This
|
||||
* implementation is guided by the guidance offered in rfc2616-sec13.
|
||||
* @author Chirag Shah <chirags@google.com>
|
||||
*/
|
||||
class W3TCG_Google_Http_CacheParser
|
||||
{
|
||||
public static $CACHEABLE_HTTP_METHODS = array('GET', 'HEAD');
|
||||
public static $CACHEABLE_STATUS_CODES = array('200', '203', '300', '301');
|
||||
|
||||
/**
|
||||
* Check if an HTTP request can be cached by a private local cache.
|
||||
*
|
||||
* @static
|
||||
* @param W3TCG_Google_Http_Request $resp
|
||||
* @return bool True if the request is cacheable.
|
||||
* False if the request is uncacheable.
|
||||
*/
|
||||
public static function isRequestCacheable(W3TCG_Google_Http_Request $resp)
|
||||
{
|
||||
$method = $resp->getRequestMethod();
|
||||
if (! in_array($method, self::$CACHEABLE_HTTP_METHODS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't cache authorized requests/responses.
|
||||
// [rfc2616-14.8] When a shared cache receives a request containing an
|
||||
// Authorization field, it MUST NOT return the corresponding response
|
||||
// as a reply to any other request...
|
||||
if ($resp->getRequestHeader("authorization")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an HTTP response can be cached by a private local cache.
|
||||
*
|
||||
* @static
|
||||
* @param W3TCG_Google_Http_Request $resp
|
||||
* @return bool True if the response is cacheable.
|
||||
* False if the response is un-cacheable.
|
||||
*/
|
||||
public static function isResponseCacheable(W3TCG_Google_Http_Request $resp)
|
||||
{
|
||||
// First, check if the HTTP request was cacheable before inspecting the
|
||||
// HTTP response.
|
||||
if (false == self::isRequestCacheable($resp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$code = $resp->getResponseHttpCode();
|
||||
if (! in_array($code, self::$CACHEABLE_STATUS_CODES)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The resource is uncacheable if the resource is already expired and
|
||||
// the resource doesn't have an ETag for revalidation.
|
||||
$etag = $resp->getResponseHeader("etag");
|
||||
if (self::isExpired($resp) && $etag == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// [rfc2616-14.9.2] If [no-store is] sent in a response, a cache MUST NOT
|
||||
// store any part of either this response or the request that elicited it.
|
||||
$cacheControl = $resp->getParsedCacheControl();
|
||||
if (isset($cacheControl['no-store'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pragma: no-cache is an http request directive, but is occasionally
|
||||
// used as a response header incorrectly.
|
||||
$pragma = $resp->getResponseHeader('pragma');
|
||||
if ($pragma == 'no-cache' || strpos($pragma, 'no-cache') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// [rfc2616-14.44] Vary: * is extremely difficult to cache. "It implies that
|
||||
// a cache cannot determine from the request headers of a subsequent request
|
||||
// whether this response is the appropriate representation."
|
||||
// Given this, we deem responses with the Vary header as uncacheable.
|
||||
$vary = $resp->getResponseHeader('vary');
|
||||
if ($vary) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param W3TCG_Google_Http_Request $resp
|
||||
* @return bool True if the HTTP response is considered to be expired.
|
||||
* False if it is considered to be fresh.
|
||||
*/
|
||||
public static function isExpired(W3TCG_Google_Http_Request $resp)
|
||||
{
|
||||
// HTTP/1.1 clients and caches MUST treat other invalid date formats,
|
||||
// especially including the value “0”, as in the past.
|
||||
$parsedExpires = false;
|
||||
$responseHeaders = $resp->getResponseHeaders();
|
||||
|
||||
if (isset($responseHeaders['expires'])) {
|
||||
$rawExpires = $responseHeaders['expires'];
|
||||
// Check for a malformed expires header first.
|
||||
if (empty($rawExpires) || (is_numeric($rawExpires) && $rawExpires <= 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if we can parse the expires header.
|
||||
$parsedExpires = strtotime($rawExpires);
|
||||
if (false == $parsedExpires || $parsedExpires <= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the freshness of an http response.
|
||||
$freshnessLifetime = false;
|
||||
$cacheControl = $resp->getParsedCacheControl();
|
||||
if (isset($cacheControl['max-age'])) {
|
||||
$freshnessLifetime = $cacheControl['max-age'];
|
||||
}
|
||||
|
||||
$rawDate = $resp->getResponseHeader('date');
|
||||
$parsedDate = strtotime($rawDate);
|
||||
|
||||
if (empty($rawDate) || false == $parsedDate) {
|
||||
// We can't default this to now, as that means future cache reads
|
||||
// will always pass with the logic below, so we will require a
|
||||
// date be injected if not supplied.
|
||||
throw new W3TCG_Google_Exception("All cacheable requests must have creation dates.");
|
||||
}
|
||||
|
||||
if (false == $freshnessLifetime && isset($responseHeaders['expires'])) {
|
||||
$freshnessLifetime = $parsedExpires - $parsedDate;
|
||||
}
|
||||
|
||||
if (false == $freshnessLifetime) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the age of an http response.
|
||||
$age = max(0, time() - $parsedDate);
|
||||
if (isset($responseHeaders['age'])) {
|
||||
$age = max($age, strtotime($responseHeaders['age']));
|
||||
}
|
||||
|
||||
return $freshnessLifetime <= $age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a cache entry should be revalidated with by the origin.
|
||||
*
|
||||
* @param W3TCG_Google_Http_Request $response
|
||||
* @return bool True if the entry is expired, else return false.
|
||||
*/
|
||||
public static function mustRevalidate(W3TCG_Google_Http_Request $response)
|
||||
{
|
||||
// [13.3] When a cache has a stale entry that it would like to use as a
|
||||
// response to a client's request, it first has to check with the origin
|
||||
// server to see if its cached entry is still usable.
|
||||
return self::isExpired($response);
|
||||
}
|
||||
}
|
@ -0,0 +1,295 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Chirag Shah <chirags@google.com>
|
||||
*
|
||||
*/
|
||||
class W3TCG_Google_Http_MediaFileUpload
|
||||
{
|
||||
const UPLOAD_MEDIA_TYPE = 'media';
|
||||
const UPLOAD_MULTIPART_TYPE = 'multipart';
|
||||
const UPLOAD_RESUMABLE_TYPE = 'resumable';
|
||||
|
||||
/** @var string $mimeType */
|
||||
private $mimeType;
|
||||
|
||||
/** @var string $data */
|
||||
private $data;
|
||||
|
||||
/** @var bool $resumable */
|
||||
private $resumable;
|
||||
|
||||
/** @var int $chunkSize */
|
||||
private $chunkSize;
|
||||
|
||||
/** @var int $size */
|
||||
private $size;
|
||||
|
||||
/** @var string $resumeUri */
|
||||
private $resumeUri;
|
||||
|
||||
/** @var int $progress */
|
||||
private $progress;
|
||||
|
||||
/** @var W3TCG_Google_Client */
|
||||
private $client;
|
||||
|
||||
/** @var W3TCG_Google_Http_Request */
|
||||
private $request;
|
||||
|
||||
/** @var string */
|
||||
private $boundary;
|
||||
|
||||
/**
|
||||
* Result code from last HTTP call
|
||||
* @var int
|
||||
*/
|
||||
private $httpResultCode;
|
||||
|
||||
/**
|
||||
* @param $mimeType string
|
||||
* @param $data string The bytes you want to upload.
|
||||
* @param $resumable bool
|
||||
* @param bool $chunkSize File will be uploaded in chunks of this many bytes.
|
||||
* only used if resumable=True
|
||||
*/
|
||||
public function __construct(
|
||||
W3TCG_Google_Client $client,
|
||||
W3TCG_Google_Http_Request $request,
|
||||
$mimeType,
|
||||
$data,
|
||||
$resumable = false,
|
||||
$chunkSize = false,
|
||||
$boundary = false
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->request = $request;
|
||||
$this->mimeType = $mimeType;
|
||||
$this->data = $data;
|
||||
$this->size = strlen($this->data);
|
||||
$this->resumable = $resumable;
|
||||
if (!$chunkSize) {
|
||||
$chunkSize = 256 * 1024;
|
||||
}
|
||||
$this->chunkSize = $chunkSize;
|
||||
$this->progress = 0;
|
||||
$this->boundary = $boundary;
|
||||
|
||||
// Process Media Request
|
||||
$this->process();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the file that is being uploaded.
|
||||
* @param $size - int file size in bytes
|
||||
*/
|
||||
public function setFileSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the progress on the upload
|
||||
* @return int progress in bytes uploaded.
|
||||
*/
|
||||
public function getProgress()
|
||||
{
|
||||
return $this->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP result code from the last call made.
|
||||
* @return int code
|
||||
*/
|
||||
public function getHttpResultCode()
|
||||
{
|
||||
return $this->httpResultCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the next part of the file to upload.
|
||||
* @param [$chunk] the next set of bytes to send. If false will used $data passed
|
||||
* at construct time.
|
||||
*/
|
||||
public function nextChunk($chunk = false)
|
||||
{
|
||||
if (false == $this->resumeUri) {
|
||||
$this->resumeUri = $this->getResumeUri();
|
||||
}
|
||||
|
||||
if (false == $chunk) {
|
||||
$chunk = substr($this->data, $this->progress, $this->chunkSize);
|
||||
}
|
||||
|
||||
$lastBytePos = $this->progress + strlen($chunk) - 1;
|
||||
$headers = array(
|
||||
'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
|
||||
'content-type' => $this->request->getRequestHeader('content-type'),
|
||||
'content-length' => $this->chunkSize,
|
||||
'expect' => '',
|
||||
);
|
||||
|
||||
$httpRequest = new W3TCG_Google_Http_Request(
|
||||
$this->resumeUri,
|
||||
'PUT',
|
||||
$headers,
|
||||
$chunk
|
||||
);
|
||||
|
||||
if ($this->client->getClassConfig("W3TCG_Google_Http_Request", "enable_gzip_for_uploads")) {
|
||||
$httpRequest->enableGzip();
|
||||
} else {
|
||||
$httpRequest->disableGzip();
|
||||
}
|
||||
|
||||
$response = $this->client->getIo()->makeRequest($httpRequest);
|
||||
$response->setExpectedClass($this->request->getExpectedClass());
|
||||
$code = $response->getResponseHttpCode();
|
||||
$this->httpResultCode = $code;
|
||||
|
||||
if (308 == $code) {
|
||||
// Track the amount uploaded.
|
||||
$range = explode('-', $response->getResponseHeader('range'));
|
||||
$this->progress = $range[1] + 1;
|
||||
|
||||
// Allow for changing upload URLs.
|
||||
$location = $response->getResponseHeader('location');
|
||||
if ($location) {
|
||||
$this->resumeUri = $location;
|
||||
}
|
||||
|
||||
// No problems, but upload not complete.
|
||||
return false;
|
||||
} else {
|
||||
return W3TCG_Google_Http_REST::decodeHttpResponse($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $meta
|
||||
* @param $params
|
||||
* @return array|bool
|
||||
* @visible for testing
|
||||
*/
|
||||
private function process()
|
||||
{
|
||||
$postBody = false;
|
||||
$contentType = false;
|
||||
|
||||
$meta = $this->request->getPostBody();
|
||||
$meta = is_string($meta) ? json_decode($meta, true) : $meta;
|
||||
|
||||
$uploadType = $this->getUploadType($meta);
|
||||
$this->request->setQueryParam('uploadType', $uploadType);
|
||||
$this->transformToUploadUrl();
|
||||
$mimeType = $this->mimeType ?
|
||||
$this->mimeType :
|
||||
$this->request->getRequestHeader('content-type');
|
||||
|
||||
if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = is_string($meta) ? $meta : json_encode($meta);
|
||||
} else if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = $this->data;
|
||||
} else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
|
||||
// This is a multipart/related upload.
|
||||
$boundary = $this->boundary ? $this->boundary : mt_rand();
|
||||
$boundary = str_replace('"', '', $boundary);
|
||||
$contentType = 'multipart/related; boundary=' . $boundary;
|
||||
$related = "--$boundary\r\n";
|
||||
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
|
||||
$related .= "\r\n" . json_encode($meta) . "\r\n";
|
||||
$related .= "--$boundary\r\n";
|
||||
$related .= "Content-Type: $mimeType\r\n";
|
||||
$related .= "Content-Transfer-Encoding: base64\r\n";
|
||||
$related .= "\r\n" . base64_encode($this->data) . "\r\n";
|
||||
$related .= "--$boundary--";
|
||||
$postBody = $related;
|
||||
}
|
||||
|
||||
$this->request->setPostBody($postBody);
|
||||
|
||||
if (isset($contentType) && $contentType) {
|
||||
$contentTypeHeader['content-type'] = $contentType;
|
||||
$this->request->setRequestHeaders($contentTypeHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private function transformToUploadUrl()
|
||||
{
|
||||
$base = $this->request->getBaseComponent();
|
||||
$this->request->setBaseComponent($base . '/upload');
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid upload types:
|
||||
* - resumable (UPLOAD_RESUMABLE_TYPE)
|
||||
* - media (UPLOAD_MEDIA_TYPE)
|
||||
* - multipart (UPLOAD_MULTIPART_TYPE)
|
||||
* @param $meta
|
||||
* @return string
|
||||
* @visible for testing
|
||||
*/
|
||||
public function getUploadType($meta)
|
||||
{
|
||||
if ($this->resumable) {
|
||||
return self::UPLOAD_RESUMABLE_TYPE;
|
||||
}
|
||||
|
||||
if (false == $meta && $this->data) {
|
||||
return self::UPLOAD_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
return self::UPLOAD_MULTIPART_TYPE;
|
||||
}
|
||||
|
||||
private function getResumeUri()
|
||||
{
|
||||
$result = null;
|
||||
$body = $this->request->getPostBody();
|
||||
if ($body) {
|
||||
$headers = array(
|
||||
'content-type' => 'application/json; charset=UTF-8',
|
||||
'content-length' => W3TCG_Google_Utils::getStrLen($body),
|
||||
'x-upload-content-type' => $this->mimeType,
|
||||
'x-upload-content-length' => $this->size,
|
||||
'expect' => '',
|
||||
);
|
||||
$this->request->setRequestHeaders($headers);
|
||||
}
|
||||
|
||||
$response = $this->client->getIo()->makeRequest($this->request);
|
||||
$location = $response->getResponseHeader('location');
|
||||
$code = $response->getResponseHttpCode();
|
||||
|
||||
if (200 == $code && true == $location) {
|
||||
return $location;
|
||||
}
|
||||
$message = $code;
|
||||
$body = @json_decode($response->getResponseBody());
|
||||
if (!empty( $body->error->errors ) ) {
|
||||
$message .= ': ';
|
||||
foreach ($body->error->errors as $error) {
|
||||
$message .= "{$error->domain}, {$error->message};";
|
||||
}
|
||||
$message = rtrim($message, ';');
|
||||
}
|
||||
throw new W3TCG_Google_Exception("Failed to start the resumable upload (HTTP {$message})");
|
||||
}
|
||||
}
|
134
wp-content/plugins/w3-total-cache/lib/Google/Http/REST.php
Normal file
134
wp-content/plugins/w3-total-cache/lib/Google/Http/REST.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class implements the RESTful transport of apiServiceRequest()'s
|
||||
*
|
||||
* @author Chris Chabot <chabotc@google.com>
|
||||
* @author Chirag Shah <chirags@google.com>
|
||||
*/
|
||||
class W3TCG_Google_Http_REST
|
||||
{
|
||||
/**
|
||||
* Executes a W3TCG_Google_Http_Request
|
||||
*
|
||||
* @param W3TCG_Google_Client $client
|
||||
* @param W3TCG_Google_Http_Request $req
|
||||
* @return array decoded result
|
||||
* @throws W3TCG_Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function execute(W3TCG_Google_Client $client, W3TCG_Google_Http_Request $req)
|
||||
{
|
||||
$httpRequest = $client->getIo()->makeRequest($req);
|
||||
$httpRequest->setExpectedClass($req->getExpectedClass());
|
||||
return self::decodeHttpResponse($httpRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an HTTP Response.
|
||||
* @static
|
||||
* @throws W3TCG_Google_Service_Exception
|
||||
* @param W3TCG_Google_Http_Request $response The http response to be decoded.
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function decodeHttpResponse($response)
|
||||
{
|
||||
$code = $response->getResponseHttpCode();
|
||||
$body = $response->getResponseBody();
|
||||
$decoded = null;
|
||||
|
||||
if ((intVal($code)) >= 300) {
|
||||
$decoded = json_decode($body, true);
|
||||
$err = 'Error calling ' . $response->getRequestMethod() . ' ' . $response->getUrl();
|
||||
if (isset($decoded['error']) &&
|
||||
isset($decoded['error']['message']) &&
|
||||
isset($decoded['error']['code'])) {
|
||||
// if we're getting a json encoded error definition, use that instead of the raw response
|
||||
// body for improved readability
|
||||
$err .= ": ({$decoded['error']['code']}) {$decoded['error']['message']}";
|
||||
} else {
|
||||
$err .= ": ($code) $body";
|
||||
}
|
||||
|
||||
$errors = null;
|
||||
// Specific check for APIs which don't return error details, such as Blogger.
|
||||
if (isset($decoded['error']) && isset($decoded['error']['errors'])) {
|
||||
$errors = $decoded['error']['errors'];
|
||||
}
|
||||
|
||||
throw new W3TCG_Google_Service_Exception($err, $code, null, $errors);
|
||||
}
|
||||
|
||||
// Only attempt to decode the response, if the response code wasn't (204) 'no content'
|
||||
if ($code != '204') {
|
||||
$decoded = json_decode($body, true);
|
||||
if ($decoded === null || $decoded === "") {
|
||||
throw new W3TCG_Google_Service_Exception("Invalid json in service response: $body");
|
||||
}
|
||||
|
||||
if ($response->getExpectedClass()) {
|
||||
$class = $response->getExpectedClass();
|
||||
$decoded = new $class($decoded);
|
||||
}
|
||||
}
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse/expand request parameters and create a fully qualified
|
||||
* request uri.
|
||||
* @static
|
||||
* @param string $servicePath
|
||||
* @param string $restPath
|
||||
* @param array $params
|
||||
* @return string $requestUrl
|
||||
*/
|
||||
public static function createRequestUri($servicePath, $restPath, $params)
|
||||
{
|
||||
$requestUrl = $servicePath . $restPath;
|
||||
$uriTemplateVars = array();
|
||||
$queryVars = array();
|
||||
foreach ($params as $paramName => $paramSpec) {
|
||||
if ($paramSpec['type'] == 'boolean') {
|
||||
$paramSpec['value'] = ($paramSpec['value']) ? 'true' : 'false';
|
||||
}
|
||||
if ($paramSpec['location'] == 'path') {
|
||||
$uriTemplateVars[$paramName] = $paramSpec['value'];
|
||||
} else if ($paramSpec['location'] == 'query') {
|
||||
if (isset($paramSpec['repeated']) && is_array($paramSpec['value'])) {
|
||||
foreach ($paramSpec['value'] as $value) {
|
||||
$queryVars[] = $paramName . '=' . rawurlencode($value);
|
||||
}
|
||||
} else {
|
||||
$queryVars[] = $paramName . '=' . rawurlencode($paramSpec['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($uriTemplateVars)) {
|
||||
$uriTemplateParser = new W3TCG_Google_Utils_URITemplate();
|
||||
$requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
|
||||
}
|
||||
|
||||
if (count($queryVars)) {
|
||||
$requestUrl .= '?' . implode($queryVars, '&');
|
||||
}
|
||||
|
||||
return $requestUrl;
|
||||
}
|
||||
}
|
474
wp-content/plugins/w3-total-cache/lib/Google/Http/Request.php
Normal file
474
wp-content/plugins/w3-total-cache/lib/Google/Http/Request.php
Normal file
@ -0,0 +1,474 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HTTP Request to be executed by IO classes. Upon execution, the
|
||||
* responseHttpCode, responseHeaders and responseBody will be filled in.
|
||||
*
|
||||
* @author Chris Chabot <chabotc@google.com>
|
||||
* @author Chirag Shah <chirags@google.com>
|
||||
*
|
||||
*/
|
||||
class W3TCG_Google_Http_Request
|
||||
{
|
||||
const GZIP_UA = " (gzip)";
|
||||
|
||||
private $batchHeaders = array(
|
||||
'Content-Type' => 'application/http',
|
||||
'Content-Transfer-Encoding' => 'binary',
|
||||
'MIME-Version' => '1.0',
|
||||
);
|
||||
|
||||
protected $queryParams;
|
||||
protected $requestMethod;
|
||||
protected $requestHeaders;
|
||||
protected $baseComponent = null;
|
||||
protected $path;
|
||||
protected $postBody;
|
||||
protected $userAgent;
|
||||
protected $canGzip = null;
|
||||
|
||||
protected $responseHttpCode;
|
||||
protected $responseHeaders;
|
||||
protected $responseBody;
|
||||
|
||||
protected $expectedClass;
|
||||
|
||||
public $accessKey;
|
||||
|
||||
public function __construct(
|
||||
$url,
|
||||
$method = 'GET',
|
||||
$headers = array(),
|
||||
$postBody = null
|
||||
) {
|
||||
$this->setUrl($url);
|
||||
$this->setRequestMethod($method);
|
||||
$this->setRequestHeaders($headers);
|
||||
$this->setPostBody($postBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Misc function that returns the base url component of the $url
|
||||
* used by the OAuth signing class to calculate the base string
|
||||
* @return string The base url component of the $url.
|
||||
*/
|
||||
public function getBaseComponent()
|
||||
{
|
||||
return $this->baseComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base URL that path and query parameters will be added to.
|
||||
* @param $baseComponent string
|
||||
*/
|
||||
public function setBaseComponent($baseComponent)
|
||||
{
|
||||
$this->baseComponent = $baseComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable support for gzipped responses with this request.
|
||||
*/
|
||||
public function enableGzip()
|
||||
{
|
||||
$this->setRequestHeaders(array("Accept-Encoding" => "gzip"));
|
||||
$this->canGzip = true;
|
||||
$this->setUserAgent($this->userAgent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable support for gzip responses with this request.
|
||||
*/
|
||||
public function disableGzip()
|
||||
{
|
||||
if (
|
||||
isset($this->requestHeaders['accept-encoding']) &&
|
||||
$this->requestHeaders['accept-encoding'] == "gzip"
|
||||
) {
|
||||
unset($this->requestHeaders['accept-encoding']);
|
||||
}
|
||||
$this->canGzip = false;
|
||||
$this->userAgent = str_replace(self::GZIP_UA, "", $this->userAgent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this request accept a gzip response?
|
||||
* @return bool
|
||||
*/
|
||||
public function canGzip()
|
||||
{
|
||||
return $this->canGzip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Misc function that returns an array of the query parameters of the current
|
||||
* url used by the OAuth signing class to calculate the signature
|
||||
* @return array Query parameters in the query string.
|
||||
*/
|
||||
public function getQueryParams()
|
||||
{
|
||||
return $this->queryParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new query parameter.
|
||||
* @param $key - string to set, does not need to be URL encoded
|
||||
* @param $value - string to set, does not need to be URL encoded
|
||||
*/
|
||||
public function setQueryParam($key, $value)
|
||||
{
|
||||
$this->queryParams[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string HTTP Response Code.
|
||||
*/
|
||||
public function getResponseHttpCode()
|
||||
{
|
||||
return (int) $this->responseHttpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $responseHttpCode HTTP Response Code.
|
||||
*/
|
||||
public function setResponseHttpCode($responseHttpCode)
|
||||
{
|
||||
$this->responseHttpCode = $responseHttpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $responseHeaders (array) HTTP Response Headers.
|
||||
*/
|
||||
public function getResponseHeaders()
|
||||
{
|
||||
return $this->responseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string HTTP Response Body
|
||||
*/
|
||||
public function getResponseBody()
|
||||
{
|
||||
return $this->responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class the response to this request should expect.
|
||||
*
|
||||
* @param $class string the class name
|
||||
*/
|
||||
public function setExpectedClass($class)
|
||||
{
|
||||
$this->expectedClass = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the expected class the response should expect.
|
||||
* @return string class name
|
||||
*/
|
||||
public function getExpectedClass()
|
||||
{
|
||||
return $this->expectedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers The HTTP response headers
|
||||
* to be normalized.
|
||||
*/
|
||||
public function setResponseHeaders($headers)
|
||||
{
|
||||
$headers = W3TCG_Google_Utils::normalize($headers);
|
||||
if ($this->responseHeaders) {
|
||||
$headers = array_merge($this->responseHeaders, $headers);
|
||||
}
|
||||
|
||||
$this->responseHeaders = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array|boolean Returns the requested HTTP header or
|
||||
* false if unavailable.
|
||||
*/
|
||||
public function getResponseHeader($key)
|
||||
{
|
||||
return isset($this->responseHeaders[$key])
|
||||
? $this->responseHeaders[$key]
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $responseBody The HTTP response body.
|
||||
*/
|
||||
public function setResponseBody($responseBody)
|
||||
{
|
||||
$this->responseBody = $responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string $url The request URL.
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->baseComponent . $this->path .
|
||||
(count($this->queryParams) ?
|
||||
"?" . $this->buildQuery($this->queryParams) :
|
||||
'');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string $method HTTP Request Method.
|
||||
*/
|
||||
public function getRequestMethod()
|
||||
{
|
||||
return $this->requestMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array $headers HTTP Request Headers.
|
||||
*/
|
||||
public function getRequestHeaders()
|
||||
{
|
||||
return $this->requestHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array|boolean Returns the requested HTTP header or
|
||||
* false if unavailable.
|
||||
*/
|
||||
public function getRequestHeader($key)
|
||||
{
|
||||
return isset($this->requestHeaders[$key])
|
||||
? $this->requestHeaders[$key]
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string $postBody HTTP Request Body.
|
||||
*/
|
||||
public function getPostBody()
|
||||
{
|
||||
return $this->postBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url the url to set
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
if (substr($url, 0, 4) != 'http') {
|
||||
// Force the path become relative.
|
||||
if (substr($url, 0, 1) !== '/') {
|
||||
$url = '/' . $url;
|
||||
}
|
||||
}
|
||||
$parts = parse_url($url);
|
||||
if (isset($parts['host'])) {
|
||||
$this->baseComponent = sprintf(
|
||||
"%s%s%s",
|
||||
isset($parts['scheme']) ? $parts['scheme'] . "://" : '',
|
||||
isset($parts['host']) ? $parts['host'] : '',
|
||||
isset($parts['port']) ? ":" . $parts['port'] : ''
|
||||
);
|
||||
}
|
||||
$this->path = isset($parts['path']) ? $parts['path'] : '';
|
||||
$this->queryParams = array();
|
||||
if (isset($parts['query'])) {
|
||||
$this->queryParams = $this->parseQuery($parts['query']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method Set he HTTP Method and normalize
|
||||
* it to upper-case, as required by HTTP.
|
||||
*
|
||||
*/
|
||||
public function setRequestMethod($method)
|
||||
{
|
||||
$this->requestMethod = strtoupper($method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers The HTTP request headers
|
||||
* to be set and normalized.
|
||||
*/
|
||||
public function setRequestHeaders($headers)
|
||||
{
|
||||
$headers = W3TCG_Google_Utils::normalize($headers);
|
||||
if ($this->requestHeaders) {
|
||||
$headers = array_merge($this->requestHeaders, $headers);
|
||||
}
|
||||
$this->requestHeaders = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $postBody the postBody to set
|
||||
*/
|
||||
public function setPostBody($postBody)
|
||||
{
|
||||
$this->postBody = $postBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the User-Agent Header.
|
||||
* @param string $userAgent The User-Agent.
|
||||
*/
|
||||
public function setUserAgent($userAgent)
|
||||
{
|
||||
$this->userAgent = $userAgent;
|
||||
if ($this->canGzip) {
|
||||
$this->userAgent = $userAgent . self::GZIP_UA;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The User-Agent.
|
||||
*/
|
||||
public function getUserAgent()
|
||||
{
|
||||
return $this->userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cache key depending on if this was an OAuth signed request
|
||||
* in which case it will use the non-signed url and access key to make this
|
||||
* cache key unique per authenticated user, else use the plain request url
|
||||
* @return string The md5 hash of the request cache key.
|
||||
*/
|
||||
public function getCacheKey()
|
||||
{
|
||||
$key = $this->getUrl();
|
||||
|
||||
if (isset($this->accessKey)) {
|
||||
$key .= $this->accessKey;
|
||||
}
|
||||
|
||||
if (isset($this->requestHeaders['authorization'])) {
|
||||
$key .= $this->requestHeaders['authorization'];
|
||||
}
|
||||
|
||||
return md5($key);
|
||||
}
|
||||
|
||||
public function getParsedCacheControl()
|
||||
{
|
||||
$parsed = array();
|
||||
$rawCacheControl = $this->getResponseHeader('cache-control');
|
||||
if ($rawCacheControl) {
|
||||
$rawCacheControl = str_replace(', ', '&', $rawCacheControl);
|
||||
parse_str($rawCacheControl, $parsed);
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return string A string representation of the HTTP Request.
|
||||
*/
|
||||
public function toBatchString($id)
|
||||
{
|
||||
$str = '';
|
||||
$path = parse_url($this->getUrl(), PHP_URL_PATH) . "?" .
|
||||
http_build_query($this->queryParams);
|
||||
$str .= $this->getRequestMethod() . ' ' . $path . " HTTP/1.1\n";
|
||||
|
||||
foreach ($this->getRequestHeaders() as $key => $val) {
|
||||
$str .= $key . ': ' . $val . "\n";
|
||||
}
|
||||
|
||||
if ($this->getPostBody()) {
|
||||
$str .= "\n";
|
||||
$str .= $this->getPostBody();
|
||||
}
|
||||
|
||||
$headers = '';
|
||||
foreach ($this->batchHeaders as $key => $val) {
|
||||
$headers .= $key . ': ' . $val . "\n";
|
||||
}
|
||||
|
||||
$headers .= "Content-ID: $id\n";
|
||||
$str = $headers . "\n" . $str;
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our own version of parse_str that allows for multiple variables
|
||||
* with the same name.
|
||||
* @param $string - the query string to parse
|
||||
*/
|
||||
private function parseQuery($string)
|
||||
{
|
||||
$return = array();
|
||||
$parts = explode("&", $string);
|
||||
foreach ($parts as $part) {
|
||||
list($key, $value) = explode('=', $part, 2);
|
||||
$value = urldecode($value);
|
||||
if (isset($return[$key])) {
|
||||
if (!is_array($return[$key])) {
|
||||
$return[$key] = array($return[$key]);
|
||||
}
|
||||
$return[$key][] = $value;
|
||||
} else {
|
||||
$return[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of build query that allows for multiple
|
||||
* duplicate keys.
|
||||
* @param $parts array of key value pairs
|
||||
*/
|
||||
private function buildQuery($parts)
|
||||
{
|
||||
$return = array();
|
||||
foreach ($parts as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $v) {
|
||||
$return[] = urlencode($key) . "=" . urlencode($v);
|
||||
}
|
||||
} else {
|
||||
$return[] = urlencode($key) . "=" . urlencode($value);
|
||||
}
|
||||
}
|
||||
return implode('&', $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we're POSTing and have no body to send, we can send the query
|
||||
* parameters in there, which avoids length issues with longer query
|
||||
* params.
|
||||
*/
|
||||
public function maybeMoveParametersToBody()
|
||||
{
|
||||
if ($this->getRequestMethod() == "POST" && empty($this->postBody)) {
|
||||
$this->setRequestHeaders(
|
||||
array(
|
||||
"content-type" =>
|
||||
"application/x-www-form-urlencoded; charset=UTF-8"
|
||||
)
|
||||
);
|
||||
$this->setPostBody($this->buildQuery($this->queryParams));
|
||||
$this->queryParams = array();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user