issue #41 - add support for XHRs on Network Panel
https://github.com/phonegap/weinre/issues/41
diff --git a/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.coffee b/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.coffee
index 0c71e63..b060469 100644
--- a/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.coffee
+++ b/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.coffee
@@ -26,7 +26,8 @@
#---------------------------------------------------------------------------
hiddenPanels: ->
- "audits,profiles,network"
+ # "audits,profiles,network"
+ "audits,profiles"
#---------------------------------------------------------------------------
platform: ->
diff --git a/weinre.web/modules/weinre/common/Ex.coffee b/weinre.web/modules/weinre/common/Ex.coffee
index 3de56c7..4062188 100644
--- a/weinre.web/modules/weinre/common/Ex.coffee
+++ b/weinre.web/modules/weinre/common/Ex.coffee
@@ -11,6 +11,15 @@
#-------------------------------------------------------------------------------
module.exports = class Ex
+ #---------------------------------------------------------------------------
+ @catching: (func) ->
+ try
+ func.call(this)
+ catch e
+ console.log "runtime error: #{e}"
+ StackTrace.dump arguments
+
+ #---------------------------------------------------------------------------
constructor: (args, message) ->
if not args or not args.callee
throw Ex(arguments, "first parameter must be an Arguments object")
diff --git a/weinre.web/modules/weinre/common/WebSocketXhr.coffee b/weinre.web/modules/weinre/common/WebSocketXhr.coffee
index f37be52..00c741e 100644
--- a/weinre.web/modules/weinre/common/WebSocketXhr.coffee
+++ b/weinre.web/modules/weinre/common/WebSocketXhr.coffee
@@ -192,7 +192,9 @@
xhr.open method, url, true
xhr.setRequestHeader "Content-Type", "text/plain"
- xhr.send data
+
+ HookLib.ignoreHooks ->
+ xhr.send data
#-------------------------------------------------------------------------------
_xhrEventHandler = (event) ->
diff --git a/weinre.web/modules/weinre/target/ElementHighlighterDivs2.coffee b/weinre.web/modules/weinre/target/ElementHighlighterDivs2.coffee
index 8b70935..8185160 100644
--- a/weinre.web/modules/weinre/target/ElementHighlighterDivs2.coffee
+++ b/weinre.web/modules/weinre/target/ElementHighlighterDivs2.coffee
@@ -62,7 +62,6 @@
#---------------------------------------------------------------------------
redraw: (metrics) ->
- console.log(JSON.stringify(metrics, null, 4))
@hElement1.style.top = px metrics.y
@hElement1.style.left = px metrics.x
diff --git a/weinre.web/modules/weinre/target/HookSites.coffee b/weinre.web/modules/weinre/target/HookSites.coffee
index ef37e98..13dedb1 100644
--- a/weinre.web/modules/weinre/target/HookSites.coffee
+++ b/weinre.web/modules/weinre/target/HookSites.coffee
@@ -19,6 +19,7 @@
HookSites.window_addEventListener = HookLib.addHookSite window, "addEventListener"
HookSites.Node_addEventListener = HookLib.addHookSite Node.prototype, "addEventListener"
HookSites.XMLHttpRequest_open = HookLib.addHookSite XMLHttpRequest.prototype, "open"
+HookSites.XMLHttpRequest_send = HookLib.addHookSite XMLHttpRequest.prototype, "send"
HookSites.XMLHttpRequest_addEventListener = HookLib.addHookSite XMLHttpRequest.prototype, "addEventListener"
if window.openDatabase
diff --git a/weinre.web/modules/weinre/target/NetworkRequest.coffee b/weinre.web/modules/weinre/target/NetworkRequest.coffee
new file mode 100644
index 0000000..64849d1
--- /dev/null
+++ b/weinre.web/modules/weinre/target/NetworkRequest.coffee
@@ -0,0 +1,176 @@
+
+#---------------------------------------------------------------------------------
+# weinre is available under *either* the terms of the modified BSD license *or* the
+# MIT License (2008). See http:#opensource.org/licenses/alphabetical for full text.
+#
+# Copyright (c) 2011 IBM Corporation
+#---------------------------------------------------------------------------------
+
+StackTrace = require('../common/StackTrace')
+IDGenerator = require('../common/IDGenerator')
+HookLib = require('../common/HookLib')
+Weinre = require('../common/Weinre')
+Ex = require('../common/Ex')
+HookSites = require('./HookSites')
+
+Loader =
+ url: window.location.href
+ frameId: 0
+ loaderId: 0
+
+#-------------------------------------------------------------------------------
+module.exports = class NetworkRequest
+
+ #---------------------------------------------------------------------------
+ constructor: (@xhr, @id, @method, @url, @stackTrace) ->
+
+ #---------------------------------------------------------------------------
+ handleSend: (data) ->
+ Weinre.wi.NetworkNotify.identifierForInitialRequest(@id, @url, Loader, @stackTrace)
+
+ time = Date.now() / 1000.0
+ request = getRequest(@url, @method, @xhr, data)
+ redirectResponse = {isNull: true}
+
+ Weinre.wi.NetworkNotify.willSendRequest(@id, time, request, redirectResponse)
+
+ #---------------------------------------------------------------------------
+ handleHeadersReceived: ->
+ time = Date.now() / 1000.0
+ response = getResponse(@xhr)
+ Weinre.wi.NetworkNotify.didReceiveResponse(@id, time, "XHR", response)
+
+ #---------------------------------------------------------------------------
+ handleLoading: ->
+
+ #---------------------------------------------------------------------------
+ handleDone: ->
+ sourceString = @xhr.responseText
+ Weinre.wi.NetworkNotify.setInitialContent(@id, sourceString, "XHR")
+
+ time = Date.now() / 1000.0
+ status = @xhr.status
+ status = 200 if status == 0
+ statusText = @xhr.statusText
+
+ success = status >= 200 and status < 300
+
+ if success
+ Weinre.wi.NetworkNotify.didFinishLoading(@id, time)
+ else
+ description = "#{status} - #{statusText}"
+ Weinre.wi.NetworkNotify.didFailLoading(@id, time, description)
+
+ #---------------------------------------------------------------------------
+ @installNativeHooks: ->
+
+ #-----------------------------------------------------------------------
+ HookSites.XMLHttpRequest_open.addHooks
+
+ before: (receiver, args) ->
+ xhr = receiver
+
+ method = args[0]
+ url = args[1]
+ id = IDGenerator.next()
+
+ rawStackTrace = new StackTrace(args).trace.slice(1)
+
+ stackTrace = []
+ for frame in rawStackTrace
+ stackTrace.push({functionName: frame})
+
+ xhr.__weinreNetworkRequest__ = new NetworkRequest(xhr, id, method, url, stackTrace)
+
+ HookLib.ignoreHooks ->
+ xhr.addEventListener "readystatechange", getXhrEventHandler(xhr), false
+
+ #-----------------------------------------------------------------------
+ HookSites.XMLHttpRequest_send.addHooks
+
+ before: (receiver, args) ->
+ xhr = receiver
+ data = args[0]
+ nr = xhr.__weinreNetworkRequest__
+ return unless nr
+
+ nr.handleSend(data)
+
+#-------------------------------------------------------------------------------
+getRequest = (url, method, xhr, data) ->
+
+ return {
+ url: url
+ httpMethod: method
+ httpHeaderFields: {}
+ requestFormData: getFormData(url, data)
+ }
+
+#-------------------------------------------------------------------------------
+getResponse = (xhr) ->
+ contentType = xhr.getResponseHeader("Content-Type")
+
+ [contentType, encoding] = splitContentType(contentType)
+
+ headers = getHeaders(xhr)
+
+ return {
+ mimeType: contentType
+ expectedContentLength: contentType
+ textEncodingName: encoding
+ httpStatusCode: xhr.status
+ httpStatusText: xhr.statusText
+ httpHeaderFields: headers
+ connectionReused: false
+ connectionID: 0
+ wasCached: false
+ }
+
+#-------------------------------------------------------------------------------
+getHeaders = (xhr) ->
+ string = xhr.getAllResponseHeaders()
+ lines = string.split('\r\n')
+
+ result = {}
+ for line in lines
+ line = trim(line)
+ break if line == ""
+
+ [key, val] = line.split(':', 2)
+ result[trim(key)] = trim(val)
+
+ result
+
+#-------------------------------------------------------------------------------
+trim = (string) ->
+ string.replace(/^\s+|\s+$/g, '')
+
+#-------------------------------------------------------------------------------
+getFormData = (url, data) ->
+ return data if data
+
+ pattern = /.*?\?(.*?)(#.*)?$/
+ match = url.match(pattern)
+ return match[1] if match
+
+ return ""
+
+#-------------------------------------------------------------------------------
+splitContentType = (contentType) ->
+ pattern = /\s*(.*?)\s*(;\s*(.*))?\s*$/
+ match = contentType.match(pattern)
+ return [contentType, ""] unless match
+
+ return [match[1], match[3]]
+
+#-------------------------------------------------------------------------------
+getXhrEventHandler = (xhr) ->
+ ->
+ nr = xhr.__weinreNetworkRequest__
+ return unless nr
+
+ switch xhr.readyState
+ when 2 then nr.handleHeadersReceived()
+ when 3 then nr.handleLoading()
+ when 4 then nr.handleDone()
+
diff --git a/weinre.web/modules/weinre/target/Target.coffee b/weinre.web/modules/weinre/target/Target.coffee
index 8dbceb6..df91a94 100644
--- a/weinre.web/modules/weinre/target/Target.coffee
+++ b/weinre.web/modules/weinre/target/Target.coffee
@@ -19,6 +19,7 @@
ElementHighlighter = require('./ElementHighlighter')
ExceptionalCallbacks = require('./ExceptionalCallbacks')
InjectedScriptHostImpl = require('./InjectedScriptHostImpl')
+NetworkRequest = require('./NetworkRequest')
WeinreTargetEventsImpl = require('./WeinreTargetEventsImpl')
WeinreExtraClientCommandsImpl = require('./WeinreExtraClientCommandsImpl')
WiConsoleImpl = require('./WiConsoleImpl')
@@ -40,8 +41,6 @@
Weinre.target = new Target()
Weinre.target.initialize()
- ExceptionalCallbacks.addHooks()
-
#----------------------------------------------------------------------------
setWeinreServerURLFromScriptSrc: (element) ->
return if window.WeinreServerURL
@@ -143,6 +142,7 @@
Weinre.wi.DatabaseNotify = messageDispatcher.createProxy("DatabaseNotify")
Weinre.wi.InspectorNotify = messageDispatcher.createProxy("InspectorNotify")
Weinre.wi.TimelineNotify = messageDispatcher.createProxy("TimelineNotify")
+ Weinre.wi.NetworkNotify = messageDispatcher.createProxy("NetworkNotify")
Weinre.WeinreTargetCommands = messageDispatcher.createProxy("WeinreTargetCommands")
Weinre.WeinreExtraTargetEvents = messageDispatcher.createProxy("WeinreExtraTargetEvents")
@@ -155,6 +155,9 @@
Target.handleError e
), false
+ ExceptionalCallbacks.addHooks()
+ NetworkRequest.installNativeHooks()
+
#---------------------------------------------------------------------------
@handleError: (event) ->
filename = event.filename or "[unknown filename]"