WP_Http_Cookie destroys cookie value through urldecode()

Background: Working on a Widget that uses a remote API using wp_remote_post to log into the service, once logged in storing the cookies received for the second request to query data with wp_remote_get.

Problem: The cookies from the first request are stored in the response as WP_Http_Cookie objects and their values are run through urldecode as seen in class-http.php. One of the cookies has an original value of l0xl4+7abTT2St+1UVA thanks to the urldecode this value becomes l0xl4 7abTT2St 1UVA in the WP_Http_Cookie object and therefore is not the same. This makes the cookie object unusable as is for the second request.

Read More

Workaround: I came up with a nasty little workaround for this problem:

// Replace space with + from cookie value
// because WP_Http_Cookie does urldecode( value )
$response['cookies'][0]->value = str_replace(' ', '+', $response['cookies'][0]->value);

// Set cookies for the second request
$this->cookies = $response['cookies'];

Question: Does anyone know why there is an urldecode instead of a filter in WP_Http_Cookie? Should I file a trac issue?

Related posts

Leave a Reply

2 comments

  1. AFAIK URL encoding the cookie value is still kind of a defacto standard, it’s an ancient relict based on the old, ugly Netscape cookie specs, that basically says that semicolons, commas and whitespaces are disallowed, and should be encoded, for example using URL encoding. Neither does it does it require enocding, nor does it force the use or URL encoding, but that’s how it was implemented.

    So when passing a string to the constructor, WP_Http_Cookie assumes that the data is from a cookie, and therefore the cookie value is encoded and needs to be decoded. Personally i think it should not do that, and leave it up to the developer to handle values as needed, as mentioned in Ticket 19922.

    However, when dispatching a request, WP_Http_Cookie::getHeaderValue is invoked, and this is where a filter is available, wp_http_cookie_value. Assuming that the cookie value you are receiving is URL encoded, you could re-encode it using this filter.

    function wp_http_cookie_value_filter($value, $name)
    {
        return urlencode($value);
    }
    add_filter('wp_http_cookie_value', 'wp_http_cookie_value_filter', 10, 2);
    

    However this would ofcourse apply to all requests, so as long as you can’t tell for sure that you are the only one using this filter and/or making requests that contain cookies, it’s probably a pretty bad idea.

    Maybe if your cookie has a very unique name you could use that to filter only your specific cookie values:

    function wp_http_cookie_value_filter($value, $name)
    {
        if($name === 'my_very_special_cookie')
        {
            return urlencode($value);
        }
        return $value;
    }
    add_filter('wp_http_cookie_value', 'wp_http_cookie_value_filter', 10, 2);
    

    Other than that you are probably better off using your workaround, ie manipulate the cookie value only for your specific requests.

  2. Virtually all implementations of cookies are URL encoded. If you’re sending a raw cookie, without encoding, then you need to control both ends of the pipeline. Since you don’t, urlencode your cookies.