Why Chrome DevTools Network shows no response? - google-chrome

I've been trying to fetch some url using Devtools 'copy as fetch' but I can see no response. If I try replay xhr, it will work. It's strange since it doesn't work for this particular site, but if I try 'copy as fetch' on some others it does bring a result.
What I'm trying to do is grab the response body and display it some other way (it's a schedling software, and I'm trying to modify the way it displays the calendar view since it displays everything together).
I have an extension that enables me to modify XMLHttpRequest so I can get the response of any XHR, but since the first async executes before I inject the script, then I'm always missing the first one.
I plan on using chrome webRequest to stop the first one and fetch it again.
manifest.json
{
"name": "jobber",
"version": "2.0",
"description": "Build an Extension!",
"manifest_version": 2,
"permissions": [
"webNavigation",
"webRequest",
"*://secure.name.com/*"
],
"content_scripts": [{
"matches": ["*://secure.name.com/calendar*"],
"js": ["contents.js"],
"run-at": "document_start"
}],
"externally_connectable": {
"matches": ["*://secure.name.com/calendar*"]
},
"background": {
"scripts": ["background.js"]
}
}
contents.js
(function () {
'use strict';
let s = document.createElement("script");
s.textContent = overloadXHR();
document.head.insertBefore(s, document.head.children[0]);
s = document.createElement("script");
s.textContent = displayCalendar;
document.head.insertBefore(s, document.head.children[0]);
})();
function overloadXHR() {
const text = `
console.log(\`overriding: \${Date.now()}\`);
const rawOpen = XMLHttpRequest.prototype.open;
let json = [];
(function(){
XMLHttpRequest.prototype.open = function () {
this.addEventListener("readystatechange", e => {
if (/secure.name.com.calendar.*?calendar=true/i.test(this.responseURL)) {
if ((this.status == 200) && (this.readyState == 4)) {
console.log(this.readyState);
try {
json = JSON.parse(this.response);
window.setTimeout(() => (window.displayCalendar({json}))({json}), 1000);
}
catch (e) { console.log(e); }
}
}
});
rawOpen.apply(this, arguments);
}
}())
`;
return text;
}
function displayCalendar({ json }) {
// do something
}
I tried POST requests too. I could see that they would work, but no response given tho.
original request:
copy as fetch
copy as fetch response
copy as fetch timing

Related

Can't inject JavaScript into new tab from popup.js

