Skip to content

Bug: CURLRequest keeps the last value provided by headers with the same name #5041

@NicolaeIotu

Description

@NicolaeIotu

It is not possible to get and forward all headers having multiple values of a response when performing a CURLRequest.
My experience was with 'set-cookie' header, but after investigating it was pretty obvious that the CURLRequest (and probably other involved or related classes) will only retain the last value of headers with the same name and in case of redirection trigger ErrorException: Header may not contain more than a single header, new line detected (SYSTEMPATH/HTTP/ResponseTrait.php at line 471).

The following fixed the issue for me:

System\HTTP\CURLRequest

    protected function parseOptions(array $options)
    {
        if (array_key_exists('baseURI', $options)) {
            $this->baseURI = $this->baseURI->setURI($options['baseURI']);
            unset($options['baseURI']);
        }

        if (array_key_exists('headers', $options) && is_array($options['headers'])) {
            foreach ($options['headers'] as $name => $value) {
                // my adjustment
                if($this->hasHeader($name)) {
                    $this->appendHeader($name, $value);
                } else {
                    $this->setHeader($name, $value);
                }
                // end my adjustment
            }

            unset($options['headers']);
        }
...

System\HTTP\ResponseTrait

    public function sendHeaders()
    {
        // Have the headers already been sent?
        if ($this->pretend || headers_sent()) {
            return $this;
        }

        // Per spec, MUST be sent with each request, if possible.
        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
        if (! isset($this->headers['Date']) && PHP_SAPI !== 'cli-server') {
            $this->setDate(DateTime::createFromFormat('U', (string) time()));
        }

        // HTTP Status
        header(sprintf('HTTP/%s %s %s', $this->getProtocolVersion(), $this->getStatusCode(), $this->getReason()), true, $this->getStatusCode());

        // Send all of our headers
        foreach (array_keys($this->getHeaders()) as $name) {
            // my adjustment
            $headerValue = $this->getHeader($name)->getValue();
            if(is_array($headerValue)) {
                foreach($headerValue as $h_value) {
                    header($name . ': ' . $h_value, false, $this->getStatusCode());
                }
            } else {
                header($name . ': ' . $this->getHeaderLine($name), false, $this->getStatusCode());
            }
        // end my adjustment
        }

        return $this;
    }

CodeIgniter 4 version
4.1.3

Affected module(s)
System\HTTP\CURLRequest
System\HTTP\ResponseTrait
probably some of the other classes as well

Expected behavior, and steps to reproduce if appropriate

  1. Perform a CURLRequest
  2. Obtain response with multiple values for i.e. 'set-cookie' header: expected - all values, obtained - the last value
  3. Redirect to endpoint while passing all 'set-cookie' headers: expected - redirection OK, obtained - error

Context
All

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugVerified issues on the current code behavior or pull requests that will fix them

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions