/**
  * Constructor.
  *
  * @param string|HTTP_Request $messageOrResponse a string (UTF-8) describing
  *                                               the error, or the
  *                                               HTTP_Request2_Response that
  *                                               caused the exception.
  * @param int                 $code              the error code.
  */
 public function __construct($messageOrResponse, $code = 0)
 {
     $message = false;
     if ($messageOrResponse instanceof HTTP_Request2_Response) {
         $this->response = $messageOrResponse;
         $contentType = $this->response->getHeader('content-type');
         if ($contentType == 'application/xml' && $this->response->getBody()) {
             $prevUseInternalErrors = libxml_use_internal_errors(true);
             $doc = new DOMDocument();
             $ok = $doc->loadXML($this->response->getBody());
             libxml_use_internal_errors($prevUseInternalErrors);
             if ($ok) {
                 $xPath = new DOMXPath($doc);
                 $this->_amazonErrorCode = $xPath->evaluate('string(/Error/Code)');
                 $message = $xPath->evaluate('string(/Error/Message)');
             }
         }
         if (!$message) {
             $message = 'Bad response from server.';
         }
         if (!$code) {
             $code = $this->response->getStatus();
         }
     } else {
         $message = (string) $messageOrResponse;
     }
     parent::__construct($message, $code);
 }
Example #2
0
 /**
  * Callback function called by cURL for saving the response headers
  *
  * @param    resource    cURL handle
  * @param    string      response header (with trailing CRLF)
  * @return   integer     number of bytes saved
  * @see      HTTP_Request2_Response::parseHeaderLine()
  */
 protected function callbackWriteHeader($ch, $string)
 {
     // we may receive a second set of headers if doing e.g. digest auth
     if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
         // don't bother with 100-Continue responses (bug #15785)
         if (!$this->eventSentHeaders || $this->response->getStatus() >= 200) {
             $this->request->setLastEvent('sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT));
         }
         $upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
         // if body wasn't read by a callback, send event with total body size
         if ($upload > $this->position) {
             $this->request->setLastEvent('sentBodyPart', $upload - $this->position);
             $this->position = $upload;
         }
         if ($upload && (!$this->eventSentHeaders || $this->response->getStatus() >= 200)) {
             $this->request->setLastEvent('sentBody', $upload);
         }
         $this->eventSentHeaders = true;
         // we'll need a new response object
         if ($this->eventReceivedHeaders) {
             $this->eventReceivedHeaders = false;
             $this->response = null;
         }
     }
     if (empty($this->response)) {
         $this->response = new HTTP_Request2_Response($string, false);
     } else {
         $this->response->parseHeaderLine($string);
         if ('' == trim($string)) {
             // don't bother with 100-Continue responses (bug #15785)
             if (200 <= $this->response->getStatus()) {
                 $this->request->setLastEvent('receivedHeaders', $this->response);
             }
             if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) {
                 $redirectUrl = new Net_URL2($this->response->getHeader('location'));
                 // for versions lower than 5.2.10, check the redirection URL protocol
                 if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute() && !in_array($redirectUrl->getScheme(), array('http', 'https'))) {
                     return -1;
                 }
                 if ($jar = $this->request->getCookieJar()) {
                     $jar->addCookiesFromResponse($this->response, $this->request->getUrl());
                     if (!$redirectUrl->isAbsolute()) {
                         $redirectUrl = $this->request->getUrl()->resolve($redirectUrl);
                     }
                     if ($cookies = $jar->getMatching($redirectUrl, true)) {
                         curl_setopt($ch, CURLOPT_COOKIE, $cookies);
                     }
                 }
             }
             $this->eventReceivedHeaders = true;
         }
     }
     return strlen($string);
 }
Example #3
0
 protected function extractLinks(\HTTP_Request2_Response $res)
 {
     $mimetype = explode(';', $res->getHeader('content-type'))[0];
     if (!isset(static::$supportedTypes[$mimetype])) {
         Log::info("MIME type not supported for crawling: {$mimetype}");
         return array();
     }
     $class = static::$supportedTypes[$mimetype];
     $extractor = new $class();
     return $extractor->extract($res);
 }
Example #4
0
 /**
  * Compares between two responses by Content-ID header.
  * 
  * @param \HTTP_Request2_Response $r1 The first response object.
  * @param \HTTP_Request2_Response $r2 The second response object.
  * 
  * @return boolean
  */
 private static function _compareUsingContentId($r1, $r2)
 {
     $h1 = array_change_key_case($r1->getHeader());
     $h2 = array_change_key_case($r2->getHeader());
     $c1 = Utilities::tryGetValue($h1, Resources::CONTENT_ID, 0);
     $c2 = Utilities::tryGetValue($h2, Resources::CONTENT_ID, 0);
     return intval($c1) >= intval($c2);
 }
