Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More details on HTTP Status Line Header #204

Open
zmoddynamics opened this issue May 12, 2020 · 2 comments
Open

More details on HTTP Status Line Header #204

zmoddynamics opened this issue May 12, 2020 · 2 comments
Labels
status:ready for adoption Feel free to implement this issue. type:enhancement Enhancement

Comments

@zmoddynamics
Copy link

zmoddynamics commented May 12, 2020

What steps will reproduce the problem?

Assume possible response headers of these forms.

HTTP:/1.1 400 InvalidParamSince

HTTP:/1.1 400 MissingParamSince

HTTP:/1.1 400 MissingQueryParams

HTTP:/1.1 400 NoMatchForQueryParams

In your current implementation, the method call getHeaders() only returns the header status code (ie. 400) but we may need to distinguish the response header using the corresponding phrase as well. It would also be nice to parse it into constituent parts. How can we get it ?

What's expected?

Additional granularity of the HTTP status line header returned from getHeaders(). For example, assume the raw response headers from a call were:

php
array(3) {
  [0]=>
  string(48) "HTTP/1.1 404 RequestNotFound (request id=0:98:0)"
  [1]=>
  string(17) "Content-Length: 0"
  [2]=>
  string(17) "Connection: Close"
}

Expected output would provide added granularity. For example,

php
$headers = $response->getHeaders();
echo '<pre>';
var_dump($headers);
echo '</pre>';
//output
yii\web\HeaderCollection Object
(
    [_headers:yii\web\HeaderCollection:private] => Array
        (
            [http-status-line] => Array
                (
                    [0] => HTTP/1.1 404 RequestNotFound
                )

            [http-version] => Array
                (
                    [0] => HTTP/1.1
                )

            [http-status-code] => Array
                (
                    [0] => 404
                )

            [http-reason-phrase] => Array
                (
                    [0] => RequestNotFound
                )

            [http-status-code-reason-phrase] => Array
                (
                    [0] => 404 RequestNotFound
                )

            [http-code] => Array
                (
                    [0] => 404
                )

            [content-length] => Array
                (
                    [0] => 0
                )

            [connection] => Array
                (
                    [0] => Close
                )

        )

)

What do you get instead?

php
$headers = $response->getHeaders();
echo '<pre>';
var_dump($headers);
echo '</pre>';
//output
object(yii\web\HeaderCollection)#131 (1) {
  ["_headers":"yii\web\HeaderCollection":private]=>
  array(3) {
    ["http-code"]=>
    array(1) {
      [0]=>
      string(3) "404"
    }
    ["content-length"]=>
    array(1) {
      [0]=>
      string(1) "0"
    }
    ["connection"]=>
    array(1) {
      [0]=>
      string(5) "Close"
    }
  }
}

Additional info

After some investigations, I was able to obtain my expected result by overriding createResponse and extending httpclient\Client. In the code below, you could remove the bit about filtering out '(request id=' as that is specific to my application. For example,

php
use yii\httpclient\Client as Client;
class modClient extends Client
{

     /**
     * {@inheritDoc}
     */
    public function createResponse($content = null, array $headers = [])
    {
        return parent::createResponse( $content, $this->modifyHeaders($headers) );
    }

    /**
     * Returns the modified headers.
     * This function appends additional headers to $headers.
     * The additional headers consist of:
     *  'http-status-line': The full status line (ie. 'HTTP/1.1 200 OK')
     *  'http-version': The http version returned from the server (ie. 'HTTP/1.1')
     *  'http-status-code': The Status code (ie. '200')
     *  'http-reason-phrase': The reason phrase (ie. 'OK')
     *  'http-status-code-reason-phrase': The status line without the HTTP version (ie. '200 OK')
     * Additional filtering removes everything after and including '(request id=' from 'http-reason-phrase' and 'http-status-line' if found.
     * @param array $headers headers list.
     * @return array modified headers list
     */

