Est-il possible de créer une extension Chrome qui modifie le corps des réponses HTTP?)
J'ai consulté = Chrome Extension APIs , mais je n'ai rien trouvé pour cela.
En général, vous ne pouvez pas modifier le corps de la réponse d'une requête HTTP à l'aide des API d'extension standard Chrome.
Cette fonctionnalité est demandée à l'adresse 104058: API WebRequest: autoriser l'extension à modifier le corps de la réponse . Lancez le numéro pour être averti des mises à jour.
Si vous souhaitez modifier le corps de la réponse pour un XMLHttpRequest
, injecter du code via un script de contenu pour remplacer le constructeur par défaut XMLHttpRequest
par un script personnalisé (complet). en vedette) qui réécrit la réponse avant de déclencher l'événement réel. Assurez-vous que votre objet XMLHttpRequest est entièrement compatible avec l'objet intégré XMLHttpRequest
de Chrome, sinon les sites AJAX lourds vont tomber en panne.
Dans d'autres cas, vous pouvez utiliser le chrome.webRequest
ou chrome.declarativeWebRequest
API pour rediriger la demande vers un data:
_ URI. Contrairement à l'approche XHR, vous n'obtiendrez pas le contenu original de la demande. En réalité, la demande ne parviendra jamais sur le serveur car la redirection ne peut être effectuée qu'avant l'envoi de la demande. Et si vous redirigez un main_frame
demande, l’utilisateur verra le data:
_ URI au lieu de l'URL demandée.
Je viens de publier une extension Devtools qui ne fait que ça :)
Elle s'appelle tamper, elle est basée sur mitmproxy et vous permet de voir toutes les demandes faites par l'onglet actuel, de les modifier et de servir la version modifiée à la prochaine actualisation.
C'est une version assez ancienne mais elle devrait être compatible avec OS X et Windows. Faites-moi savoir si cela ne fonctionne pas pour vous.
Vous pouvez l'obtenir ici http://dutzi.github.io/tamper/
Comment ça marche
Comme @Xan a commenté ci-dessous, l'extension communique par le biais de Native Messaging avec un script python qui étend mitmproxy .
L'extension liste toutes les requêtes utilisant chrome.devtools.network.onRequestFinished
.
Lorsque vous cliquez sur l'une des requêtes, il télécharge sa réponse à l'aide de la méthode getContent()
de l'objet de requête, puis envoie cette réponse au script python qui l'enregistre localement).
Il ouvre ensuite le fichier dans un éditeur (en utilisant call
pour OSX ou subprocess.Popen
Pour Windows).
Le script python utilise mitmproxy pour écouter toutes les communications établies via ce proxy. S'il détecte une demande de fichier enregistré, il sert le fichier qui a été enregistré à la place.
J'ai utilisé l'API proxy de Chrome (en particulier chrome.proxy.settings.set()
) pour définir un PAC en tant que paramètre de proxy. Ce fichier PAC redirige toutes les communications vers le proxy du script python.
L'un des principaux avantages de mitmproxy est qu'il peut également modifier la communication HTTP. Donc vous avez ça aussi :)
Oui. C'est possible avec le chrome.debugger
API, qui accorde un accès d'extension à protocole Chrome DevTools , qui prend en charge l'interception et la modification HTTP via son API résea .
Cette solution a été suggérée par n commentaire sur Chrome Issue 487422 :
Pour ceux qui souhaitent une alternative réalisable pour le moment, vous pouvez utiliser
chrome.debugger
dans une page d’arrière-plan/événement à attacher à l’onglet spécifique que vous voulez écouter (ou attacher à tous les onglets si cela est possible, n’a pas testé tous les onglets personnellement), puis utilisez l’API réseau du protocole de débogage.Le seul problème avec cela est qu'il y aura la barre jaune habituelle en haut de la fenêtre de l'onglet, à moins que l'utilisateur ne le désactive dans
chrome://flags
.
Tout d’abord, attachez un débogueur à la cible:
chrome.debugger.getTargets((targets) => {
let target = /* Find the target. */;
let debuggee = { targetId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
// TODO
});
});
Ensuite, envoyez le Network.setRequestInterceptionEnabled
commande, qui permettra l’interception des requêtes réseau:
chrome.debugger.getTargets((targets) => {
let target = /* Find the target. */;
let debuggee = { targetId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
});
});
Chrome va maintenant commencer à envoyer Network.requestIntercepted
événements. Ajoutez un auditeur pour eux:
chrome.debugger.getTargets((targets) => {
let target = /* Find the target. */;
let debuggee = { targetId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
});
chrome.debugger.onEvent.addListener((source, method, params) => {
if(source.targetId === target.id && method === "Network.requestIntercepted") {
// TODO
}
});
});
Dans l'auditeur, params.request
sera l’objet Request
correspondant.
Envoyez la réponse avec Network.continueInterceptedRequest
:
rawResponse
.params.interceptionId
comme interceptionId
.Notez que je n'ai pas du tout testé cela.
Comme @Rob w, j'ai remplacé XMLHttpRequest
et il en résulte une modification des requêtes XHR de tous les sites (fonctionnant comme un proxy de modification transparent):
var _open = XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (method, URL) {
var _onreadystatechange = this.onreadystatechange,
_this = this;
_this.onreadystatechange = function () {
// catch only completed 'api/search/universal' requests
if (_this.readyState === 4 && _this.status === 200 && ~URL.indexOf('api/search/universal')) {
try {
//////////////////////////////////////
// THIS IS ACTIONS FOR YOUR REQUEST //
// EXAMPLE: //
//////////////////////////////////////
var data = JSON.parse(_this.responseText); // {"fields": ["a","b"]}
if (data.fields) {
data.fields.Push('c','d');
}
// rewrite responseText
Object.defineProperty(_this, 'responseText', {value: JSON.stringify(data)});
/////////////// END //////////////////
} catch (e) {}
console.log('Caught! :)', method, URL/*, _this.responseText*/);
}
// call original callback
if (_onreadystatechange) _onreadystatechange.apply(this, arguments);
};
// detect any onreadystatechange changing
Object.defineProperty(this, "onreadystatechange", {
get: function () {
return _onreadystatechange;
},
set: function (value) {
_onreadystatechange = value;
}
});
return _open.apply(_this, arguments);
};
par exemple, Tampermonkey peut utiliser ce code avec succès pour apporter des modifications sur n’importe quel site :)