Every webRequest event receives information about a request, including the ID of the originating tab.
So, assuming that the tab exists note 1, you can use the following flow:
// background.js
chrome.webRequest.onHeadersReceived.addListener(function(details) {
    if (details.tabId == -1)
        return; // Not related to any tab
    chrome.tabs.sendMessage(details.tabId, {
        responseHeaders: details.responseHeaders
    });
}, {
    urls: ['*://*/*'], // e.g. all http(s) URLs. See match patterns docs
    // types: ['image'] // for example, defaults to **all** request types
}, ['responseHeaders']);
Then, in a content script (declared in the manifest file), you take the message and pass it to the web page:
// contentscript.js
chrome.runtime.onMessage.addListener(function(message) {
    // Assuming that all messages from the background are meant for the page:
    document.dispatchEvent(new CustomEvent('my-extension-event', {
        detail: message
    }));
});
After doing that, your web page can just receive these events as follows:
document.addEventListener('my-extension-event', function(event) {
    var message = event.detail;
    if (message.responseHeaders) {
        // Do something with response headers
    }
});
If you want to put an abstraction on top (e.g. implementing a custom EventEmitter), then you need to inject a script in the main execution environment, and declare your custom API over there.
note 1. For simplicity, I assumed that the tab existed. In reality, that is never true for type "main_frame" (and "sub_frame"), because the page has not yet been rendered. If you want to get response headers for the top-level/frame documents, then you need to temporarily store the response headers in some data structure (e.g. a queue / dictionary) in the background page, and send the data to the content script whenever the script is ready.
This can be implemented by using chrome.runtime.sendMessage in the content script to send a message to the background page. Then, whenever a page has loaded and the content script is ready, the background page can use sendResponse to deliver any queued messages.