Czy można utworzyć rozszerzenie do Chrome, które modyfikuje treść odpowiedzi HTTP?
Szukałem w Chrome Extension API , ale nie znalazłem nic, aby to zrobić.
google-chrome-extension
Kapitan Smok
źródło
źródło
webRequest.filterResponseData()
. Niestety jest to rozwiązanie tylko dla przeglądarki Firefox.Odpowiedzi:
Ogólnie rzecz biorąc, nie można zmienić treści odpowiedzi żądania HTTP przy użyciu standardowych interfejsów API rozszerzeń Chrome.
Ta funkcja jest wymagana pod adresem 104058: WebRequest API: zezwól rozszerzeniu na edytowanie treści odpowiedzi . Oznacz problem gwiazdką, aby otrzymywać powiadomienia o aktualizacjach.
Jeśli chcesz edytować treść odpowiedzi dla znanego
XMLHttpRequest
, wstrzykuj kod za pomocą skryptu zawartości, aby zastąpić domyślnyXMLHttpRequest
konstruktor niestandardowym (w pełni funkcjonalnym), który przepisuje odpowiedź przed wyzwoleniem rzeczywistego zdarzenia. Upewnij się, że Twój obiekt XMLHttpRequest jest w pełni zgodny z wbudowanymXMLHttpRequest
obiektem Chrome, w przeciwnym razie strony z dużą ilością technologii AJAX ulegną awarii.W innych przypadkach możesz użyć interfejsów API
chrome.webRequest
lub,chrome.declarativeWebRequest
aby przekierować żądanie dodata:
-URI. W przeciwieństwie do podejścia XHR, nie otrzymasz oryginalnej treści żądania. W rzeczywistości żądanie nigdy nie dotrze do serwera, ponieważ przekierowanie można wykonać tylko przed wysłaniem rzeczywistego żądania. Jeśli przekierowujeszmain_frame
żądanie, użytkownik zobaczydata:
-URI zamiast żądanego adresu URL.źródło
data:text...
?Właśnie wydałem rozszerzenie Devtools, które właśnie to robi :)
Nazywa się tamper, jest oparty na mitmproxy i pozwala zobaczyć wszystkie żądania wysyłane przez bieżącą kartę, modyfikować je i obsługiwać zmodyfikowaną wersję przy następnym odświeżeniu.
To dość wczesna wersja, ale powinna być kompatybilna z OS X i Windows. Daj mi znać, jeśli to nie zadziała.
Możesz go pobrać tutaj http://dutzi.github.io/tamper/
Jak to działa
Jak skomentował @Xan poniżej, rozszerzenie komunikuje się poprzez Native Messaging ze skryptem Pythona, który rozszerza mitmproxy .
Rozszerzenie wyświetla listę wszystkich żądań używających
chrome.devtools.network.onRequestFinished
.Po kliknięciu żądań pobiera swoją odpowiedź przy użyciu metody obiektu żądania
getContent()
, a następnie wysyła tę odpowiedź do skryptu Pythona, który zapisuje ją lokalnie.Następnie otwiera plik w edytorze (używając
call
dla OSX lubsubprocess.Popen
dla Windows).Skrypt w Pythonie używa mitmproxy do nasłuchiwania całej komunikacji prowadzonej przez to proxy, jeśli wykryje żądanie dotyczące zapisanego pliku, zamiast tego obsługuje zapisany plik.
Użyłem API proxy Chrome (w szczególności
chrome.proxy.settings.set()
), aby ustawić PAC jako ustawienie proxy. Ten plik PAC przekierowuje całą komunikację do serwera proxy skryptu Python.Jedną z największych zalet mitmproxy jest to, że może również modyfikować komunikację HTTPs. Więc to też masz :)
źródło
Tak. Jest to możliwe dzięki
chrome.debugger
interfejsowi API, który zapewnia rozszerzeniu dostęp do protokołu Chrome DevTools , który obsługuje przechwytywanie i modyfikację HTTP za pośrednictwem sieciowego interfejsu API .To rozwiązanie zostało zasugerowane w komentarzu do Chrome Issue 487422 :
Najpierw dołącz debugger do celu:
chrome.debugger.getTargets((targets) => { let target = /* Find the target. */; let debuggee = { targetId: target.id }; chrome.debugger.attach(debuggee, "1.2", () => { // TODO }); });
Następnie wyślij
Network.setRequestInterceptionEnabled
polecenie, które umożliwi przechwytywanie żądań sieciowych: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 zacznie teraz wysyłać
Network.requestIntercepted
wydarzenia. Dodaj dla nich słuchacza: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 } }); });
W odbiorniku
params.request
będzie odpowiedniRequest
obiekt.Wyślij odpowiedź z
Network.continueInterceptedRequest
:rawResponse
.params.interceptionId
jakointerceptionId
.Zwróć uwagę, że w ogóle tego nie testowałem.
źródło
setRequestInterceptionEnabled
metoda wydaje się nie być zawarte w protokole DevTools v1.2, a ja nie mogę znaleźć sposób, aby dołączyć go do najnowszej (tip-of-tree) zamiast wersji.chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
nie powiodło się, a „Network.setRequestInterceptionEnabled” nie został znaleziony ”Jak powiedział @Rob w, nadpisałem
XMLHttpRequest
i jest to wynikiem modyfikacji wszelkich żądań XHR w dowolnych witrynach (działa jak przezroczysty proxy modyfikacji):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); };
na przykład ten kod może być z powodzeniem używany przez Tampermonkey do wprowadzania jakichkolwiek modyfikacji na dowolnych stronach :)
źródło
response
raczej nowszego niżresponseText
, więc wszystko, co musisz zrobić, to zmienić Object.defineProperty, aby użyćresponse
zamiast tego