/** * Get the values of trusted proxy header. * * @param string $type One of the HEADER_* constants * @param Request $request The request to get the trusted proxy header from * @return \Iterator An array of the values for this header type or NULL if this header type should not be trusted */ protected function getTrustedProxyHeaderValues($type, Request $request) { $trustedHeaders = isset($this->settings['headers'][$type]) ? $this->settings['headers'][$type] : ''; if ($trustedHeaders === '' || !$request->getAttribute(Request::ATTRIBUTE_TRUSTED_PROXY)) { (yield null); return; } $trustedHeaders = array_map('trim', explode(',', $trustedHeaders)); foreach ($trustedHeaders as $trustedHeader) { if ($request->hasHeader($trustedHeader)) { (yield array_map('trim', explode(',', $request->getHeader($trustedHeader)))); } } (yield null); }
/** * Analyzes this response, considering the given request and makes additions * or removes certain headers in order to make the response compliant to * RFC 2616 and related standards. * * It is recommended to call this method before the response is sent and Flow * does so by default in its built-in HTTP request handler. * * @param Request $request The corresponding request * @return void * @api */ public function makeStandardsCompliant(Request $request) { if ($request->hasHeader('If-Modified-Since') && $this->headers->has('Last-Modified') && $this->statusCode === 200) { $ifModifiedSinceDate = $request->getHeader('If-Modified-Since'); $lastModifiedDate = $this->headers->get('Last-Modified'); if ($lastModifiedDate <= $ifModifiedSinceDate) { $this->setStatus(304); $this->content = ''; } } elseif ($request->hasHeader('If-Unmodified-Since') && $this->headers->has('Last-Modified') && ($this->statusCode >= 200 && $this->statusCode <= 299 || $this->statusCode === 412)) { $unmodifiedSinceDate = $request->getHeader('If-Unmodified-Since'); $lastModifiedDate = $this->headers->get('Last-Modified'); if ($lastModifiedDate > $unmodifiedSinceDate) { $this->setStatus(412); } } if (in_array($this->statusCode, [100, 101, 204, 304])) { $this->content = ''; } if ($this->headers->getCacheControlDirective('no-cache') !== null || $this->headers->has('Expires')) { $this->headers->removeCacheControlDirective('max-age'); } if ($request->getMethod() === 'HEAD') { if (!$this->headers->has('Content-Length')) { $this->headers->set('Content-Length', strlen($this->content)); } $this->content = ''; } if (!$this->headers->has('Content-Length')) { $this->headers->set('Content-Length', strlen($this->content)); } if ($this->headers->has('Transfer-Encoding')) { $this->headers->remove('Content-Length'); } }
/** * Sends the given HTTP request * * @param Http\Request $request * @return Http\Response The response or FALSE * @api * @throws Http\Exception * @throws CurlEngineException */ public function sendRequest(Http\Request $request) { if (!extension_loaded('curl')) { throw new Http\Exception('CurlEngine requires the PHP CURL extension to be installed and loaded.', 1346319808); } $requestUri = $request->getUri(); $curlHandle = curl_init((string) $requestUri); curl_setopt_array($curlHandle, $this->options); // Send an empty Expect header in order to avoid chunked data transfer (which we can't handle yet). // If we don't set this, cURL will set "Expect: 100-continue" for requests larger than 1024 bytes. curl_setopt($curlHandle, CURLOPT_HTTPHEADER, ['Expect:']); // If the content is a stream resource, use cURL's INFILE feature to stream it $content = $request->getContent(); if (is_resource($content)) { curl_setopt_array($curlHandle, [CURLOPT_INFILE => $content, CURLOPT_INFILESIZE => $request->getHeader('Content-Length')]); } switch ($request->getMethod()) { case 'GET': if ($request->getContent()) { // workaround because else the request would implicitly fall into POST: curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'GET'); if (!is_resource($content)) { curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $content); } } break; case 'POST': curl_setopt($curlHandle, CURLOPT_POST, true); if (!is_resource($content)) { $body = $content !== '' ? $content : http_build_query($request->getArguments()); curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); } break; case 'PUT': curl_setopt($curlHandle, CURLOPT_PUT, true); if (!is_resource($content) && $content !== '') { $inFileHandler = fopen('php://temp', 'r+'); fwrite($inFileHandler, $request->getContent()); rewind($inFileHandler); curl_setopt_array($curlHandle, [CURLOPT_INFILE => $inFileHandler, CURLOPT_INFILESIZE => strlen($request->getContent())]); } break; default: if (!is_resource($content)) { $body = $content !== '' ? $content : http_build_query($request->getArguments()); curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); } curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, $request->getMethod()); } $preparedHeaders = []; foreach ($request->getHeaders()->getAll() as $fieldName => $values) { foreach ($values as $value) { $preparedHeaders[] = $fieldName . ': ' . $value; } } curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $preparedHeaders); // curl_setopt($curlHandle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP && CURLPROTO_HTTPS); // CURLOPT_UPLOAD if ($requestUri->getPort() !== null) { curl_setopt($curlHandle, CURLOPT_PORT, $requestUri->getPort()); } // CURLOPT_COOKIE $curlResult = curl_exec($curlHandle); if ($curlResult === false) { throw new CurlEngineException(sprintf('cURL reported error code %s with message "%s". Last requested URL was "%s" (%s).', curl_errno($curlHandle), curl_error($curlHandle), curl_getinfo($curlHandle, CURLINFO_EFFECTIVE_URL), $request->getMethod()), 1338906040); } elseif (strlen($curlResult) === 0) { return false; } curl_close($curlHandle); $response = Http\Response::createFromRaw($curlResult); if ($response->getStatusCode() === 100) { $response = Http\Response::createFromRaw($response->getContent(), $response); } return $response; }
/** * Parses the request body according to the media type. * * @param HttpRequest $httpRequest * @return array */ protected function parseRequestBody(HttpRequest $httpRequest) { $requestBody = $httpRequest->getContent(); if ($requestBody === null || $requestBody === '') { return []; } $mediaTypeConverter = $this->objectManager->get(MediaTypeConverterInterface::class); $propertyMappingConfiguration = new PropertyMappingConfiguration(); $propertyMappingConfiguration->setTypeConverter($mediaTypeConverter); $propertyMappingConfiguration->setTypeConverterOption(MediaTypeConverterInterface::class, MediaTypeConverterInterface::CONFIGURATION_MEDIA_TYPE, $httpRequest->getHeader('Content-Type')); $arguments = $this->propertyMapper->convert($requestBody, 'array', $propertyMappingConfiguration); return $arguments; }