I'M creating an extension that autofill's forms on different websites. There is a portion of the script that records the actions of the user with event listeners. After the recording is done the user click the test button that will launch a new tab and autofill's the form. I know launching a new tab for testing is not necessary but this function will be used later for another feature.
This is what I got so far. I had started over several times. I tried sending a message to content script. The chrome.windows,create function only launched from the popup script. I started chrome development a week ago. I'm totally confused.
Popup.js
`(async () =\> { const tab = await chrome.tabs.create({url: 'https://www.listyourself.net/ListYourself/listing.jsp'});
const tabId = tab.id; if (!tab.url)
await onTabUrlUpdated(tabId);
await chrome.scripting.executeScript({
target: {tabId},
files: \['test.js'\],
});`
})();`
I think your extension has two problems.
onTabUrlUpdated is not defined.
Execution of chrome.tabs.create causes the popup to lose focus, so the JavaScript is also terminated.
Here is a sample that fixes it.
manifest.json
{
"manifest_version": 3,
"name": "hoge",
"version": "1.0",
"permissions": [
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "hoge"
}
}
background.js
chrome.action.onClicked.addListener(() => {
main();
});
const test = () => {
console.log("test");
}
const main = async () => {
const tab = await chrome.tabs.create({ url: "https://nory-soft.web.app/" });
const tabId = tab.id;
if (!tab.url) {
chrome.tabs.onUpdated.addListener((updateTabId, changeInfo) => {
if ((updateTabId == tabId) && (changeInfo.status == "complete")) {
chrome.scripting.executeScript({
target: { tabId },
func: test
});
}
});
}
}

How can I focus a document programmatically from a Chrome extension (to paste content)

What I try to do is simple:
I am making a chrome extension.
This extension has a shortcut (e.g. alt + o).
When I press this shortcut it switches to a tab,
and should paste clipboard content in the page.
Here's the background script that reacts to the shortcut and inject code in page to simulate paste event:
// --- background.js
chrome.commands.onCommand.addListener((command) => {
switch (command) {
case 'switch_tab_and_paste_content':
switchToTabAndPasteContent()
break;
}
})
async function switchToTabAndPasteContent() {
const tab = (await chrome.tabs.query({})).filter((tab) => tab.title.toLowerCase().includes('my page'))[0]
// focus the window
await chrome.windows.update(tab.windowId, { focused: true })
// and focus the tab
await chrome.tabs.update(tab.id, { active: true })
/* inject paste emulation script */
await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: function () {
pasteContent()
}
})
}
pasteContent() in the code above is a function contained in a content script. It's used to simulate paste event (just like a user would use ctrl + v on some page.)
// --- paste.js
async function pasteContent() {
try {
const wizElement = document.querySelector('c-wiz')
const clipboardItems = await navigator.clipboard.read()
const firstItem = clipboardItems[0]
const blob = await firstItem.getType('image/png')
const file = new File([blob], 'image.png', { type: 'image/png' })
const dataTransfer = new DataTransfer()
dataTransfer.items.add(file)
const pasteEvent = new ClipboardEvent('paste', {
bubbles: true,
cancelable: true,
clipboardData: dataTransfer,
})
wizElement.dispatchEvent(pasteEvent)
}
catch (e) { console.log(e) }
}
and here's the simplified manifest.json
{
"name": "app-connector",
"version": 3,
"permissions": [ "tabs", "scripting", "activeTab" ],
"background": {
"service_worker": "background.js"
},
"content_scripts": [{
"matches": [ ... ],
"js": "paste.js"
}],
"commands": {
"switch_tab_and_paste_content": {
"description": "Switch tab"
}
}
}
However when I press the shortcut on my keyboard, the tab is focused but I get this exception
DOMException: Document is not focused.
I know the reason of that exception (it's because when I leave the tab the document loses focus, chrome.tabs.update(tab.id, { active: true }) activates the tab but it's not enough to focus back on the document)
What I want to know is if there is a way to bypass that (a chrome flag, a command-line argument, etc...).
Of course the ideal would be a native solution in the extension ecosystem but I didn't find/can't think of any solution. I tried opening/closing a popup fast to give focus back to the page but I still get this exception (it seems like it won't work unless I click in the page but it defeats the purpose of making an automated routine behind).
am I missing a permission?

Chrome extension sendResponse not working

There are numerous versions of this question, and I have reviewed them and tried many things to the best of my ability without success. I am new to chrome extensions, and I could be missing many things, but I don't know what.
First, I want to point out that I have copied several claimed working examples from various answers, and none of them work for me. I am using Chrome Version 58.0.3029.81 on Windows 7 Professional.
Whether it's my code, or examples I have copied, the code in the content script executes, and calls sendResponse with the correct response. Beyond that, nothing - the specified callback function is never executed.
Here is my current code:
manifest.json
{
"manifest_version": 2,
"name": "TestExtension",
"description": "...",
"version": "1.0",
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [ "content.js" ]
}
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "Send a checkpoint request"
},
"permissions": [
"activeTab",
"tabs",
"http://*/*", // allow any host
"https://*/*" // allow any secure host
]
}
popup.js
document.addEventListener('DOMContentLoaded', function ()
{
document.getElementById('extension_form').onsubmit = function ()
{
var elementName = "DataAccessURL";
chrome.tabs.query(
{
active: true,
currentWindow: true
},
function (tabs)
{
chrome.tabs.sendMessage(
tabs[0].id,
{ Method: "GetElement", data: elementName },
function (response)
{
debugger;
console.log("response:Element = " + response.Element);
alert(response.Element);
});
});
};
});
content.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse)
{
console.log("In Listener");
if (request.Method && request.Method == "GetElement")
{
var result = "";
var element = request.data;
console.log(element);
var e = document.getElementById(element);
if (e) result = e.innerHTML;
console.log(result);
sendResponse({ Element: result });
return true; // <-- the presence or absence of this line makes no difference
}
});
Any clues would be appreciated. I simply do not understand why my callback is not being called.
User wOxxOm provided this answer in his comments.
In the popup.js example, I am attaching to the form 'onsubmit' event to trigger my code.
I had previously read that if the popup gets closed, it's code would no longer be there to be run. I could not visually tell in my case that, as wOxxOm pointed out, that the submit event reloads the popup. That was disconnecting my code.
In order to prevent the popup from reloading, I needed to prevent the default action on the submit event. I added an 'evt' parameter to accept the event argument to the submit, and called preventDefault as shown below.
document.getElementById('extension_form').onsubmit = function (evt)
{
evt.preventDefault();
...
This allowed the sample to work as expected.
Thanks wOxxOm!

Chrome Extension Modify FormData

chrome.webRequest.onBeforeRequest.addListener(function (details) {
if (details.method === "POST") {
var bodyObj = details['requestBody'];
// I can see/modify bodyObj.formData, but
}
}, {
urls: ["<all_urls>"]
}, [
"blocking", "requestBody"
]););
How can I return a modified formData?
I see from Chrome Extensions's documentation that I can cancel a request, redirect a request, or modify the request headers, but how can I change the formData?
Based on http://crbug.com/91191, it looks like there's only read-only access to POST data for webRequest's onBeforeRequest listeners.
It means we can see what is being sent in a request BODY like this below:
chrome.webRequest.onBeforeRequest.addListener(function (details) {
console.log(details['requestBody']);
}, {
urls: ["<all_urls>"]
}, [
"blocking", "requestBody"
]);
But we can't update it for now.

addListener's sendResponse called from callback returns previous message

In the beginning I thought that the problem is with chrome.runtime.sendMessage() I was sending two messages. One for accessing localstorage and another one to get/read the file data, but nothing changed after I merged them in one sendMessage which means that the actual problem is window.webkitRequestFileSystem() it's returning the previous file instead of the current one.
Is there a better/faster way of storing something client side ? (I'm willing to try everything) ?
manifest.json
{
"manifest_version": 2,
...
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"background": {
"scripts": ["background.js"]
},
"permissions": [
"unlimitedStorage"
]
}
background.js
var theme = '';
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request.method == "getTheme") {
themes = JSON.parse(localStorage["themes"]);
themeName = "";
for (var i = themes.length - 1; i >= 0; i--) {
if(request.url.indexOf(themes[i]) !== -1) {
themeName = themes[i];
}
};
window.webkitRequestFileSystem(window.PERSISTENT, 0, readFromFileStorage.bind(window, themeName), errorHandler);
sendResponse({data: theme});
}
});
function readFromFileStorage(filename, fs) {
fs.root.getFile(filename, {}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
theme = this.result;
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
function errorHandler(e) {
console.log('Error: ' + e.message);
}
content.js
chrome.runtime.sendMessage({method: "getTheme", url: location.href}, function(response) {
console.log(response.data);
});
As your question is not an SSCCE it is hard to test it, but I think your problem is understanding of JS asynchronous nature.
So how your code will actually execute:
First window.webkitRequestFileSystem(PERSISTENT, 0, successCallback, errorHandler); will be executed
Then sendResponse({data: theme}); will send the response with whatever is stored in theme
Then either successCallback either errorHandler will be called depending on file request success. If successCallback will be called then you'll have your theme variable filled with the value you want. But it will be to late as you already sent the response.
The next time you pass the message you will receive previous theme value (point 2) as your code will find new value only after you'll send the value.
A solution may be to call sendResponse inside of successCallback after you find your desired value (you'll have to pass sendResponse into readFromFileStorage). If you'll do so then you may consider to add sendResponse into errorHandler function just to be sure that your code will always get a valid response.
In case that you'll move the sendResponse into a callback then you have to return true from addListener function, otherwise on addListener return channel will be closed and response will not be sent.