    public function modifyHeaders(array $headers = [])
    {
        $newHeaders = $headers;
        $addHeaders = [
            'http-status-line' => '',
            'http-version' => '',
            'http-status-code' => '',
            'http-reason-phrase' => '',
            'http-status-code-reason-phrase' =>'',
        ];

        if (!is_object($newHeaders)) {
            if (is_array($newHeaders)) {
                foreach ($newHeaders as $name => $value) {
                    if (is_int($name)) {
                        // parse raw header :
                        $rawHeader = $value;
                        if (strpos($rawHeader, 'HTTP/') === 0) {
                            //removes everything after and including '(request id='
                            if( ($separatorPos = strpos($rawHeader,'(request id=')) !== false ) {
                                $rawHeader = trim(substr($rawHeader, 0, $separatorPos));
                            }
                            //parse out the various parts
                            $parts = explode(' ', $rawHeader, 3);

                            $addHeaders['http-status-line'] = $rawHeader;
                            $addHeaders['http-version'] = $parts[0];
                            $addHeaders['http-status-code'] = sizeof($parts)>1?trim($parts[1]):'';
                            $addHeaders['http-reason-phrase'] = sizeof($parts)>2?trim($parts[2]):'';
                            $addHeaders['http-status-code-reason-phrase'] = $addHeaders['http-status-code']. ' '.$addHeaders['http-reason-phrase'];
                        }
                    }
                }
            }
        }
        return array_merge($addHeaders,$newHeaders);
    }
}

With the override, and using the extended client the same original headers provides added granularity. For example,

php
$client = new modClient();
$request = $client->get('http://example.com');
$headers = $response->getHeaders();
echo '<pre>';
var_dump($headers);
echo '</pre>';

//output
object(yii\web\HeaderCollection)#131 (1) {
  ["_headers":"yii\web\HeaderCollection":private]=>
  array(8) {
    ["http-status-line"]=>
    array(1) {
      [0]=>
      string(28) "HTTP/1.1 404 RequestNotFound"
    }
    ["http-version"]=>
    array(1) {
      [0]=>
      string(8) "HTTP/1.1"
    }
    ["http-status-code"]=>
    array(1) {
      [0]=>
      string(3) "404"
    }
    ["http-reason-phrase"]=>
    array(1) {
      [0]=>
      string(15) "RequestNotFound"
    }
    ["http-status-code-reason-phrase"]=>
    array(1) {
      [0]=>
      string(19) "404 RequestNotFound"
    }
    ["http-code"]=>
    array(1) {
      [0]=>
      string(3) "404"
    }
    ["content-length"]=>
    array(1) {
      [0]=>
      string(1) "0"
    }
    ["connection"]=>
    array(1) {
      [0]=>
      string(5) "Close"
    }
  }
}
Q A
Yii version 2.0.35
Yii HTTP Client version 2.0.12
PHP version 7.4.5
Operating system UNIX
@zmoddynamics zmoddynamics changed the title Response Headers phrase More details on HTTP Status line Header May 13, 2020
@zmoddynamics zmoddynamics changed the title More details on HTTP Status line Header More details on HTTP Status Line Header May 13, 2020
@samdark samdark added the type:enhancement Enhancement label May 16, 2020
@samdark
Copy link
Member

samdark commented May 16, 2020

Looks like a good addition. Do you have time for a pull request?

@samdark samdark added the status:ready for adoption Feel free to implement this issue. label May 16, 2020
@zmoddynamics
Copy link
Author

Will do.

zmoddynamics added a commit to zmoddynamics/yii2-httpclient that referenced this issue May 17, 2020
Adds 3 new header keys to $headerCollection.
1. 'http-status-line': The full status line (ie. 'HTTP/1.1 200 OK')
2. 'http-version': The http version returned from the server (ie. 'HTTP/1.1')
3.'http-status-code-reason-phrase': The status line without the HTTP version (ie. '200 OK')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:ready for adoption Feel free to implement this issue. type:enhancement Enhancement
Projects
None yet
Development

No branches or pull requests

2 participants