What is WebSub?
WebSub (previously known as PubSubHubbub) is an open standard for:
- Push-based distribution of content changes
- Hub-mediated publication workflows
- Real-time notifications instead of polling
Benefits for HuntFeed
- Real-time updates - Get news immediately when published
- Reduced bandwidth - No empty polling requests
- Lower latency - Instant notification delivery
- Better UX - Users see content faster
- Scalable - Hub handles distribution to many subscribers
Architecture
┌─────────────────────────────────────────────────────┐
│ WebSub System │
├─────────────────────────────────────────────────────┤
│ │
│ WebSubSubscriber │
│ ├─ subscribe() │
│ ├─ unsubscribe() │
│ ├─ verifyChallenge() │
│ ├─ handleNotification() │
│ └─ detectHubFromFeed() │
│ │
│ WebSubManager (Orchestration) │
│ ├─ registerFeedWithWebSub() │
│ ├─ registerMultipleFeeds() │
│ ├─ getSubscriptionStatus() │
│ └─ handleWebSubNotification() │
│ │
│ WebSubHandler (HTTP Endpoint) │
│ ├─ GET (verification challenge) │
│ └─ POST (push notification) │
│ │
└─────────────────────────────────────────────────────┘
Components
WebSubSubscriber
Core subscription management, handles hub communication, subscription lifecycle.
WebSubManager
Orchestration layer, manages multiple subscriptions, handles notification distribution.
WebSubHandler
HTTP endpoint handling, verification challenges, notification reception.
Workflow
1
Discovery
Your app fetches the feed and discovers the WebSub hub:
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title>
<link rel="hub" href="https://hub.example.com/" />
<link rel="self" href="https://example.com/feed.xml" />
...
</feed>
2
Subscription
Your app subscribes to the hub:
POST /hub HTTP/1.1
Host: hub.example.com
hub.callback=https://your-domain.com/websub-callback.php
hub.mode=subscribe
hub.topic=https://example.com/feed.xml
hub.lease_seconds=86400
hub.secret=your_secret_key
3
Verification
Hub verifies your callback endpoint:
GET /websub-callback.php?hub.mode=subscribe&
hub.topic=https://example.com/feed.xml&
hub.challenge=random_challenge_string&
hub.lease_seconds=86400
4
Notification
Hub pushes updates when feed changes:
POST /websub-callback.php HTTP/1.1
Host: your-domain.com
Content-Type: application/atom+xml
X-Hub-Signature: sha1=hmac_signature
<feed>...updated feed content...</feed>
Implementation Guide
Basic Setup
use Hosseinhunta\Huntfeed\Hub\FeedManager;
use Hosseinhunta\Huntfeed\WebSub\WebSubManager;
// Initialize
$feedManager = new FeedManager();
$callbackUrl = 'https://your-domain.com/websub-callback.php';
$webSubManager = new WebSubManager($feedManager, $callbackUrl);
// Configure
$webSubManager
->setAutoSubscribe(true) // Auto-subscribe to hubs
->setFallbackToPolling(true) // Fallback if no hub
->setLeaseSeconds(86400); // 24-hour subscription
Callback Endpoint
Create websub-callback.php:
use Hosseinhunta\Huntfeed\Hub\FeedManager;
use Hosseinhunta\Huntfeed\WebSub\WebSubManager;
use Hosseinhunta\Huntfeed\WebSub\WebSubHandler;
// Setup
$feedManager = new FeedManager();
$callbackUrl = 'https://your-domain.com/websub-callback.php';
$webSubManager = new WebSubManager($feedManager, $callbackUrl);
$handler = $webSubManager->getHandler();
// Get request data
$method = $_SERVER['REQUEST_METHOD'];
$body = file_get_contents('php://input');
$headers = getallheaders();
// Process request
$result = $handler->processRequest($method, $_GET, $body, $headers);
// Handle verification
if ($method === 'GET') {
http_response_code($result['status'] ?? 200);
echo $result['challenge'] ?? '';
exit;
}
// Handle notification
if ($method === 'POST') {
$notification = $webSubManager->handleWebSubNotification(
$body,
$headers,
function($items) {
foreach ($items as $item) {
// Process each item
processNewItem($item);
}
}
);
http_response_code($notification['success'] ? 204 : 400);
exit;
}
Hub Detection
HuntFeed automatically detects hubs in feeds:
$hubUrl = WebSubSubscriber::detectHubFromFeed($feedContent);
if ($hubUrl) {
echo "WebSub hub found: $hubUrl";
// Subscribe to this hub
} else {
echo "No WebSub hub found, falling back to polling";
// Fallback to polling
}
Security Considerations
Signature Verification
HuntFeed automatically verifies HMAC-SHA1 signatures:
// HuntFeed automatically handles this internally:
// Calculate HMAC-SHA1 of body with secret:
$expectedSignature = hash_hmac('sha1', $body, $secret);
$requestSignature = $headers['X-Hub-Signature'];
if (!hash_equals($expectedSignature, $requestSignature)) {
// Reject notification
http_response_code(403);
exit;
}
Best Practices
- ✅ Always use HTTPS in production
- ✅ Validate signatures for each notification
- ✅ Use strong secrets (32-byte random strings)
- ✅ Store secrets securely (environment variables)
- ✅ Implement rate limiting on callback endpoint
- ✅ Log all subscription activities for auditing
- ✅ Monitor hub availability and health
Performance Comparison
| Metric | Traditional Polling | WebSub with HuntFeed |
|---|---|---|
| Requests (no updates) | ∞ (every poll interval) | 0 (push only) |
| Update Latency | Minutes to hours | < 1 second |
| Bandwidth Usage | High (full feed transfers) | Very Low (push notifications) |
| Server Load | High (continuous polling) | Low (event-driven) |
| Real-time Updates | ❌ No | ✅ Yes |
| Scaling | Difficult | Easy |
Optimization Tips
- Cache subscriptions - Store in database to survive restarts
- Queue processing - Use background jobs for notifications
- Batch inserts - Insert items in batches, not individually
- Index smartly - Pre-index common search fields
- Monitor health - Track subscription renewals and failures
Troubleshooting
Common Issues
"No WebSub Hub Found"
- Check feed contains
<link rel="hub" /> - Verify hub URL is valid and accessible
- Some feeds don't have hubs - fallback to polling works fine
"Subscription Verification Failed"
- Ensure callback URL is publicly accessible
- Check firewall allows incoming requests
- Verify HTTP method (should be GET for verification)
- Return HTTP 200 with challenge in body
"Notification Not Received"
- Verify subscription was verified
- Check callback URL in subscription request
- Ensure endpoint returns HTTP 204
- Monitor server logs for incoming requests
"Signature Verification Failed"
- Confirm secret matches subscription request
- Check HMAC algorithm (should be sha1)
- Verify header format:
sha1=<signature> - Ensure hub sends X-Hub-Signature header