You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
3.7 KiB
PHP
132 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace Proxy\Plugin;
|
|
|
|
use Proxy\Plugin\AbstractPlugin;
|
|
use Proxy\Event\ProxyEvent;
|
|
|
|
class CookiePlugin extends AbstractPlugin {
|
|
|
|
const COOKIE_PREFIX = 'pc';
|
|
|
|
public function onBeforeRequest(ProxyEvent $event){
|
|
|
|
$request = $event['request'];
|
|
|
|
// cookie sent by the browser to the server
|
|
$http_cookie = $request->headers->get("cookie");
|
|
|
|
// remove old cookie header and rewrite it
|
|
$request->headers->remove("cookie");
|
|
|
|
/*
|
|
When the user agent generates an HTTP request, the user agent MUST NOT attach more than one Cookie header field.
|
|
http://tools.ietf.org/html/rfc6265#section-5.4
|
|
*/
|
|
$send_cookies = array();
|
|
|
|
// extract "proxy cookies" only
|
|
// A Proxy Cookie would have the following name: COOKIE_PREFIX_domain-it-belongs-to__cookie-name
|
|
if(preg_match_all('@pc_(.+?)__(.+?)=([^;]+)@', $http_cookie, $matches, PREG_SET_ORDER)){
|
|
|
|
foreach($matches as $match){
|
|
|
|
$cookie_name = $match[2];
|
|
$cookie_value = $match[3];
|
|
$cookie_domain = str_replace("_", ".", $match[1]);
|
|
|
|
// what is the domain or our current URL?
|
|
$host = parse_url($request->getUri(), PHP_URL_HOST);
|
|
|
|
// does this cookie belong to this domain?
|
|
// sometimes domain begins with a DOT indicating all subdomains - deprecated but still in use on some servers...
|
|
if(strpos($host, $cookie_domain) !== false){
|
|
$send_cookies[] = $cookie_name.'='.$cookie_value;
|
|
}
|
|
}
|
|
}
|
|
|
|
// do we have any cookies to send?
|
|
if($send_cookies){
|
|
$request->headers->set('cookie', implode("; ", $send_cookies));
|
|
}
|
|
}
|
|
|
|
// cookies received from a target server via set-cookie should be rewritten
|
|
public function onHeadersReceived(ProxyEvent $event){
|
|
|
|
$request = $event['request'];
|
|
$response = $event['response'];
|
|
|
|
// does the response send any cookies?
|
|
$set_cookie = $response->headers->get('set-cookie');
|
|
|
|
if($set_cookie){
|
|
|
|
// remove set-cookie header and reconstruct it differently
|
|
$response->headers->remove('set-cookie');
|
|
|
|
// loop through each set-cookie line
|
|
foreach( (array)$set_cookie as $line){
|
|
|
|
// parse cookie data as array from header line
|
|
$cookie = $this->parse_cookie($line, $request->getUri());
|
|
|
|
// construct a "proxy cookie" whose name includes the domain to which this cookie belongs to
|
|
// replace dots with underscores as cookie name can only contain alphanumeric and underscore
|
|
$cookie_name = sprintf("%s_%s__%s", self::COOKIE_PREFIX, str_replace('.', '_', $cookie['domain']), $cookie['name']);
|
|
|
|
// append a simple name=value cookie to the header - no expiration date means that the cookie will be a session cookie
|
|
$event['response']->headers->set('set-cookie', $cookie_name.'='.$cookie['value'], false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// adapted from browserkit
|
|
private function parse_cookie($line, $url){
|
|
|
|
$host = parse_url($url, PHP_URL_HOST);
|
|
|
|
$data = array(
|
|
'name' => '',
|
|
'value' => '',
|
|
'domain' => $host,
|
|
'path' => '/',
|
|
'expires' => 0,
|
|
'secure' => false,
|
|
'httpOnly' => true
|
|
);
|
|
|
|
$line = preg_replace('/^Set-Cookie2?: /i', '', trim($line));
|
|
|
|
// there should be at least one name=value pair
|
|
$pairs = array_filter(array_map('trim', explode(';', $line)));
|
|
|
|
foreach($pairs as $index => $comp){
|
|
|
|
$parts = explode('=', $comp, 2);
|
|
$key = trim($parts[0]);
|
|
|
|
if(count($parts) == 1){
|
|
|
|
// secure; HttpOnly; == 1
|
|
$data[$key] = true;
|
|
|
|
} else {
|
|
|
|
$value = trim($parts[1]);
|
|
|
|
if($index == 0){
|
|
$data['name'] = $key;
|
|
$data['value'] = $value;
|
|
} else {
|
|
$data[$key] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
?>
|