We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit bd6efa0e authored by mattl's avatar mattl

Update PuSH callback URL if remote side switched to HTTPS

See the comment in the source on why we're not following Location headers...
parent f24cdf4a
......@@ -40,7 +40,7 @@ class HubSub extends Managed_DataObject
public $created;
public $modified;
protected static function hashkey($topic, $callback)
static function hashkey($topic, $callback)
{
return sha1($topic . '|' . $callback);
}
......@@ -120,6 +120,11 @@ class HubSub extends Managed_DataObject
$qm->enqueue($data, 'hubconf');
}
public function getTopic()
{
return $this->topic;
}
/**
* Send a verification ping to subscriber, and if confirmed apply the changes.
* This may create, update, or delete the database record.
......@@ -134,7 +139,7 @@ class HubSub extends Managed_DataObject
$challenge = common_random_hexstr(32);
$params = array('hub.mode' => $mode,
'hub.topic' => $this->topic,
'hub.topic' => $this->getTopic(),
'hub.challenge' => $challenge);
if ($mode == 'subscribe') {
$params['hub.lease_seconds'] = $this->lease;
......@@ -157,13 +162,13 @@ class HubSub extends Managed_DataObject
$status = $response->getStatus();
if ($status >= 200 && $status < 300) {
common_log(LOG_INFO, "Verified {$mode} of {$this->callback}:{$this->topic}");
common_log(LOG_INFO, "Verified {$mode} of {$this->callback}:{$this->getTopic()}");
} else {
// TRANS: Client exception. %s is a HTTP status code.
throw new ClientException(sprintf(_m('Hub subscriber verification returned HTTP %s.'),$status));
}
$old = HubSub::getByHashkey($this->topic, $this->callback);
$old = HubSub::getByHashkey($this->getTopic(), $this->callback);
if ($mode == 'subscribe') {
if ($old instanceof HubSub) {
$this->update($old);
......@@ -185,7 +190,7 @@ class HubSub extends Managed_DataObject
*/
function insert()
{
$this->hashkey = self::hashkey($this->topic, $this->callback);
$this->hashkey = self::hashkey($this->getTopic(), $this->callback);
$this->created = common_sql_now();
$this->modified = common_sql_now();
return parent::insert();
......@@ -208,11 +213,11 @@ class HubSub extends Managed_DataObject
// destroy the result data for the parent query.
// @fixme use clone() again when it's safe to copy an
// individual item from a multi-item query again.
$sub = HubSub::getByHashkey($this->topic, $this->callback);
$sub = HubSub::getByHashkey($this->getTopic(), $this->callback);
$data = array('sub' => $sub,
'atom' => $atom,
'retries' => $retries);
common_log(LOG_INFO, "Queuing PuSH: $this->topic to $this->callback");
common_log(LOG_INFO, "Queuing PuSH: {$this->getTopic()} to {$this->callback}");
$qm = QueueManager::get();
$qm->enqueue($data, 'hubout');
}
......@@ -229,10 +234,9 @@ class HubSub extends Managed_DataObject
function bulkDistribute($atom, $pushCallbacks)
{
$data = array('atom' => $atom,
'topic' => $this->topic,
'topic' => $this->getTopic(),
'pushCallbacks' => $pushCallbacks);
common_log(LOG_INFO, "Queuing PuSH batch: $this->topic to " .
count($pushCallbacks) . " sites");
common_log(LOG_INFO, "Queuing PuSH batch: {$this->getTopic()} to ".count($pushCallbacks)." sites");
$qm = QueueManager::get();
$qm->enqueue($data, 'hubprep');
}
......@@ -256,18 +260,58 @@ class HubSub extends Managed_DataObject
} else {
$hmac = '(none)';
}
common_log(LOG_INFO, "About to push feed to $this->callback for $this->topic, HMAC $hmac");
common_log(LOG_INFO, "About to push feed to $this->callback for {$this->getTopic()}, HMAC $hmac");
$request = new HTTPClient();
$request->setBody($atom);
$response = $request->post($this->callback, $headers);
try {
$response = $request->post($this->callback, $headers);
if ($response->isOk()) {
return true;
} else {
// TRANS: Exception. %1$s is a response status code, %2$s is the body of the response.
throw new Exception(sprintf(_m('Callback returned status: %1$s. Body: %2$s'),
$response->getStatus(),trim($response->getBody())));
if ($response->isOk()) {
return true;
}
} catch (Exception $e) {
$response = null;
common_debug('PuSH callback to '._ve($this->callback).' for '._ve($this->getTopic()).' failed with exception: '._ve($e->getMessage()));
}
// XXX: DO NOT trust a Location header here, _especially_ from 'http' protocols,
// but not 'https' either at least if we don't do proper CA verification. Trust that
// the most common change here is simply switching 'http' to 'https' and we will
// solve 99% of all of these issues for now. There should be a proper mechanism
// if we want to change the callback URLs, preferrably just manual resubscriptions
// from the remote side, combined with implemented PuSH subscription timeouts.
// We failed the PuSH, but it might be that the remote site has changed their configuration to HTTPS
if ('http' === parse_url($this->callback, PHP_URL_SCHEME)) {
// Test if the feed callback for this node has migrated to HTTPS
$httpscallback = preg_replace('/^http/', 'https', $this->callback, 1);
if ($httpscallback === $this->callback) {
throw new ServerException('Trying to preg_replace http to https on '._ve($this->callback).' failed and resulted in an identical string: '._ve($httpscallback).'.');
}
common_debug('PuSH callback to '._ve($this->callback).' for '._ve($this->getTopic()).' testing with HTTPS callback: '._ve($httpscallback));
$response = $request->post($httpscallback, $headers);
if ($response->isOk()) {
$orig = clone($this);
$this->callback = $httpscallback;
$this->hashkey = self::hashkey($this->getTopic(), $this->callback);
common_debug('HubSub DEBUG, from '._ve($orig).' to '._ve($this));
$this->updateWithKeys($orig, 'hashkey');
return true;
}
}
// FIXME: Add 'failed' incremental count for this callback.
if (is_null($response)) {
// This means we got a lower-than-HTTP level error, like domain not found or maybe connection refused
// This should be using a more distinguishable exception class, but for now this will do.
throw new Exception(sprintf(_m('HTTP request failed without response to URL: %s'), var_export($target, true)));
}
// TRANS: Exception. %1$s is a response status code, %2$s is the body of the response.
throw new Exception(sprintf(_m('Callback returned status: %1$s. Body: %2$s'),
$response->getStatus(),trim($response->getBody())));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment