2015-12-12 5 views
2

Я разрабатываю прокси-сервер, используя nsITraceableChannel (addon-proxy на npm). Я могу изменить входящие ответы, но как я могу сделать fake один?Mozilla: Как подделать ответ с помощью nsITraceableChannel

Предположим, что если URL-адрес содержит hello.html, я хочу вернуть hello world в качестве ответа. Я не могу перенаправить на другую страницу, потому что она не будет прозрачной для клиента и будет конфликтовать с материалом того же происхождения.

На данный момент я отсылаю запрос на сервер и полностью переписываю входящий ответ (см. Фрагмент Noitidart, который можно найти в Интернете во многих вариантах). Это далеко от оптимального для моего конкретного случая использования:

  • я отправить запрос и ждать, пока сервер в любом случае, даже если эти данные доступны на местном уровне.

  • Я не могу изменить заголовки, такие как код контента и код состояния, из фактического значения.

Есть ли способ подавать полный ответ на основной слушатель без фактического выдачи одного из них в сети?

ответ

0

Это абсолютно возможно.

Этот пояс показывает, как просто получить его копию: https://gist.github.com/Noitidart/d0b08629ee2804538ad9 - вы можете скопировать и вставить это в блокнот, нажать пробег и увидеть его в действии.

Обратите внимание на линии 44, он устанавливает this.responseBody = this.receivedChunks.join('');

Так в основном вы бы установить this.responseBody все, что вы хотите

Heres код с сутью:

var {classes: Cc, interfaces: Ci, results: Cr, Constructor: CC, utils: Cu} = Components; 
Cu.import('resource://gre/modules/Services.jsm'); 

var BinaryInputStream = CC('@mozilla.org/binaryinputstream;1', 'nsIBinaryInputStream', 'setInputStream'); 
var BinaryOutputStream = CC('@mozilla.org/binaryoutputstream;1', 'nsIBinaryOutputStream', 'setOutputStream'); 
var StorageStream = CC('@mozilla.org/storagestream;1', 'nsIStorageStream', 'init'); 

function TracingListener() { 
    this.receivedChunks = []; // array for incoming data. holds chunks as they come, onStopRequest we join these junks to get the full source 
    this.responseBody; // we'll set this to the 
    this.responseStatusCode; 

    this.deferredDone = { 
     promise: null, 
     resolve: null, 
     reject: null 
    }; 
    this.deferredDone.promise = new Promise(function(resolve, reject) { 
     this.resolve = resolve; 
     this.reject = reject; 
    }.bind(this.deferredDone)); 
    Object.freeze(this.deferredDone); 
    this.promiseDone = this.deferredDone.promise; 
} 
TracingListener.prototype = { 
    onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { 
     var iStream = new BinaryInputStream(aInputStream) // binaryaInputStream 
     var sStream = new StorageStream(8192, aCount); // storageStream // not sure why its 8192 but thats how eveyrone is doing it, we should ask why 
     var oStream = new BinaryOutputStream(sStream.getOutputStream(0)); // binaryOutputStream 

     // Copy received data as they come. 
     var data = iStream.readBytes(aCount); 
     this.receivedChunks.push(data); 

     oStream.writeBytes(data, aCount); 

     this.originalListener.onDataAvailable(aRequest, aContext, sStream.newInputStream(0), aOffset, aCount); 
    }, 
    onStartRequest: function(aRequest, aContext) { 
     this.originalListener.onStartRequest(aRequest, aContext); 
    }, 
    onStopRequest: function(aRequest, aContext, aStatusCode) { 
     this.responseBody = this.receivedChunks.join(''); 
     delete this.receivedChunks; 
     this.responseStatus = aStatusCode; 
     this.originalListener.onStopRequest(aRequest, aContext, aStatusCode); 

     this.deferredDone.resolve(); 
    }, 
    QueryInterface: function(aIID) { 
     if (aIID.equals(Ci.nsIStreamListener) || aIID.equals(Ci.nsISupports)) { 
      return this; 
     } 
     throw Cr.NS_NOINTERFACE; 
    } 
}; 

var httpResponseObserver = { 
    observe: function(aSubject, aTopic, aData) { 
     var newListener = new TracingListener(); 
     aSubject.QueryInterface(Ci.nsITraceableChannel); 
     newListener.originalListener = aSubject.setNewListener(newListener); 
     /////// END - DO NOT EDIT 
     newListener.promiseDone.then(
      function() { 
       // no error happened 
       console.log('yay response done:', newListener.responseBody); 
      }, 
      function(aReason) { 
       // promise was rejected, right now i didnt set up rejection, but i should listen to on abort or bade status code then reject maybe 
      } 
     ).catch(
      function(aCatch) { 
       console.error('something went wrong, a typo by dev probably:', aCatch); 
      } 
     ); 
    } 
}; 

Services.obs.addObserver(httpResponseObserver, 'http-on-examine-response', false); 
// Services.obs.removeObserver(httpResponseObserver, 'http-on-examine-response'); // call this when you dont want to listen anymore 
+0

Это уже то, что я делаю (см. https://github.com/BruceBerry/addon-proxy/blob/master/proxy.js), и есть множество примеров этого. В отличие от обычного случая, когда вы хотите изменить реальный ответ с сервера, здесь я хочу вернуть полностью фальшивый ответ, так что применяются # 1 и # 2: с кодом, по которому вы отправляете запрос в сети без причины, вы ждут ответа на возврат данных, даже если данные уже доступны локально, и, самое главное, вы не можете изменить код состояния ответа, тип контента и другие значения. – BruceBerry

+0

@BruceBerry Я уверен, что он не отправляет другой запрос. Он делает копию запроса. Если вы хотите подделать код статуса ответа, я не уверен, как это сделать. То, что я думаю, что вам следует делать, - это что-то вроде того, когда вы переходите на страницу с страницей загрузки проблем, вы видите, как они перенаправляют ее на другую страницу, но URL-адрес не изменяется? Посмотрите, как они это делают и разделяют. Я знаю, что новый URL-адрес отображается в 'nsiWebNavigation' like -' win.QueryInterface (Ci.nsIInterfaceRequestor) .getInterface (Ci.nsIWebNavigation) .document.documentURI; ' – Noitidart

+0

Я посмотрю, спасибо. Мое требование состоит не в том, чтобы избежать второго запроса (как вы сказали, это не так), но и для того, чтобы избежать первого! Как только канал узнает, что этот запрос может фактически обслуживаться локально, он не должен отправлять какие-либо данные по сети и ждать ответа. – BruceBerry

Смежные вопросы