annotate vendor/symfony/browser-kit/Client.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\BrowserKit;
Chris@0 13
Chris@0 14 use Symfony\Component\DomCrawler\Crawler;
Chris@17 15 use Symfony\Component\DomCrawler\Form;
Chris@0 16 use Symfony\Component\DomCrawler\Link;
Chris@0 17 use Symfony\Component\Process\PhpProcess;
Chris@0 18
Chris@0 19 /**
Chris@0 20 * Client simulates a browser.
Chris@0 21 *
Chris@0 22 * To make the actual request, you need to implement the doRequest() method.
Chris@0 23 *
Chris@0 24 * If you want to be able to run requests in their own process (insulated flag),
Chris@0 25 * you need to also implement the getScript() method.
Chris@0 26 *
Chris@0 27 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 28 */
Chris@0 29 abstract class Client
Chris@0 30 {
Chris@0 31 protected $history;
Chris@0 32 protected $cookieJar;
Chris@17 33 protected $server = [];
Chris@0 34 protected $internalRequest;
Chris@0 35 protected $request;
Chris@0 36 protected $internalResponse;
Chris@0 37 protected $response;
Chris@0 38 protected $crawler;
Chris@0 39 protected $insulated = false;
Chris@0 40 protected $redirect;
Chris@0 41 protected $followRedirects = true;
Chris@0 42
Chris@0 43 private $maxRedirects = -1;
Chris@0 44 private $redirectCount = 0;
Chris@17 45 private $redirects = [];
Chris@0 46 private $isMainRequest = true;
Chris@0 47
Chris@0 48 /**
Chris@0 49 * @param array $server The server parameters (equivalent of $_SERVER)
Chris@0 50 * @param History $history A History instance to store the browser history
Chris@0 51 * @param CookieJar $cookieJar A CookieJar instance to store the cookies
Chris@0 52 */
Chris@17 53 public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null)
Chris@0 54 {
Chris@0 55 $this->setServerParameters($server);
Chris@0 56 $this->history = $history ?: new History();
Chris@0 57 $this->cookieJar = $cookieJar ?: new CookieJar();
Chris@0 58 }
Chris@0 59
Chris@0 60 /**
Chris@0 61 * Sets whether to automatically follow redirects or not.
Chris@0 62 *
Chris@0 63 * @param bool $followRedirect Whether to follow redirects
Chris@0 64 */
Chris@0 65 public function followRedirects($followRedirect = true)
Chris@0 66 {
Chris@0 67 $this->followRedirects = (bool) $followRedirect;
Chris@0 68 }
Chris@0 69
Chris@0 70 /**
Chris@0 71 * Returns whether client automatically follows redirects or not.
Chris@0 72 *
Chris@0 73 * @return bool
Chris@0 74 */
Chris@0 75 public function isFollowingRedirects()
Chris@0 76 {
Chris@0 77 return $this->followRedirects;
Chris@0 78 }
Chris@0 79
Chris@0 80 /**
Chris@13 81 * Sets the maximum number of redirects that crawler can follow.
Chris@0 82 *
Chris@0 83 * @param int $maxRedirects
Chris@0 84 */
Chris@0 85 public function setMaxRedirects($maxRedirects)
Chris@0 86 {
Chris@0 87 $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
Chris@0 88 $this->followRedirects = -1 != $this->maxRedirects;
Chris@0 89 }
Chris@0 90
Chris@0 91 /**
Chris@13 92 * Returns the maximum number of redirects that crawler can follow.
Chris@0 93 *
Chris@0 94 * @return int
Chris@0 95 */
Chris@0 96 public function getMaxRedirects()
Chris@0 97 {
Chris@0 98 return $this->maxRedirects;
Chris@0 99 }
Chris@0 100
Chris@0 101 /**
Chris@0 102 * Sets the insulated flag.
Chris@0 103 *
Chris@0 104 * @param bool $insulated Whether to insulate the requests or not
Chris@0 105 *
Chris@0 106 * @throws \RuntimeException When Symfony Process Component is not installed
Chris@0 107 */
Chris@0 108 public function insulate($insulated = true)
Chris@0 109 {
Chris@0 110 if ($insulated && !class_exists('Symfony\\Component\\Process\\Process')) {
Chris@0 111 throw new \RuntimeException('Unable to isolate requests as the Symfony Process Component is not installed.');
Chris@0 112 }
Chris@0 113
Chris@0 114 $this->insulated = (bool) $insulated;
Chris@0 115 }
Chris@0 116
Chris@0 117 /**
Chris@0 118 * Sets server parameters.
Chris@0 119 *
Chris@0 120 * @param array $server An array of server parameters
Chris@0 121 */
Chris@0 122 public function setServerParameters(array $server)
Chris@0 123 {
Chris@17 124 $this->server = array_merge([
Chris@0 125 'HTTP_USER_AGENT' => 'Symfony BrowserKit',
Chris@17 126 ], $server);
Chris@0 127 }
Chris@0 128
Chris@0 129 /**
Chris@0 130 * Sets single server parameter.
Chris@0 131 *
Chris@0 132 * @param string $key A key of the parameter
Chris@0 133 * @param string $value A value of the parameter
Chris@0 134 */
Chris@0 135 public function setServerParameter($key, $value)
Chris@0 136 {
Chris@0 137 $this->server[$key] = $value;
Chris@0 138 }
Chris@0 139
Chris@0 140 /**
Chris@0 141 * Gets single server parameter for specified key.
Chris@0 142 *
Chris@0 143 * @param string $key A key of the parameter to get
Chris@0 144 * @param string $default A default value when key is undefined
Chris@0 145 *
Chris@0 146 * @return string A value of the parameter
Chris@0 147 */
Chris@0 148 public function getServerParameter($key, $default = '')
Chris@0 149 {
Chris@0 150 return isset($this->server[$key]) ? $this->server[$key] : $default;
Chris@0 151 }
Chris@0 152
Chris@0 153 /**
Chris@0 154 * Returns the History instance.
Chris@0 155 *
Chris@0 156 * @return History A History instance
Chris@0 157 */
Chris@0 158 public function getHistory()
Chris@0 159 {
Chris@0 160 return $this->history;
Chris@0 161 }
Chris@0 162
Chris@0 163 /**
Chris@0 164 * Returns the CookieJar instance.
Chris@0 165 *
Chris@0 166 * @return CookieJar A CookieJar instance
Chris@0 167 */
Chris@0 168 public function getCookieJar()
Chris@0 169 {
Chris@0 170 return $this->cookieJar;
Chris@0 171 }
Chris@0 172
Chris@0 173 /**
Chris@0 174 * Returns the current Crawler instance.
Chris@0 175 *
Chris@0 176 * @return Crawler|null A Crawler instance
Chris@0 177 */
Chris@0 178 public function getCrawler()
Chris@0 179 {
Chris@0 180 return $this->crawler;
Chris@0 181 }
Chris@0 182
Chris@0 183 /**
Chris@0 184 * Returns the current BrowserKit Response instance.
Chris@0 185 *
Chris@0 186 * @return Response|null A BrowserKit Response instance
Chris@0 187 */
Chris@0 188 public function getInternalResponse()
Chris@0 189 {
Chris@0 190 return $this->internalResponse;
Chris@0 191 }
Chris@0 192
Chris@0 193 /**
Chris@0 194 * Returns the current origin response instance.
Chris@0 195 *
Chris@0 196 * The origin response is the response instance that is returned
Chris@0 197 * by the code that handles requests.
Chris@0 198 *
Chris@0 199 * @return object|null A response instance
Chris@0 200 *
Chris@0 201 * @see doRequest()
Chris@0 202 */
Chris@0 203 public function getResponse()
Chris@0 204 {
Chris@0 205 return $this->response;
Chris@0 206 }
Chris@0 207
Chris@0 208 /**
Chris@0 209 * Returns the current BrowserKit Request instance.
Chris@0 210 *
Chris@0 211 * @return Request|null A BrowserKit Request instance
Chris@0 212 */
Chris@0 213 public function getInternalRequest()
Chris@0 214 {
Chris@0 215 return $this->internalRequest;
Chris@0 216 }
Chris@0 217
Chris@0 218 /**
Chris@0 219 * Returns the current origin Request instance.
Chris@0 220 *
Chris@0 221 * The origin request is the request instance that is sent
Chris@0 222 * to the code that handles requests.
Chris@0 223 *
Chris@0 224 * @return object|null A Request instance
Chris@0 225 *
Chris@0 226 * @see doRequest()
Chris@0 227 */
Chris@0 228 public function getRequest()
Chris@0 229 {
Chris@0 230 return $this->request;
Chris@0 231 }
Chris@0 232
Chris@0 233 /**
Chris@0 234 * Clicks on a given link.
Chris@0 235 *
Chris@0 236 * @return Crawler
Chris@0 237 */
Chris@0 238 public function click(Link $link)
Chris@0 239 {
Chris@0 240 if ($link instanceof Form) {
Chris@0 241 return $this->submit($link);
Chris@0 242 }
Chris@0 243
Chris@0 244 return $this->request($link->getMethod(), $link->getUri());
Chris@0 245 }
Chris@0 246
Chris@0 247 /**
Chris@0 248 * Submits a form.
Chris@0 249 *
Chris@0 250 * @param Form $form A Form instance
Chris@0 251 * @param array $values An array of form field values
Chris@0 252 *
Chris@0 253 * @return Crawler
Chris@0 254 */
Chris@17 255 public function submit(Form $form, array $values = [])
Chris@0 256 {
Chris@0 257 $form->setValues($values);
Chris@0 258
Chris@0 259 return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles());
Chris@0 260 }
Chris@0 261
Chris@0 262 /**
Chris@0 263 * Calls a URI.
Chris@0 264 *
Chris@0 265 * @param string $method The request method
Chris@0 266 * @param string $uri The URI to fetch
Chris@0 267 * @param array $parameters The Request parameters
Chris@0 268 * @param array $files The files
Chris@0 269 * @param array $server The server parameters (HTTP headers are referenced with a HTTP_ prefix as PHP does)
Chris@0 270 * @param string $content The raw body data
Chris@0 271 * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
Chris@0 272 *
Chris@0 273 * @return Crawler
Chris@0 274 */
Chris@17 275 public function request($method, $uri, array $parameters = [], array $files = [], array $server = [], $content = null, $changeHistory = true)
Chris@0 276 {
Chris@0 277 if ($this->isMainRequest) {
Chris@0 278 $this->redirectCount = 0;
Chris@0 279 } else {
Chris@0 280 ++$this->redirectCount;
Chris@0 281 }
Chris@0 282
Chris@17 283 $originalUri = $uri;
Chris@17 284
Chris@0 285 $uri = $this->getAbsoluteUri($uri);
Chris@0 286
Chris@0 287 $server = array_merge($this->server, $server);
Chris@0 288
Chris@17 289 if (!empty($server['HTTP_HOST']) && null === parse_url($originalUri, PHP_URL_HOST)) {
Chris@17 290 $uri = preg_replace('{^(https?\://)'.preg_quote($this->extractHost($uri)).'}', '${1}'.$server['HTTP_HOST'], $uri);
Chris@17 291 }
Chris@17 292
Chris@17 293 if (isset($server['HTTPS']) && null === parse_url($originalUri, PHP_URL_SCHEME)) {
Chris@0 294 $uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri);
Chris@0 295 }
Chris@0 296
Chris@0 297 if (!$this->history->isEmpty()) {
Chris@0 298 $server['HTTP_REFERER'] = $this->history->current()->getUri();
Chris@0 299 }
Chris@0 300
Chris@0 301 if (empty($server['HTTP_HOST'])) {
Chris@0 302 $server['HTTP_HOST'] = $this->extractHost($uri);
Chris@0 303 }
Chris@0 304
Chris@0 305 $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME);
Chris@0 306
Chris@0 307 $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content);
Chris@0 308
Chris@0 309 $this->request = $this->filterRequest($this->internalRequest);
Chris@0 310
Chris@0 311 if (true === $changeHistory) {
Chris@0 312 $this->history->add($this->internalRequest);
Chris@0 313 }
Chris@0 314
Chris@0 315 if ($this->insulated) {
Chris@0 316 $this->response = $this->doRequestInProcess($this->request);
Chris@0 317 } else {
Chris@0 318 $this->response = $this->doRequest($this->request);
Chris@0 319 }
Chris@0 320
Chris@0 321 $this->internalResponse = $this->filterResponse($this->response);
Chris@0 322
Chris@0 323 $this->cookieJar->updateFromResponse($this->internalResponse, $uri);
Chris@0 324
Chris@0 325 $status = $this->internalResponse->getStatus();
Chris@0 326
Chris@0 327 if ($status >= 300 && $status < 400) {
Chris@0 328 $this->redirect = $this->internalResponse->getHeader('Location');
Chris@0 329 } else {
Chris@0 330 $this->redirect = null;
Chris@0 331 }
Chris@0 332
Chris@0 333 if ($this->followRedirects && $this->redirect) {
Chris@12 334 $this->redirects[serialize($this->history->current())] = true;
Chris@12 335
Chris@0 336 return $this->crawler = $this->followRedirect();
Chris@0 337 }
Chris@0 338
Chris@0 339 return $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type'));
Chris@0 340 }
Chris@0 341
Chris@0 342 /**
Chris@0 343 * Makes a request in another process.
Chris@0 344 *
Chris@0 345 * @param object $request An origin request instance
Chris@0 346 *
Chris@0 347 * @return object An origin response instance
Chris@0 348 *
Chris@0 349 * @throws \RuntimeException When processing returns exit code
Chris@0 350 */
Chris@0 351 protected function doRequestInProcess($request)
Chris@0 352 {
Chris@12 353 $deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec');
Chris@12 354 putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile);
Chris@12 355 $_ENV['SYMFONY_DEPRECATIONS_SERIALIZE'] = $deprecationsFile;
Chris@0 356 $process = new PhpProcess($this->getScript($request), null, null);
Chris@0 357 $process->run();
Chris@0 358
Chris@12 359 if (file_exists($deprecationsFile)) {
Chris@12 360 $deprecations = file_get_contents($deprecationsFile);
Chris@12 361 unlink($deprecationsFile);
Chris@17 362 foreach ($deprecations ? unserialize($deprecations) : [] as $deprecation) {
Chris@12 363 if ($deprecation[0]) {
Chris@17 364 @trigger_error($deprecation[1], E_USER_DEPRECATED);
Chris@12 365 } else {
Chris@12 366 @trigger_error($deprecation[1], E_USER_DEPRECATED);
Chris@12 367 }
Chris@12 368 }
Chris@12 369 }
Chris@12 370
Chris@0 371 if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) {
Chris@0 372 throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput()));
Chris@0 373 }
Chris@0 374
Chris@0 375 return unserialize($process->getOutput());
Chris@0 376 }
Chris@0 377
Chris@0 378 /**
Chris@0 379 * Makes a request.
Chris@0 380 *
Chris@0 381 * @param object $request An origin request instance
Chris@0 382 *
Chris@0 383 * @return object An origin response instance
Chris@0 384 */
Chris@0 385 abstract protected function doRequest($request);
Chris@0 386
Chris@0 387 /**
Chris@0 388 * Returns the script to execute when the request must be insulated.
Chris@0 389 *
Chris@0 390 * @param object $request An origin request instance
Chris@0 391 *
Chris@0 392 * @throws \LogicException When this abstract class is not implemented
Chris@0 393 */
Chris@0 394 protected function getScript($request)
Chris@0 395 {
Chris@0 396 throw new \LogicException('To insulate requests, you need to override the getScript() method.');
Chris@0 397 }
Chris@0 398
Chris@0 399 /**
Chris@0 400 * Filters the BrowserKit request to the origin one.
Chris@0 401 *
Chris@0 402 * @param Request $request The BrowserKit Request to filter
Chris@0 403 *
Chris@0 404 * @return object An origin request instance
Chris@0 405 */
Chris@0 406 protected function filterRequest(Request $request)
Chris@0 407 {
Chris@0 408 return $request;
Chris@0 409 }
Chris@0 410
Chris@0 411 /**
Chris@0 412 * Filters the origin response to the BrowserKit one.
Chris@0 413 *
Chris@0 414 * @param object $response The origin response to filter
Chris@0 415 *
Chris@0 416 * @return Response An BrowserKit Response instance
Chris@0 417 */
Chris@0 418 protected function filterResponse($response)
Chris@0 419 {
Chris@0 420 return $response;
Chris@0 421 }
Chris@0 422
Chris@0 423 /**
Chris@0 424 * Creates a crawler.
Chris@0 425 *
Chris@0 426 * This method returns null if the DomCrawler component is not available.
Chris@0 427 *
Chris@0 428 * @param string $uri A URI
Chris@0 429 * @param string $content Content for the crawler to use
Chris@0 430 * @param string $type Content type
Chris@0 431 *
Chris@0 432 * @return Crawler|null
Chris@0 433 */
Chris@0 434 protected function createCrawlerFromContent($uri, $content, $type)
Chris@0 435 {
Chris@0 436 if (!class_exists('Symfony\Component\DomCrawler\Crawler')) {
Chris@0 437 return;
Chris@0 438 }
Chris@0 439
Chris@0 440 $crawler = new Crawler(null, $uri);
Chris@0 441 $crawler->addContent($content, $type);
Chris@0 442
Chris@0 443 return $crawler;
Chris@0 444 }
Chris@0 445
Chris@0 446 /**
Chris@0 447 * Goes back in the browser history.
Chris@0 448 *
Chris@0 449 * @return Crawler
Chris@0 450 */
Chris@0 451 public function back()
Chris@0 452 {
Chris@12 453 do {
Chris@12 454 $request = $this->history->back();
Chris@18 455 } while (\array_key_exists(serialize($request), $this->redirects));
Chris@12 456
Chris@12 457 return $this->requestFromRequest($request, false);
Chris@0 458 }
Chris@0 459
Chris@0 460 /**
Chris@0 461 * Goes forward in the browser history.
Chris@0 462 *
Chris@0 463 * @return Crawler
Chris@0 464 */
Chris@0 465 public function forward()
Chris@0 466 {
Chris@12 467 do {
Chris@12 468 $request = $this->history->forward();
Chris@18 469 } while (\array_key_exists(serialize($request), $this->redirects));
Chris@12 470
Chris@12 471 return $this->requestFromRequest($request, false);
Chris@0 472 }
Chris@0 473
Chris@0 474 /**
Chris@0 475 * Reloads the current browser.
Chris@0 476 *
Chris@0 477 * @return Crawler
Chris@0 478 */
Chris@0 479 public function reload()
Chris@0 480 {
Chris@0 481 return $this->requestFromRequest($this->history->current(), false);
Chris@0 482 }
Chris@0 483
Chris@0 484 /**
Chris@0 485 * Follow redirects?
Chris@0 486 *
Chris@0 487 * @return Crawler
Chris@0 488 *
Chris@0 489 * @throws \LogicException If request was not a redirect
Chris@0 490 */
Chris@0 491 public function followRedirect()
Chris@0 492 {
Chris@0 493 if (empty($this->redirect)) {
Chris@0 494 throw new \LogicException('The request was not redirected.');
Chris@0 495 }
Chris@0 496
Chris@0 497 if (-1 !== $this->maxRedirects) {
Chris@0 498 if ($this->redirectCount > $this->maxRedirects) {
Chris@12 499 $this->redirectCount = 0;
Chris@0 500 throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects));
Chris@0 501 }
Chris@0 502 }
Chris@0 503
Chris@0 504 $request = $this->internalRequest;
Chris@0 505
Chris@17 506 if (\in_array($this->internalResponse->getStatus(), [301, 302, 303])) {
Chris@0 507 $method = 'GET';
Chris@17 508 $files = [];
Chris@0 509 $content = null;
Chris@0 510 } else {
Chris@0 511 $method = $request->getMethod();
Chris@0 512 $files = $request->getFiles();
Chris@0 513 $content = $request->getContent();
Chris@0 514 }
Chris@0 515
Chris@0 516 if ('GET' === strtoupper($method)) {
Chris@0 517 // Don't forward parameters for GET request as it should reach the redirection URI
Chris@17 518 $parameters = [];
Chris@0 519 } else {
Chris@0 520 $parameters = $request->getParameters();
Chris@0 521 }
Chris@0 522
Chris@0 523 $server = $request->getServer();
Chris@0 524 $server = $this->updateServerFromUri($server, $this->redirect);
Chris@0 525
Chris@0 526 $this->isMainRequest = false;
Chris@0 527
Chris@0 528 $response = $this->request($method, $this->redirect, $parameters, $files, $server, $content);
Chris@0 529
Chris@0 530 $this->isMainRequest = true;
Chris@0 531
Chris@0 532 return $response;
Chris@0 533 }
Chris@0 534
Chris@0 535 /**
Chris@0 536 * Restarts the client.
Chris@0 537 *
Chris@0 538 * It flushes history and all cookies.
Chris@0 539 */
Chris@0 540 public function restart()
Chris@0 541 {
Chris@0 542 $this->cookieJar->clear();
Chris@0 543 $this->history->clear();
Chris@0 544 }
Chris@0 545
Chris@0 546 /**
Chris@0 547 * Takes a URI and converts it to absolute if it is not already absolute.
Chris@0 548 *
Chris@0 549 * @param string $uri A URI
Chris@0 550 *
Chris@0 551 * @return string An absolute URI
Chris@0 552 */
Chris@0 553 protected function getAbsoluteUri($uri)
Chris@0 554 {
Chris@0 555 // already absolute?
Chris@0 556 if (0 === strpos($uri, 'http://') || 0 === strpos($uri, 'https://')) {
Chris@0 557 return $uri;
Chris@0 558 }
Chris@0 559
Chris@0 560 if (!$this->history->isEmpty()) {
Chris@0 561 $currentUri = $this->history->current()->getUri();
Chris@0 562 } else {
Chris@0 563 $currentUri = sprintf('http%s://%s/',
Chris@0 564 isset($this->server['HTTPS']) ? 's' : '',
Chris@0 565 isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost'
Chris@0 566 );
Chris@0 567 }
Chris@0 568
Chris@0 569 // protocol relative URL
Chris@0 570 if (0 === strpos($uri, '//')) {
Chris@0 571 return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri;
Chris@0 572 }
Chris@0 573
Chris@0 574 // anchor or query string parameters?
Chris@0 575 if (!$uri || '#' == $uri[0] || '?' == $uri[0]) {
Chris@0 576 return preg_replace('/[#?].*?$/', '', $currentUri).$uri;
Chris@0 577 }
Chris@0 578
Chris@0 579 if ('/' !== $uri[0]) {
Chris@0 580 $path = parse_url($currentUri, PHP_URL_PATH);
Chris@0 581
Chris@0 582 if ('/' !== substr($path, -1)) {
Chris@0 583 $path = substr($path, 0, strrpos($path, '/') + 1);
Chris@0 584 }
Chris@0 585
Chris@0 586 $uri = $path.$uri;
Chris@0 587 }
Chris@0 588
Chris@0 589 return preg_replace('#^(.*?//[^/]+)\/.*$#', '$1', $currentUri).$uri;
Chris@0 590 }
Chris@0 591
Chris@0 592 /**
Chris@0 593 * Makes a request from a Request object directly.
Chris@0 594 *
Chris@0 595 * @param Request $request A Request instance
Chris@0 596 * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
Chris@0 597 *
Chris@0 598 * @return Crawler
Chris@0 599 */
Chris@0 600 protected function requestFromRequest(Request $request, $changeHistory = true)
Chris@0 601 {
Chris@0 602 return $this->request($request->getMethod(), $request->getUri(), $request->getParameters(), $request->getFiles(), $request->getServer(), $request->getContent(), $changeHistory);
Chris@0 603 }
Chris@0 604
Chris@0 605 private function updateServerFromUri($server, $uri)
Chris@0 606 {
Chris@0 607 $server['HTTP_HOST'] = $this->extractHost($uri);
Chris@0 608 $scheme = parse_url($uri, PHP_URL_SCHEME);
Chris@0 609 $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme;
Chris@0 610 unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']);
Chris@0 611
Chris@0 612 return $server;
Chris@0 613 }
Chris@0 614
Chris@0 615 private function extractHost($uri)
Chris@0 616 {
Chris@0 617 $host = parse_url($uri, PHP_URL_HOST);
Chris@0 618
Chris@0 619 if ($port = parse_url($uri, PHP_URL_PORT)) {
Chris@0 620 return $host.':'.$port;
Chris@0 621 }
Chris@0 622
Chris@0 623 return $host;
Chris@0 624 }
Chris@0 625 }