// ==UserScript==
// @name ajax log
// @namespace https://greasyfork.org/users/174399
// @description library for log ajax requests and save logs as a file
// @version 0.5.0-beta.1.0
// ==/UserScript==
function getNull(arg){return arg || null;}
(function(window){
try{
var tracker = {},
proto = window.XMLHttpRequest.prototype;
['open', 'send', 'setRequestHeader', 'abort'].forEach(function(m){
tracker[m] = {
'original': null,
'hook': null,
'ready': null,
};
});
/*function getVal(obj, name){ var c = obj[name] = obj[name] || {}; return c;};*/
var getVal = function(obj, name){ var c = obj[name] = obj[name] || {}; return c;};
console.log("tracker: ", tracker);
/*function setTracker(type, hook)*/
var setTracker = function(type, hook)
{
var t = tracker[type];
if(!t || t.ready)
return;
t.original = proto[type];
/*t.hook = proto[type] = function()*/
proto[type] = function()
{
hook.apply(this, arguments);
t.original.apply(this, arguments);
};
t.ready = true;
};
/*function toObj(str)*/
var toObj = function(str)
{
if( !str )
return null;
switch(typeof str)
{
case 'object':
return str;
case 'string':
var o = {}, s = str.split('&'), v, p;
for(p of s)
{
v = p.split('=');
o[v[0]] = v[1] || '';
}
return o;
default:
return null;
}
};
Object.defineProperty(proto, 'xhrTracker', {
value: null,
writable: true,
});
proto.xhrTracker = {};
['addEventListener', 'onreadystatechange', 'onload'].forEach(function(m){
proto.xhrTracker[m] = {
'original': null,
'hook': null,
'ready': null,
};
});
console.log("prototype: ", proto);
var responseL = ['response', 'readyState', 'status', 'statusText'];
/*function setResponse(obj, r)*/
var setResponse = function(obj, r)
{
responseL.forEach(function(n){
obj[n] = r[n];
});
};
var xhrHook = {
'onreadystatechange': null,
'onload': null,
};
var flushAndSave = null, totalResponse = '';
var saveLog = function()
{
if( !flushAndSave )
return;
console.log("save.totalResponse:\r\n" + totalResponse);
saveFile('xml-http-request-' + getDate() + '.txt', createFile(totalResponse, 'text/plain'));
totalResponse = '';
flushAndSave = false;
};
var getHeaders = function(x)
{
var headers = x.getAllResponseHeaders(), o = {}, h;
var hs = headers.split(/\r\n/);
for(var h of hs)
{
h = h.split(': ');
o[h[0].trim()] = h.slice(1).join(': ').trim();
}
return o;
};
xhrHook.onreadystatechange = function(e)
{
var t = e.target;
if( t.readyState == 4 )
{
var cntx = getVal(t, 'context'),
o = cntx.onreadystatechange = {};
setResponse(o, t);
o.responseHeaders = getHeaders(t);
o.respHeads = t.getAllResponseHeaders();
totalResponse += '\r\n\r\n' + JSON.stringify(cntx, null, 2);
console.log("onreadystatechange.totalResponse:\r\n" + totalResponse);
saveLog();
}
};
/*function getDate(date)*/
var getDate = function(date)
{
date = date || new Date();
return '' +
date.getFullYear() + '-' +
(date.getMonth() + 1) + '-' +
date.getDate() + '-@' +
date.getHours() + '-' +
date.getMinutes() + '-' +
(date.getSeconds() * 1e3 + date.getMilliseconds())/1e3;
};
console.log("date: ", getDate());
xhrHook.onload = function(e)
{
/*
var t = e.target,
cntx = getVal(t, 'context'),
o = cntx.onload = {};
setResponse(o, t);
o.responseHeaders = getHeaders(t);
totalResponse += '\r\n\r\n' + JSON.stringify(cntx, null, 2);
console.log("onload.totalResponse:\r\n" + totalResponse);
saveLog();
*/
};
/*function setXhrTracker(inst, type, hook, original)*/
var setXhrTracker = function(inst, type, hook, original)
{
var t = inst.xhrTracker[type];
if( t.ready )
return;
t.inst = inst;
console.log("setXhrTracker:" + type + ": ", inst);
if( typeof original != 'function' )
{
t.original = inst[type] || function(){console.log("dummy: " + type);};
t.hook = inst[type] = function(){
hook.apply(t.inst, arguments);
t.original.apply(t.inst, arguments);
};
}else{
t.original = original;
t.hook = function(){
hook.apply(t.inst, arguments);
t.original.apply(t.inst, arguments);
};
}
t.ready = true;
};
/*function setEventTracker(inst)*/
var setEventTracker = function(inst)
{
var n = 'addEventListener',
o = inst.xhrTracker[n],
i = inst;
o.inst = inst;
o.original = inst[n];
o.hook = inst[n] = function(evt, fun)
{
var t = i.xhrTracker['on' + evt];
if( !!t )
setXhrTracker(i, 'on' + ev, xhrHook['on' + ev], fun);
else
o.original.apply(o.inst, arguments);
};
};
var link;
var getLocation = function(url, p)
{
link = link || document.createElement('a');
link.href = url;
return link[p||'href'];
};
setTracker('open', function(method, url, async){
try{
var cntx = getVal(this, 'context');
cntx.method = method.toUpperCase();
cntx.url = getLocation(url, 'href');
cntx.async = (async === undefined ? null: async);
console.log("open:context: ", JSON.stringify(cntx, null, 2));
setEventTracker(this);
}catch(er){console.error(er);}
});
setTracker('setRequestHeader', function(name, val){
try{
var cntx = getVal(this, 'context'),
headers = getVal(cntx, 'headers');
headers[name] = val;
console.log("headers:context: ", JSON.stringify(cntx, null, 2));
}catch(er){console.error(er);}
});
setTracker('abort', function(){
var cntx = getVal(this, 'context');
cntx.onabort = true;
});
setTracker('send', function(data){
try{
var cntx = getVal(this, 'context');
cntx.data = toObj(data);
console.log("send:context: ", JSON.stringify(cntx, null, 2));
setXhrTracker(this, 'onreadystatechange', xhrHook.onreadystatechange);
setXhrTracker(this, 'onload', xhrHook.onreadystatechange);
}catch(er){console.error(er);}
});
var keyboard = function(e)
{
if(!e.shiftKey)
return;
var code = e.keyCode || e.which,
ch = String.fromCharCode(code).toUpperCase();
switch(ch)
{
case 'S':
flushAndSave = true;
saveLog();
break;
}
};
window.addEventListener('keydown', function(e){
keyboard(e);
});
function saveFile(name, resource)
{
var link = document.createElement('a');
link.href = resource;
link.download = name;
document.querySelector('body').appendChild(link);
link.click();
link.parentNode.removeChild(link);
}
function createFile(data, type)
{
var wu = window.URL || window.webkitURL,
b = new Blob([data], {type: type}),
u = wu.createObjectURL(b);
setTimeout(function(){wu.revokeObjectURL(b);}, 1e4);
return u;
}
}catch(err){console.error(err);}
})(getNull(unsafeWindow) || window);