Example #5
0
 /**
  * Checks whether another request should be performed with proxy digest auth
  *
  * Several conditions should be satisfied for it to return true:
  *   - response status should be 407
  *   - proxy auth credentials should be set in the request object
  *   - response should contain Proxy-Authenticate header with digest challenge
  *   - there is either no challenge stored for this proxy or new challenge
  *     contains stale=true parameter (in other case we probably just failed
  *     due to invalid username / password)
  *
  * The method stores challenge values in $challenges static property
  *
  * @param    HTTP_Request2_Response  response to check
  * @return   boolean whether another request should be performed
  * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
  */
 protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)
 {
     if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {
         return false;
     }
     if (!($challenge = $this->parseDigestChallenge($response->getHeader('proxy-authenticate')))) {
         return false;
     }
     $key = 'proxy://' . $this->request->getConfig('proxy_host') . ':' . $this->request->getConfig('proxy_port');
     if (!empty(self::$challenges[$key]) && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))) {
         $ret = false;
     } else {
         $ret = true;
     }
     self::$challenges[$key] = $challenge;
     return $ret;
 }
Example #6
0
 /**
  * Based on an XRI, will request the XRD document located at the proxy
  * prefixed URI and parse in search of the XRI Canonical Id. This is
  * a flexible requirement. OpenID 2.0 requires the use of the Canonical
  * ID instead of the raw i-name. 2idi.com, on the other hand, does not.
  *
  * @param string $xri The XRI
  *
  * @todo Imcomplete; requires interface from Yadis main class
  * @return string
  * @throws Services_Yadis_Exception
  */
 public function toCanonicalId($xri = null)
 {
     if (!isset($xri) && !isset($this->uri)) {
         throw new Services_Yadis_Exception('No XRI passed as parameter as required unless called after ' . 'Services_Yadis_Xri:toUri');
     } elseif (isset($xri)) {
         $uri = $this->toUri($xri);
     } else {
         $uri = $this->uri;
     }
     $this->httpResponse = $this->get($uri, null, $this->getHttpRequestOptions());
     if (stripos($this->httpResponse->getHeader('Content-Type'), 'application/xrds+xml') === false) {
         throw new Services_Yadis_Exception('The response header indicates the response body is not ' . 'an XRDS document');
     }
     $xrds = new SimpleXMLElement($this->httpResponse->getBody());
     $this->namespace->registerXpathNamespaces($xrds);
     $id = $xrds->xpath('//xrd:CanonicalID[last()]');
     $this->canonicalID = (string) array_shift($id);
     if (!$this->canonicalID) {
         throw new Services_Yadis_Exception('Unable to determine canonicalID');
     }
     return $xrds;
 }
Example #7
0
 /**
  * Returns a DOMXPath object for the XML document in the body of the
  * specified HTTP response. This method is for internal use only.
  *
  * @param HTTP_Request2_Response $response the HTTP response.
  *
  * @return DOMXPath
  * @throws Services_Amazon_S3_ServerErrorException
  */
 public static function getDOMXPath(HTTP_Request2_Response $response)
 {
     if ($response->getHeader('content-type') != 'application/xml') {
         throw new Services_Amazon_S3_ServerErrorException('Response was not of type application/xml', $response);
     }
     $prevUseInternalErrors = libxml_use_internal_errors(true);
     $doc = new DOMDocument();
     $ok = $doc->loadXML($response->getBody());
     libxml_use_internal_errors($prevUseInternalErrors);
     if (!$ok) {
         throw new Services_Amazon_S3_ServerErrorException($response);
     }
     $xPath = new DOMXPath($doc);
     $xPath->registerNamespace('s3', self::NS_S3);
     $xPath->registerNamespace('xsi', self::NS_XSI);
     return $xPath;
 }
Example #8
0
 /**
  * Saves the response body to a specified directory
  *
  * @param  HTTP_Request2_Response $response
  * @return void
  * @throws BuildException
  */
 protected function processResponse(HTTP_Request2_Response $response)
 {
     if ($response->getStatus() != 200) {
         throw new BuildException("Request unsuccessful. Response from server: " . $response->getStatus() . " " . $response->getReasonPhrase());
     }
     $content = $response->getBody();
     $disposition = $response->getHeader('content-disposition');
     if ($this->filename) {
         $filename = $this->filename;
     } elseif ($disposition && 0 == strpos($disposition, 'attachment') && preg_match('/filename="([^"]+)"/', $disposition, $m)) {
         $filename = basename($m[1]);
     } else {
         $filename = basename(parse_url($this->url, PHP_URL_PATH));
     }
     if (!is_writable($this->dir)) {
         throw new BuildException("Cannot write to directory: " . $this->dir);
     }
     $filename = $this->dir . "/" . $filename;
     file_put_contents($filename, $content);
     $this->log("Contents from " . $this->url . " saved to {$filename}");
 }
Example #9
0
 /**
  * Gets the Expires header from the response object
  * 
  * @return string
  */
 protected function getExpiresHeader()
 {
     // @codeCoverageIgnoreStart
     return $this->response->getHeader('Expires');
     // @codeCoverageIgnoreEnd
 }
