public function testGetters() { $response = new HttpResponse(200, array('Age: 42'), 'Hey'); $this->assertEquals(200, $response->getStatus()); $this->assertEquals(array('Age: 42'), $response->getHeaders()); $this->assertEquals('Hey', $response->getBody()); }
/** * Processes this batch. This sends the captured requests to the server as one batch. * * @throws ClientException * @return bool - true if processing of the batch was or the HttpResponse object in case of a failure. A successful process just means that tha parts were processed. Each part has it's own response though and should be checked on its own. */ public function process() { $this->stopCapture(); $this->setBatchRequest(true); $data = ''; $batchParts = $this->getBatchParts(); if (count($batchParts) == 0) { throw new ClientException('Can\'t process empty batch.'); } /** @var $partValue BatchPart */ foreach ($batchParts as $partValue) { $data .= '--' . HttpHelper::MIME_BOUNDARY . HttpHelper::EOL; $data .= 'Content-Type: application/x-arango-batchpart' . HttpHelper::EOL; if (!is_null($partValue->getId())) { $data .= 'Content-Id: ' . (string) $partValue->getId() . HttpHelper::EOL . HttpHelper::EOL; } else { $data .= HttpHelper::EOL; } $data .= (string) $partValue->getRequest() . HttpHelper::EOL; } $data .= '--' . HttpHelper::MIME_BOUNDARY . '--' . HttpHelper::EOL . HttpHelper::EOL; $params = array(); $url = UrlHelper::appendParamsUrl(Urls::URL_BATCH, $params); $this->_batchResponse = $this->_connection->post($url, $data); if ($this->_batchResponse->getHttpCode() !== 200) { return $this->_batchResponse; } $body = $this->_batchResponse->getBody(); $body = trim($body, '--' . HttpHelper::MIME_BOUNDARY . '--'); $batchParts = $this->splitWithContentIdKey('--' . HttpHelper::MIME_BOUNDARY . HttpHelper::EOL, $body); foreach ($batchParts as $partKey => $partValue) { $response = new HttpResponse($partValue); $body = $response->getBody(); $response = new HttpResponse($body); $batchPartResponses[$partKey] = $response; $this->getPart($partKey)->setResponse($batchPartResponses[$partKey]); } return $this; }
public function _parseHtml($uri, HttpResponse $response) { $body = $response->getBody(); $body = trim($body); // Get DOM if (class_exists('DOMDocument')) { $dom = new DOMXPath($body); } else { $dom = null; // Maybe add b/c later } $title = null; if ($dom) { $titleList = $dom->query('title'); if (count($titleList) > 0) { $title = trim($titleList->current()->textContent); $title = substr($title, 0, 255); } } $arr_result['title'] = $title; $description = null; if ($dom) { $descriptionList = $dom->queryXpath("//meta[@name='description']"); // Why are they using caps? -_- if (count($descriptionList) == 0) { $descriptionList = $dom->queryXpath("//meta[@name='Description']"); } if (count($descriptionList) > 0) { $description = trim($descriptionList->current()->getAttribute('content')); $description = substr($description, 0, 255); } } $arr_result['description'] = $description; $thumb = null; if ($dom) { $thumbList = $dom->queryXpath("//link[@rel='image_src']"); if (count($thumbList) > 0) { $thumb = $thumbList->current()->getAttribute('href'); } } $medium = null; if ($dom) { $mediumList = $dom->queryXpath("//meta[@name='medium']"); if (count($mediumList) > 0) { $medium = $mediumList->current()->getAttribute('content'); } } // Get baseUrl and baseHref to parse . paths $baseUrlInfo = parse_url($uri); $baseUrl = null; $baseHostUrl = null; if ($dom) { $baseUrlList = $dom->query('base'); if ($baseUrlList && count($baseUrlList) > 0 && $baseUrlList->current()->getAttribute('href')) { $baseUrl = $baseUrlList->current()->getAttribute('href'); $baseUrlInfo = parse_url($baseUrl); $baseHostUrl = $baseUrlInfo['scheme'] . '://' . $baseUrlInfo['host'] . '/'; } } if (!$baseUrl) { $baseHostUrl = $baseUrlInfo['scheme'] . '://' . $baseUrlInfo['host'] . '/'; if (empty($baseUrlInfo['path'])) { $baseUrl = $baseHostUrl; } else { $baseUrl = explode('/', $baseUrlInfo['path']); array_pop($baseUrl); $baseUrl = join('/', $baseUrl); $baseUrl = trim($baseUrl, '/'); $baseUrl = $baseUrlInfo['scheme'] . '://' . $baseUrlInfo['host'] . '/' . $baseUrl . '/'; } } $images = array(); if ($thumb) { $images[] = $thumb; } if ($dom) { $imageQuery = $dom->query('img'); foreach ($imageQuery as $image) { $src = $image->getAttribute('src'); // Ignore images that don't have a src if (!$src || false === ($srcInfo = @parse_url($src))) { continue; } $ext = ltrim(strrchr($src, '.'), '.'); // Detect absolute url if (strpos($src, '/') === 0) { // If relative to root, add host $src = $baseHostUrl . ltrim($src, '/'); } else { if (strpos($src, './') === 0) { // If relative to current path, add baseUrl $src = $baseUrl . substr($src, 2); } else { if (!empty($srcInfo['scheme']) && !empty($srcInfo['host'])) { // Contians host and scheme, do nothing } else { if (empty($srcInfo['scheme']) && empty($srcInfo['host'])) { // if not contains scheme or host, add base $src = $baseUrl . ltrim($src, '/'); } else { if (empty($srcInfo['scheme']) && !empty($srcInfo['host'])) { // if contains host, but not scheme, add scheme? $src = $baseUrlInfo['scheme'] . ltrim($src, '/'); } else { // Just add base $src = $baseUrl . ltrim($src, '/'); } } } } } // Ignore images that don't come from the same domain //if( strpos($src, $srcInfo['host']) === false ) { // @todo should we do this? disabled for now //continue; //} // Ignore images that don't end in an image extension if (!in_array($ext, array('jpg', 'jpeg', 'gif', 'png'))) { // @todo should we do this? disabled for now //continue; } if (!in_array($src, $images)) { $images[] = $src; } } } // Unique $images = array_values(array_unique($images)); // Truncate if greater than 20 if (count($images) > 30) { array_splice($images, 30, count($images)); } $imageCount = count($images); if ($imageCount > 0) { $arr_result['uri'] = $images[0]; } else { $arr_result['uri'] = ''; } return $arr_result; }
/** * Retrive http exception from HttpResponse object. * * @param HttpResponse $httpResponse * @return string */ protected function getHttpException($httpResponse) { $exception = ''; $headers = $httpResponse->getHeaders(); if (isset($headers['Content-type'])) { if (strpos(strtolower($headers['Content-type']), strtolower(Resource::Content_Type_ATOM)) !== FALSE) { $exception = $httpResponse->getMessage(); } else { $exception = $httpResponse->getBody(); } } else { $exception = $httpResponse->getMessage(); } return $exception; }
public function handleInput(&$data, &$errNo) { // What is this? we're getting input while we're sending a reply? if ($this->sendFile) { $this->writeFileReset(); $this->httpRequest = null; } else { if ($this->sendQLen > 0) { $this->sendQReset(); $this->httpRequest = null; } } if (!$this->httpRequest) { $this->httpRequest = new HttpRequest(); } // Pass the incoming data to the HttpRequest class, so it can handle it. if (!$this->httpRequest->handleInput($data)) { // An error was encountered while receiving the requst. // Send reply (unless 444, a special 'direct reject' code) and return false to close this connection. if ($this->httpRequest->errNo != 444) { $r = new HttpResponse('1.1', $this->httpRequest->errNo); $r->addBody($this->createErrorPage($this->httpRequest->errNo, $this->httpRequest->errStr)); if ($this->httpRequest->errNo == 405) { $r->addHeader('Allow: GET, POST, HEAD'); $r->addHeader('Access-Control-Allow-Methods: GET, POST, HEAD'); } $this->write($r->getHeaders()); $this->write($r->getBody()); $this->logRequest($r->getResponseCode(), $r->getHeader('Content-Length') ? $r->getHeader('Content-Length') : 0); } else { $this->logRequest(444, 0); } $errNo = $this->httpRequest->errNo; return false; } // If we have no headers, or we are busy with receiving. // Just return and wait for more data. if (!$this->httpRequest->hasHeaders || $this->httpRequest->isReceiving) { // We're still receiving the body of a request return true; } // Return true to just wait and try again later // At this point we have a fully qualified and parsed HttpRequest // The HttpRequest object contains all info about the headers / GET / POST / COOKIE / FILES // Just finalise it by adding some extra client info. $this->httpRequest->SERVER['REMOTE_ADDR'] = $this->ip; $this->httpRequest->SERVER['REMOTE_PORT'] = $this->port; $this->httpRequest->SERVER['SERVER_ADDR'] = $this->localIP; $this->httpRequest->SERVER['SERVER_PORT'] = $this->localPort; $exp = explode(':', $this->httpRequest->headers['Host']); $this->httpRequest->SERVER['SERVER_NAME'] = $exp[0]; $this->httpRequest->SERVER['HTTP_HOST'] = $this->httpRequest->headers['Host']; $this->httpRequest->SERVER['HTTP_USER_AGENT'] = isset($this->httpRequest->headers['User-Agent']) ? $this->httpRequest->headers['User-Agent'] : ''; $this->httpRequest->SERVER['HTTP_ACCEPT'] = isset($this->httpRequest->headers['Accept']) ? $this->httpRequest->headers['Accept'] : ''; $this->httpRequest->SERVER['HTTP_ACCEPT_LANGUAGE'] = isset($this->httpRequest->headers['Accept-Language']) ? $this->httpRequest->headers['Accept-Language'] : ''; $this->httpRequest->SERVER['HTTP_ACCEPT_ENCODING'] = isset($this->httpRequest->headers['Accept-Encoding']) ? $this->httpRequest->headers['Accept-Encoding'] : ''; $this->httpRequest->SERVER['HTTP_ACCEPT_CHARSET'] = isset($this->httpRequest->headers['Accept-Charset']) ? $this->httpRequest->headers['Accept-Charset'] : ''; $this->httpRequest->SERVER['HTTP_CONNECTION'] = isset($this->httpRequest->headers['Connection']) ? $this->httpRequest->headers['Connection'] : ''; $this->httpRequest->SERVER['HTTP_KEEP_ALIVE'] = isset($this->httpRequest->headers['Keep-Alive']) ? $this->httpRequest->headers['Keep-Alive'] : ''; if (isset($this->httpRequest->headers['Referer'])) { $this->httpRequest->SERVER['HTTP_REFERER'] = $this->httpRequest->headers['Referer']; } if (isset($this->httpRequest->headers['Range'])) { $this->httpRequest->SERVER['HTTP_RANGE'] = $this->httpRequest->headers['Range']; } if (isset($this->httpRequest->headers['Cookie'])) { $this->httpRequest->SERVER['HTTP_COOKIE'] = $this->httpRequest->headers['Cookie']; } if (isset($this->httpRequest->headers['Authorization'])) { $this->httpRequest->SERVER['HTTP_AUTHORIZATION'] = $this->httpRequest->headers['Authorization']; } $this->httpRequest->SERVER['REQUEST_TIME'] = time(); // Check if we have to match siteDomain if ($this->http->getSiteDomain() != '' && $this->http->getSiteDomain() != $this->httpRequest->SERVER['SERVER_NAME']) { $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 404); $r->addBody($this->createErrorPage(404)); $this->write($r->getHeaders()); $this->write($r->getBody()); $errNo = 404; $this->logRequest($r->getResponseCode(), $r->getHeader('Content-Length') ? $r->getHeader('Content-Length') : 0); return false; } // HTTP Authorisation? if ($this->http->getHttpAuthPath() != '') { $scriptPath = pathinfo($this->httpRequest->SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME); // Check if path must be auth'd and if HTTP_AUTHORIZATION header exists and if so, validate it if (isDirInDir($this->http->getHttpAuthPath(), $this->http->getDocRoot() . $scriptPath) && (!isset($this->httpRequest->SERVER['HTTP_AUTHORIZATION']) || !$this->validateAuthorization())) { // Not validated - send 401 Unauthorized do { $nonce = createRandomString(17, RAND_HEX); if (!$this->http->getNonceInfo($nonce)) { break; } } while (true); $opaque = $this->http->addNewNonce($nonce); $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 401); if ($this->http->getHttpAuthType() == 'Digest') { $r->addHeader('WWW-Authenticate: Digest realm="' . HTTP_AUTH_REALM . '", qop="auth", nonce="' . $nonce . '", opaque="' . $opaque . '"'); } else { $r->addHeader('WWW-Authenticate: Basic realm="' . HTTP_AUTH_REALM . '"'); } $r->addBody($this->createErrorPage(401, '', true)); $this->write($r->getHeaders()); $this->write($r->getBody()); $errNo = 401; $this->logRequest($r->getResponseCode(), $r->getHeader('Content-Length') ? $r->getHeader('Content-Length') : 0); $this->httpRequest = null; return true; // we return true this time because we may stay connected } } //var_dump($this->httpRequest->headers); //var_dump($this->httpRequest->SERVER); //var_dump($this->httpRequest->GET); //var_dump($this->httpRequest->POST); //var_dump($this->httpRequest->COOKIE); // Rewrite script name? (keep it internal - don't rewrite SERVER header $scriptName = $this->httpRequest->SERVER['SCRIPT_NAME'] == '/' ? '/index.php' : $this->httpRequest->SERVER['SCRIPT_NAME']; if (file_exists($this->http->getDocRoot() . $scriptName)) { // Should we serve a file or pass the request to PHPParser for page generation? if (preg_match('/^.*\\.php$/', $scriptName)) { if ($this->httpRequest->SERVER['REQUEST_METHOD'] == 'HEAD') { $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 200); $this->write($r->getHeaders()); } else { // 'Parse' the php file $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 200); $html = PHPParser::parseFile($r, $scriptName, $this->httpRequest->SERVER, $this->httpRequest->GET, $this->httpRequest->POST, $this->httpRequest->COOKIE, $this->httpRequest->FILES); $r->addBody($html); $this->write($r->getHeaders()); $this->write($r->getBody()); } } else { if (is_dir($this->http->getDocRoot() . $this->httpRequest->SERVER['SCRIPT_NAME'])) { // 403 - not allowed to view folder contents $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 403); $r->addBody($this->createErrorPage(403)); $this->write($r->getHeaders()); $this->write($r->getBody()); } else { // Send a file if ($this->httpRequest->SERVER['REQUEST_METHOD'] == 'HEAD') { $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 200); $this->write($r->getHeaders()); } else { $r = $this->serveFile(); } } } } else { // 404 $r = new HttpResponse($this->httpRequest->SERVER['httpVersion'], 404); $r->addBody($this->createErrorPage(404)); $this->write($r->getHeaders()); $this->write($r->getBody()); } // log line $this->logRequest($r->getResponseCode(), $r->getHeader('Content-Length') ? $r->getHeader('Content-Length') : 0); // Reset httpRequest $this->httpRequest = null; return true; }
/** * Execute an HTTP request and return the results * * This function will throw if no connection to the server can be established or if * there is a problem during data exchange with the server. * * will restore it. * * @throws Exception * * @param string $method - HTTP request method * @param string $url - HTTP URL * @param string $data - data to post in body * @param array $customHeader - any array containing header elements * * @return HttpResponse */ private function executeRequest($method, $url, $data, $customHeader = array()) { HttpHelper::validateMethod($method); $database = $this->getDatabase(); if ($database === '') { $url = '/_db/' . '_system' . $url; } else { $url = '/_db/' . $database . $url; } // create request data if ($this->_batchRequest === false) { if ($this->_captureBatch === true) { $this->_options->offsetSet(ConnectionOptions::OPTION_BATCHPART, true); $request = HttpHelper::buildRequest($this->_options, $method, $url, $data, $customHeader); $this->_options->offsetSet(ConnectionOptions::OPTION_BATCHPART, false); } else { $request = HttpHelper::buildRequest($this->_options, $method, $url, $data, $customHeader); } if ($this->_captureBatch === true) { $batchPart = $this->doBatch($method, $request); if (!is_null($batchPart)) { return $batchPart; } } } else { $this->_batchRequest = false; $this->_options->offsetSet(ConnectionOptions::OPTION_BATCH, true); $request = HttpHelper::buildRequest($this->_options, $method, $url, $data, $customHeader); $this->_options->offsetSet(ConnectionOptions::OPTION_BATCH, false); } $traceFunc = $this->_options[ConnectionOptions::OPTION_TRACE]; if ($traceFunc) { // call tracer func if ($this->_options[ConnectionOptions::OPTION_ENHANCED_TRACE]) { list($header) = HttpHelper::parseHttpMessage($request, $url, $method); $headers = HttpHelper::parseHeaders($header); $traceFunc(new TraceRequest($headers[2], $method, $url, $data)); } else { $traceFunc('send', $request); } } // open the socket. note: this might throw if the connection cannot be established $handle = $this->getHandle(); if ($handle) { // send data and get response back if ($traceFunc) { // only issue syscall if we need it $startTime = microtime(true); } $result = HttpHelper::transfer($handle, $request); if ($traceFunc) { // only issue syscall if we need it $timeTaken = microtime(true) - $startTime; } $status = socket_get_status($handle); if ($status['timed_out']) { throw new ClientException('Got a timeout while waiting for the server\'s response', 408); } if (!$this->_useKeepAlive) { // must close the connection fclose($handle); } $response = new HttpResponse($result, $url, $method); if ($traceFunc) { // call tracer func if ($this->_options[ConnectionOptions::OPTION_ENHANCED_TRACE]) { $traceFunc(new TraceResponse($response->getHeaders(), $response->getHttpCode(), $response->getBody(), $timeTaken)); } else { $traceFunc('receive', $result); } } return $response; } throw new ClientException('Whoops, this should never happen'); }
/** * Handle a non 200 series response from the API. * * This method is here specifically for sub-classes to override. When an API call is made and a non-200 series * status code is returned then this method is called with that response. This lets API client authors to extract * the appropriate error message out of the response and decide whether or not to throw a PHP exception. * * It is recommended that you obey the caller's wishes on whether or not to throw an exception by using the * following `if` statement: * * ```php * if ($this->val('throw', $options, $this->throwExceptions)) { * ... * } * ``` * * @param HttpResponse $response The response sent from the API. * @param array $options The options that were sent with the request. * @throws \Exception Throws an exception if the settings or options say to throw an exception. */ public function handleErrorResponse(HttpResponse $response, $options = []) { if ($this->val('throw', $options, $this->throwExceptions)) { $body = $response->getBody(); if (is_array($body)) { $message = $this->val('message', $body, $response->getReasonPhrase()); } else { $message = $response->getReasonPhrase(); } throw new \Exception($message, $response->getStatusCode()); } }
/** * @dataProvider stringProvider * * @param string $body */ public function testGetBody($body) { $response = new HttpResponse($body, 200, ''); $this->assertEquals($body, $response->getBody()); }