142 lines
4.1 KiB
JavaScript
142 lines
4.1 KiB
JavaScript
const logger = require('../utils/logger');
|
|
const RequestValidator = require('./validation');
|
|
const UserAgentFilter = require('./userAgentFilter');
|
|
|
|
/**
|
|
* Request Processing Pipeline - Equivalent to Kamailio's main request_route
|
|
* This is the primary entry point for all SIP requests received by Drachtio
|
|
*/
|
|
class RequestProcessor {
|
|
constructor(srf) {
|
|
this.srf = srf;
|
|
this.validator = new RequestValidator();
|
|
this.uaFilter = new UserAgentFilter();
|
|
}
|
|
|
|
/**
|
|
* Handle OPTIONS requests (equivalent to kamailio.cfg:297-301)
|
|
*/
|
|
handleOptions(req, res) {
|
|
logger.info('[OPTIONS] Options request from %s:%s | Call-ID: %s',
|
|
req.source_address, req.source_port, req.get('Call-ID'));
|
|
res.send(200, 'OK');
|
|
}
|
|
|
|
/**
|
|
* Handle CANCEL requests (equivalent to kamailio.cfg:196-201)
|
|
*/
|
|
handleCancel(req, res) {
|
|
const callId = req.get('Call-ID');
|
|
logger.info('[CANCEL] CANCEL: Call-ID: %s', callId);
|
|
|
|
// Check if transaction exists
|
|
if (this.srf.hasUacTransaction(callId)) {
|
|
// Relay the CANCEL to the appropriate destination
|
|
this.srf.createUacRequest('CANCEL', req.uri, {
|
|
headers: {
|
|
'Call-ID': callId,
|
|
'CSeq': req.get('CSeq'),
|
|
'From': req.get('From'),
|
|
'To': req.get('To'),
|
|
'Via': req.get('Via'),
|
|
'Route': req.get('Route'),
|
|
'Max-Forwards': req.get('Max-Forwards')
|
|
}
|
|
})
|
|
.then(() => {
|
|
res.send(200, 'OK');
|
|
})
|
|
.catch((err) => {
|
|
logger.error('[CANCEL] Failed to relay CANCEL: %s', err.message);
|
|
res.send(500, 'Server Error');
|
|
});
|
|
} else {
|
|
res.send(481, 'Transaction Does Not Exist');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle in-dialog requests (equivalent to kamailio.cfg:239-241)
|
|
*/
|
|
handleInDialog(req, res, next) {
|
|
if (req.has('To') && req.getParsedHeader('to').params.tag && req.method !== 'INVITE') {
|
|
logger.info('[WITHINDLG] %s request | Call-ID: %s', req.method, req.get('Call-ID'));
|
|
// Pass to in-dialog handler
|
|
next();
|
|
} else {
|
|
next();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle presence-related requests (equivalent to kamailio.cfg:304)
|
|
*/
|
|
handlePresence(req, res) {
|
|
if (req.method === 'PUBLISH' || req.method === 'SUBSCRIBE') {
|
|
logger.info('[PRESENCE] %s request from %s:%s | Call-ID: %s',
|
|
req.method, req.source_address, req.source_port, req.get('Call-ID'));
|
|
res.send(404, 'Not here');
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Handle requests that don't match specific routes (equivalent to kamailio.cfg:312-315)
|
|
*/
|
|
handleUnmatchedRequest(req, res) {
|
|
logger.warn('[MAIN_ROUTE] No specific route found for method: %s to %s | Call-ID: %s',
|
|
req.method, req.uri.user, req.get('Call-ID'));
|
|
res.send(501, 'Not Implemented - No action found for destination or method');
|
|
}
|
|
|
|
/**
|
|
* Main request processing pipeline
|
|
*/
|
|
processRequest() {
|
|
return (req, res, next) => {
|
|
logger.debug('[REQUEST_PROCESSOR] Processing %s request from %s:%s',
|
|
req.method, req.source_address, req.source_port);
|
|
|
|
// Apply validation middleware
|
|
this.validator.middleware()(req, res, () => {
|
|
// Apply User-Agent filtering
|
|
this.uaFilter.middleware()(req, res, () => {
|
|
// Handle specific method types
|
|
switch (req.method) {
|
|
case 'OPTIONS':
|
|
this.handleOptions(req, res);
|
|
break;
|
|
|
|
case 'CANCEL':
|
|
this.handleCancel(req, res);
|
|
break;
|
|
|
|
case 'REGISTER':
|
|
// Pass to registration handler
|
|
next();
|
|
break;
|
|
|
|
case 'INVITE':
|
|
// Pass to INVITE handler
|
|
next();
|
|
break;
|
|
|
|
default:
|
|
// Handle in-dialog requests
|
|
this.handleInDialog(req, res, () => {
|
|
// Check for presence requests
|
|
if (!this.handlePresence(req, res)) {
|
|
// If no specific handler, return error
|
|
this.handleUnmatchedRequest(req, res);
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = RequestProcessor; |