/** * Merge a request's data with the default data * * @param array $request Request data (same form as {@see request_multiple}) * @param boolean $merge_options Should we merge options as well? * @return array Request data */ protected function merge_request($request, $merge_options = true) { if ($this->url !== null) { $request['url'] = Requests_IRI::absolutize($this->url, $request['url']); $request['url'] = $request['url']->uri; } if (empty($request['headers'])) { $request['headers'] = array(); } $request['headers'] = array_merge($this->headers, $request['headers']); if (empty($request['data'])) { if (is_array($this->data)) { $request['data'] = $this->data; } } elseif (is_array($request['data']) && is_array($this->data)) { $request['data'] = array_merge($this->data, $request['data']); } if ($merge_options !== false) { $request['options'] = array_merge($this->options, $request['options']); // Disallow forcing the type, as that's a per request setting unset($request['options']['type']); } return $request; }
/** * HTTP response parser * * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`) * @throws Requests_Exception On missing head/body separator (`noversion`) * @throws Requests_Exception On missing head/body separator (`toomanyredirects`) * * @param string $headers Full response text including headers and body * @param string $url Original request URL * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects * * @return Requests_Response */ protected static function parse_response($headers, $url, $req_headers, $req_data, $options) { $return = new Requests_Response(); if (!$options['blocking']) { return $return; } $return->raw = $headers; $return->url = $url; if (!$options['filename']) { if (strpos($headers, "\r\n\r\n") === false) { // Crap! throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator'); } $headers = explode("\r\n\r\n", $headers, 2); $return->body = array_pop($headers); $headers = $headers[0]; } else { $return->body = ''; } // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3) $headers = str_replace("\r\n", "\n", $headers); // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2) $headers = preg_replace('/\\n[ \\t]/', ' ', $headers); $headers = explode("\n", $headers); preg_match('#^HTTP/1\\.\\d[ \\t]+(\\d+)#i', array_shift($headers), $matches); if (empty($matches)) { throw new Requests_Exception('Response could not be parsed', 'noversion', $headers); } $return->status_code = (int) $matches[1]; if ($return->status_code >= 200 && $return->status_code < 300) { $return->success = true; } foreach ($headers as $header) { list($key, $value) = explode(':', $header, 2); $value = trim($value); preg_replace('#(\\s+)#i', ' ', $value); $return->headers[$key] = $value; } if (isset($return->headers['transfer-encoding'])) { $return->body = self::decode_chunked($return->body); unset($return->headers['transfer-encoding']); } if (isset($return->headers['content-encoding'])) { $return->body = self::decompress($return->body); } //fsockopen and cURL compatibility if (isset($return->headers['connection'])) { unset($return->headers['connection']); } if ((in_array($return->status_code, [300, 301, 302, 303, 307]) || $return->status_code > 307 && $return->status_code < 400) && $options['follow_redirects'] === true) { if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) { if ($return->status_code === 303) { $options['type'] = Requests::GET; } $options['redirected']++; $location = $return->headers['location']; if (strpos($location, '/') === 0) { // relative redirect, for compatibility make it absolute $location = Requests_IRI::absolutize($url, $location); } $redirected = self::request($location, $req_headers, $req_data, false, $options); $redirected->history[] = $return; return $redirected; } elseif ($options['redirected'] >= $options['redirects']) { throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return); } } $return->redirects = $options['redirected']; $options['hooks']->dispatch('requests.after_request', [&$return, $req_headers, $req_data, $options]); return $return; }