Example #10
0
 /**
  * Parse the response (from {@link self::makeRequest()}.
  *
  * @param HTTP_Request2_Response $resp The response returned from the API.
  *
  * @return mixed
  * @throws RuntimeException In case the API returned an error.
  */
 protected function parseResponse(HTTP_Request2_Response $resp)
 {
     $body = $resp->getBody();
     $headers = $resp->getHeader();
     if (isset($headers['content-type'])) {
         if ($headers['content-type'] == 'text/calendar; charset=utf-8') {
             return $body;
         }
     }
     switch ($body) {
         case 'Access Denied':
             throw new RuntimeException("API response: {$body}");
         case 'Item Deleted Successfully':
         case 'Meeting Deleted Successfully':
         case 'Note Deleted Successfully':
             return $body;
         default:
             $resp = json_decode($body);
             if (isset($resp->status)) {
                 switch ($resp->status) {
                     case 'internal_server_error':
                         throw new RuntimeException($resp->message);
                 }
             }
             return $resp;
     }
 }
Example #11
0
 /**
  * Determines the filename from either the 'content-disposition' header
  * or from the basename of the current request.
  *
  * @param \HTTP_Request2 $request
  * @param \HTTP_Request2_Response $response
  * @return void
  */
 protected function determineFilename(\HTTP_Request2 $request, \HTTP_Request2_Response $response)
 {
     $matches = array();
     $disposition = $response->getHeader('content-disposition');
     if ($disposition !== null && 0 === strpos($disposition, 'attachment') && 1 === preg_match('/filename="([^"]+)"/', $disposition, $matches)) {
         $filename = basename($matches[1]);
     } else {
         $filename = basename($request->getUrl()->getPath());
     }
     $this->setFilename($filename);
 }
Example #12
0
 /**
  * Verifies that the HTTP response has status code 200 and
  * content-type application/json; charset=utf-8
  *
  * @param HTTP_Request2_Response $res HTTP Response object
  *
  * @return void
  */
 protected function assertResponseJson200(HTTP_Request2_Response $res)
 {
     $this->assertEquals(200, $res->getStatus());
     $this->assertEquals('application/json; charset=utf-8', $res->getHeader('content-type'));
 }
Example #13
0
 /**
  * Given an HTTP response, return the requested Link: header
  *
  * @param HTTP_Request2_Response $response response to check
  * @param string                 $rel      relationship to look for
  * @param string                 $type     media type to look for
  *
  * @return LinkHeader discovered header, or null on failure
  */
 static function getLink($response, $rel = null, $type = null)
 {
     $headers = $response->getHeader('Link');
     if ($headers) {
         // Can get an array or string, so try to simplify the path
         if (!is_array($headers)) {
             $headers = array($headers);
         }
         foreach ($headers as $header) {
             $lh = new LinkHeader($header);
             if ((is_null($rel) || $lh->rel == $rel) && (is_null($type) || $lh->type == $type)) {
                 return $lh->href;
             }
         }
     }
     return null;
 }
Example #14
0
 /**
  * Assuming this user is hosting a third party sourced identity under an
  * alias personal URL, we'll need to check if the website's HTML body
  * has a http-equiv meta element with a content attribute pointing to where
  * we can fetch the XRD document.
  *
  * @param HTTP_Request2_Response $response Instance of HTTP_Request2_Response
  *
  * @return boolean
  * @throws Services_Yadis_Exception
  */
 protected function isMetaHttpEquiv(HTTP_Request2_Response $response)
 {
     $location = null;
     if (!in_array($response->getHeader('Content-Type'), $this->validHtmlContentTypes)) {
         return false;
     }
     /**
      * Find a match for a relevant <meta> element, then iterate through the
      * results to see if a valid http-equiv value and matching content URI
      * exist.
      */
     $html = new DOMDocument();
     $html->loadHTML($response->getBody());
     $head = $html->getElementsByTagName('head');
     if ($head->length > 0) {
         $metas = $head->item(0)->getElementsByTagName('meta');
         if ($metas->length > 0) {
             foreach ($metas as $meta) {
                 $equiv = strtolower($meta->getAttribute('http-equiv'));
                 if ($equiv == 'x-xrds-location' || $equiv == 'x-yadis-location') {
                     $location = $meta->getAttribute('content');
                 }
             }
         }
     }
     if (is_null($location)) {
         return false;
     } elseif (!self::validateURI($location)) {
         throw new Services_Yadis_Exception('The URI parsed from the HTML Alias document appears to be invalid, ' . 'or could not be found: ' . htmlentities($location, ENT_QUOTES, 'utf-8'));
     }
     /**
      * Should now contain the content value of the http-equiv type pointing
      * to an XRDS resource for the user's Identity Provider, as found by
      * passing the meta regex across the response body.
      */
     $this->metaHttpEquivUrl = $location;
     return true;
 }