server-logger-monitor.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. "use strict";
  6. const {Ci} = require("chrome");
  7. const Services = require("Services");
  8. const {makeInfallible} = require("devtools/shared/DevToolsUtils");
  9. loader.lazyGetter(this, "NetworkHelper", () => require("devtools/shared/webconsole/network-helper"));
  10. // Helper tracer. Should be generic sharable by other modules (bug 1171927)
  11. const trace = {
  12. log: function (...args) {
  13. }
  14. };
  15. const acceptableHeaders = ["x-chromelogger-data"];
  16. /**
  17. * This object represents HTTP events observer. It's intended to be
  18. * used in e10s enabled browser only.
  19. *
  20. * Since child processes can't register HTTP event observer they use
  21. * this module to do the observing in the parent process. This monitor
  22. * is loaded through DebuggerServerConnection.setupInParent() that is
  23. * executed from within the child process. The execution is done by
  24. * {@ServerLoggingListener}. The monitor listens to HTTP events and
  25. * forwards it into the right child process.
  26. *
  27. * Read more about the architecture:
  28. * https://github.com/mozilla/gecko-dev/blob/fx-team/devtools/server/docs/actor-e10s-handling.md
  29. */
  30. var ServerLoggerMonitor = {
  31. // Initialization
  32. initialize: function () {
  33. this.onChildMessage = this.onChildMessage.bind(this);
  34. this.onExamineResponse = this.onExamineResponse.bind(this);
  35. // Set of registered child frames (loggers).
  36. this.targets = new Set();
  37. },
  38. // Parent Child Relationship
  39. attach: makeInfallible(function ({ mm, prefix }) {
  40. trace.log("ServerLoggerMonitor.attach; ", arguments);
  41. let setMessageManager = newMM => {
  42. if (mm) {
  43. mm.removeMessageListener("debug:server-logger", this.onChildMessage);
  44. }
  45. mm = newMM;
  46. if (mm) {
  47. mm.addMessageListener("debug:server-logger", this.onChildMessage);
  48. }
  49. };
  50. // Start listening for messages from the {@ServerLogger} actor
  51. // living in the child process.
  52. setMessageManager(mm);
  53. return {
  54. onBrowserSwap: setMessageManager,
  55. onDisconnected: () => {
  56. trace.log("ServerLoggerMonitor.onDisconnectChild; ", arguments);
  57. setMessageManager(null);
  58. }
  59. };
  60. }),
  61. // Child Message Handling
  62. onChildMessage: function (msg) {
  63. let method = msg.data.method;
  64. trace.log("ServerLoggerMonitor.onChildMessage; ", method, msg);
  65. switch (method) {
  66. case "attachChild":
  67. return this.onAttachChild(msg);
  68. case "detachChild":
  69. return this.onDetachChild(msg);
  70. default:
  71. trace.log("Unknown method name: ", method);
  72. return undefined;
  73. }
  74. },
  75. onAttachChild: function (event) {
  76. let target = event.target;
  77. let size = this.targets.size;
  78. trace.log("ServerLoggerMonitor.onAttachChild; size: ", size, target);
  79. // If this is the first child attached, register global HTTP observer.
  80. if (!size) {
  81. trace.log("ServerLoggerMonitor.onAttatchChild; Add HTTP Observer");
  82. Services.obs.addObserver(this.onExamineResponse,
  83. "http-on-examine-response", false);
  84. }
  85. // Collect child loggers. The frame element where the
  86. // window/document lives.
  87. this.targets.add(target);
  88. },
  89. onDetachChild: function (event) {
  90. let target = event.target;
  91. this.targets.delete(target);
  92. let size = this.targets.size;
  93. trace.log("ServerLoggerMonitor.onDetachChild; size: ", size, target);
  94. // If this is the last child process attached, unregister
  95. // the global HTTP observer.
  96. if (!size) {
  97. trace.log("ServerLoggerMonitor.onDetachChild; Remove HTTP Observer");
  98. Services.obs.removeObserver(this.onExamineResponse,
  99. "http-on-examine-response", false);
  100. }
  101. },
  102. // HTTP Observer
  103. onExamineResponse: makeInfallible(function (subject, topic) {
  104. let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
  105. trace.log("ServerLoggerMonitor.onExamineResponse; ", httpChannel.name,
  106. this.targets);
  107. // Ignore requests from chrome or add-on code when we are monitoring
  108. // content.
  109. if (!httpChannel.loadInfo &&
  110. httpChannel.loadInfo.loadingDocument === null &&
  111. httpChannel.loadInfo.loadingPrincipal ===
  112. Services.scriptSecurityManager.getSystemPrincipal()) {
  113. return;
  114. }
  115. let requestFrame = NetworkHelper.getTopFrameForRequest(httpChannel);
  116. if (!requestFrame) {
  117. return;
  118. }
  119. // Ignore requests from parent frames that aren't registered.
  120. if (!this.targets.has(requestFrame)) {
  121. return;
  122. }
  123. let headers = [];
  124. httpChannel.visitResponseHeaders((header, value) => {
  125. header = header.toLowerCase();
  126. if (acceptableHeaders.indexOf(header) !== -1) {
  127. headers.push({header: header, value: value});
  128. }
  129. });
  130. if (!headers.length) {
  131. return;
  132. }
  133. let { messageManager } = requestFrame;
  134. messageManager.sendAsyncMessage("debug:server-logger", {
  135. method: "examineHeaders",
  136. headers: headers,
  137. });
  138. trace.log("ServerLoggerMonitor.onExamineResponse; headers ",
  139. headers.length, ", ", headers);
  140. }),
  141. };
  142. /**
  143. * Executed automatically by the framework.
  144. */
  145. function setupParentProcess(event) {
  146. return ServerLoggerMonitor.attach(event);
  147. }
  148. // Monitor initialization.
  149. ServerLoggerMonitor.initialize();
  150. // Exports from this module
  151. exports.setupParentProcess = setupParentProcess;