Update PuSH callback URL if remote side switched to HTTPS
See the comment in the source on why we're not following Location headers...
This commit is contained in:
parent
f24cdf4a80
commit
bd6efa0e45
@ -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())));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user