Handler drove through handler, or why everything slows down

It’s been 10 years since my previous analysis of, I’m not afraid of this word, shitty software, when another problem appeared that I wanted to figure out and fix.

TLDR

How it all began

Some time ago it happened that the TV became the only available way to output sound from my PC, and in fact, took the role of a second monitor. Well, since he is now occupied by a computer, the question arose – how can I watch documentaries on YouTube while falling asleep? Since I'm too lazy to make playlists in advance, I needed control from my phone, through the official YouTube application. Constantly switching between HDMI and YouTube App on TV was not at all in my interests, I started looking for a solution, which was found very quickly – the platform already has ready interface for TV on the web, but there was a problem: when opened in the browser, it simply redirects to the main page.
The solution to this problem did not take long to arrive; there are a bunch of extensions for Chrome that allow you to solve the problem with the redirect. In the end, my choice settled on Youtube TV On PC, because it worked and had a relatively good rating. But everything was not as colorful as I dreamed…

Problems appearing

In the following text, “TV” refers to the web version of YouTube TV

I encountered the first problem after probably a week – the application could not connect to TV. And the TV download itself could take several minutes. But after that everything worked successfully until similar behavior started again.
I didn’t pay much attention to this, since I use other extensions, incl. and to block ads, and at that time YouTube was actively slowing down the service for such users.

I encountered the second problem a few months later, when I used a laptop instead of a PC – the video began to slow down like hell and chrome began to eat away at the processor. This was due to the fact that on YouTube my videos were played in maximum quality, and in most cases this is 4k60. I also successfully ignored this problem, because… A few days later I returned to the PC again, and this did not cause any problems. Until my provider decided that 10Mbps was enough for me. But even then the problem was resolved by a dispute with the provider.

Time passed, the number changed, not a damn thing changed

In general, I suffered in this way for about six months, and I was fed up with it. Because in addition to the previously announced problems, there was one more, the most annoying one – more than one tab froze, all of Chrome froze, even the Chrome task manager froze.
I had no desire to understand how to debug software in Windows, but the problem had to be fixed somehow. I decided to use ProcessExplorer to find the very process that was hanging and look at its stacktrace. The process was found, at the top of the stack there was something about …crash…. Well, I think you've got it. If something crashes somewhere, then something must go into the logs. I turn on logging in Chrome, wait a week, get stuck again, and… And there is absolutely nothing in the logs. I monitored for several more months in the hope of catching something.

Last straw

Once again everything froze for a few minutes, but… I was busy with work at the time, it made me very angry, and I decided to finally end it.
I think, what will happen if we shoot this expansion process? Shift+Esc, End process, freeze! That's it, scoundrel, I'm caught!
Considering my laziness, I probably should have gone and installed another extension, but no, it was already a matter of principle, I need to get to the bottom of the truth. Therefore, I download the CRX archive, pour a mug of kvass and go ahead. You never know, maybe the miner was spinning there all this time, but it turned out to be much simpler and more boring.

Sources

Having opened the extension in the archiver, I saw background.js the following content:

const userAgent = "Mozilla/5.0 (SMART-TV; LINUX; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) 69.0.3497.106.1/5.5 TV Safari/537.36";
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
	chrome.webRequest.onBeforeSendHeaders.addListener(function (details) {
		for (var i = 0; i < details.requestHeaders.length; ++i) {
			if (details.requestHeaders[i].name === "User-Agent") {
				details.requestHeaders[i].value = userAgent;
				break;
			}
		}
		return { requestHeaders: details.requestHeaders };
	}, { urls: ['*://www.youtube.com/tv*'] }, ['blocking', 'requestHeaders']);

	if (changeInfo.status == "complete" && tab.url.includes("youtube") && tab.url.includes("watch?v=")) {
		chrome.tabs.executeScript(tabId, {
			file: "/hd.js"
		});
	}
});

And then I understand the whole %%% of what is happening, and where the freezes come from, and where 4k60 comes from everywhere possible. And now, in order…

  1. The extension adds a handler for all events of all tabs! Yes, as it turned out, the extension does not have a domain limitation specified in its manifest, and in the addListener not specified filterwhich would allow you to filter out unnecessary events, at least by URL and event type.

  2. Inside the handler, which, let me remind you, is called for all tabs and for all types of events, of which at least 12 piecesthe required handler is added webRequest.onBeforeSendHeaderswhich at least is called only from the page www.youtube.com/tv.

  3. It is checked that the URL of the tab from which the event came contains youtube And watch?v=and executes the script, which turns on the maximum quality in the player.

If we calculate very roughly, then we have the fact that when you open a browser with 50 tabs (I don’t know about you, but for me this is a normal situation), we add approximately 200 handlers for webRequest.onBeforeSendHeaders. This is if you count the events of changing url, favicon, page title and loading status. Next, you can also add events that occur while using the browser, and as I said above, freezes happened about a week after launch. There are also sites like VK, where the favicon changes every few seconds for incoming messages.

hd.js is not particularly interesting
var scriptTag = document.getElementById('ytTvHd');
if (scriptTag) {
	scriptTag.remove();
}
var script = document.createElement('script');
script.id = "ytTvHd";
script.type="text/javascript";
script.textContent = "var ytvPlayer = document.getElementById('movie_player') || document.querySelector('.html5-video-player');ytvPlayer.setPlaybackQualityRange('highres');" +
	"document.getElementsByTagName('body')[0].onkeydown = function(e) {if (e.keyCode == 428) {ytvPlayer.requestFullscreen();}};";
document.body.appendChild(script);

conclusions

For myself, I made an obvious conclusion: problems should always be looked for on the surface, and first of all, evaluate the straightforwardness of the developers of simple things, and not try to find the problem by approaching from the other end. And I solved the problem with the extension by shortening the code and installing it from a local directory.

const userAgent = "Mozilla/5.0 (SMART-TV; LINUX; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) 69.0.3497.106.1/5.5 TV Safari/537.36";

chrome.webRequest.onBeforeSendHeaders.addListener(function (details) {
	for (var i = 0; i < details.requestHeaders.length; ++i) {
		if (details.requestHeaders[i].name === "User-Agent") {
			details.requestHeaders[i].value = userAgent;
			break;
		}
	}
	return { requestHeaders: details.requestHeaders };
}, { urls: ['*://www.youtube.com/tv*'] }, ['blocking', 'requestHeaders']);

Probably any other extension for changing HTTP headers would be suitable to solve my problem, but how many more secrets can they hide?

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *