HTTP Request/Response logger

Listen to all ajax http requests and responses and renders a button on screen that allows it's download (groups by request). Exports in mockserver format.

  1. // ==UserScript==
  2. // @name HTTP Request/Response logger
  3. // @namespace tacatman@gmail.com/scripts
  4. // @version 1.1
  5. // @description Listen to all ajax http requests and responses and renders a button on screen that allows it's download (groups by request). Exports in mockserver format.
  6. // @author Pedro Fonseca
  7. // @license GPL
  8. // @match *://*/*
  9. // @grant none
  10. // @run-at document-start
  11. // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js
  12. // ==/UserScript==
  13. var startup = function() {
  14. var XMLHttpRequestOpen = XMLHttpRequest.prototype.open;
  15. var exportFile = function (key) {
  16. var blob = new Blob([JSON.stringify(window.requestSnifferForMock[key], null, 2)], {type : 'application/json'});
  17. requestSnifferForMockSaveAs(blob, key+".json");
  18. };
  19. var addButton = function(text, func) {
  20. var div = document.createElement('div');
  21. div.setAttribute('style', 'padding: 10px; display: flex;');
  22. var button = document.createElement('button');
  23. button.setAttribute('style', 'flex: 1 0 auto');
  24. button.addEventListener('click', func, false);
  25. button.innerText = text;
  26. div.appendChild(button);
  27. return div;
  28. };
  29. var updateDownloaderDiv = function() {
  30. const element = document.getElementById('requestSnifferForMockDiv');
  31. if (Object.keys(window.requestSnifferForMock).length > 0) {
  32. element.innerHTML = "";
  33. Object.keys(window.requestSnifferForMock).forEach((t) => {
  34. element.appendChild(addButton(t + '(' + window.requestSnifferForMock[t].length + ')', exportFile.bind(undefined, t)));
  35. });
  36. element.appendChild(addButton('Clear', clear));
  37. } else {
  38. element.innerHTML = "listening...";
  39. }
  40. };
  41. var clear = function() {
  42. Object.keys(window.requestSnifferForMock).forEach((t) => {
  43. delete window.requestSnifferForMock[t];
  44. });
  45. updateDownloaderDiv();
  46. };
  47. XMLHttpRequest.prototype.open = function() {
  48. const request = {
  49. method: arguments['0']
  50. };
  51. const url = arguments['1'];
  52. const index = url.indexOf('?');
  53. if (index >= 0) {
  54. request.path = url.substring(0, index);
  55. request.queryStringParameters = url.substring(url.indexOf('?') + 1).split('&').map((t) => t.split('=')).reduce((agg, t) => ({ ...agg, [t[0]] : [t[1]]}) , {});
  56. } else {
  57. request.path = url;
  58. }
  59.  
  60. this.addEventListener("load", () => {
  61. if (window.requestSnifferForMock[request.path] == null) {
  62. window.requestSnifferForMock[request.path] = [];
  63. }
  64. window.requestSnifferForMock[request.path].push({
  65. httpRequest: request,
  66. httpResponse: {
  67. statusCode: this.status,
  68. body: JSON.stringify(JSON.parse(this.responseText)),
  69. },
  70. });
  71. updateDownloaderDiv();
  72. });
  73.  
  74. XMLHttpRequestOpen.apply(this, arguments);
  75. };
  76. updateDownloaderDiv();
  77. };
  78.  
  79. window.requestSnifferForMock = {};
  80. window.requestSnifferForMockSaveAs = saveAs;
  81. var div = document.createElement('div');
  82. div.setAttribute('id', 'requestSnifferForMockDiv');
  83. div.setAttribute('style', 'background-color: yellow; border-color: red; position: absolute; z-index: 1000;');
  84. document.body.appendChild(div);
  85. var script = document.createElement('script');
  86. script.setAttribute('type', 'text/javascript');
  87. script.innerText = '(' + String(startup) + '())';
  88. document.body.appendChild(script);