Skip to content

Instantly share code, notes, and snippets.

@yuru4c
Last active August 31, 2021 09:07
Show Gist options
  • Save yuru4c/846dbba5de27e370c0e233aba68ee3b6 to your computer and use it in GitHub Desktop.
Save yuru4c/846dbba5de27e370c0e233aba68ee3b6 to your computer and use it in GitHub Desktop.
HAR に含まれるファイルを展開(NW.js 用)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>har reader</title>
<style type="text/css">
body {
white-space: nowrap;
}
.browser .nw {
display: none;
}
</style>
</head>
<body class="browser">
<form name="form">
<fieldset name="fieldset">
<p>
<label>
入力:
<input type="file" accept=".har" multiple name="file">
</label>
<input type="button" name="show" value="表示">
</p>
<p class="nw">
<label>
出力:
<input type="file" name="directory" nwdirectory>
</label>
<input type="button" name="save" value="保存">
</p>
</fieldset>
</form>
<div id="list"></div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
{
"name": "har-reader",
"version": "0.0.0.4",
"main": "index.html"
}
(function () {
var nw = this.nw;
var path;
var fs;
if (nw != null) {
path = require('path');
fs = require('fs');
}
var RE = {
FILE: /[^/]*$/, DOT: /\.|$/, DIR: /\/$/,
REPLACE: /\\|\/|:|\*|\?|"|<|>|\||\.|~/g
};
function decode(base64) {
var bin = atob(base64);
var array = new Uint8Array(bin.length);
for (var i = 0; i < array.length; i++) {
array[i] = bin.charCodeAt(i);
}
return array.buffer;
}
function createBlob(data, type) {
var blob = new Blob([data], {type: type});
return URL.createObjectURL(blob);
}
function createHref(content) {
var encoding = content['encoding'];
var mimeType = content['mimeType'];
var text = content['text'];
if (text == null) {
return null;
}
if (!encoding) {
return createBlob(text, mimeType);
}
switch (encoding) {
case 'base64':
return createBlob(decode(text), mimeType);
}
return 'data:' + mimeType + ';' + encoding + ',' + text;
}
function createFilename(url, headers, replace) {
var filename = url.pathname.match(RE.FILE)[0] || '#';
var lastModified;
for (var i = 0; i < headers.length; i++) {
var header = headers[i];
if (header['name'].toLowerCase() == 'last-modified') {
lastModified = header['value'];
break;
}
}
if (lastModified == null) {
return filename;
}
if (replace) {
lastModified = lastModified.replace(RE.REPLACE, '_');
}
return filename.replace(RE.DOT, ' (' + lastModified + ')$&');
}
function createDirname(destination, url) {
var pathname = url.pathname;
var dir = RE.DIR.test(pathname) ?
pathname :
path.dirname(pathname);
return path.join(destination, url.hostname, dir);
}
function Show(list) {
this.fragment = document.createDocumentFragment();
this.ol = document.createElement('ol');
list.innerHTML = '';
list.appendChild(this.ol);
}
Show.prototype.each = function (request, response) {
var content = response['content'];
var href = createHref(content);
if (href == null) return;
var url = request['url'];
var headers = response['headers'];
var li = document.createElement('li');
var a = document.createElement('a');
a.href = href;
a.download = createFilename(new URL(url), headers, false);
a.appendChild(document.createTextNode(url));
li.appendChild(a);
this.fragment.appendChild(li);
};
Show.prototype.done = function () {
this.ol.appendChild(this.fragment);
};
function Save(destination) {
this.destination = destination;
}
Save.prototype.each = function (request, response) {
var content = response['content'];
var text = content['text'];
if (text == null) return;
var url = request['url'];
var headers = response['headers'];
var encoding = content['encoding'];
var urlObj = new URL(url);
var dir = createDirname(this.destination, urlObj);
var file = path.format({
dir: dir,
base: createFilename(urlObj, headers, true)
});
fs.mkdirSync(dir, {recursive: true});
try {
fs.writeFileSync(file, text, {encoding: encoding, flag: 'wx'});
} catch (e) {
switch (e.errno) {
case -4075: break;
default: throw e;
}
}
};
Save.prototype.done = function () { };
function Context(elements) {
this.fieldset = elements['fieldset'];
this.input = elements['file'];
this.title = document.title;
this.verb = null;
}
function Loop(context, action) {
context.fieldset.disabled = true;
this.context = context;
this.action = action;
this.files = context.input.files;
this.length = this.files.length;
this.index = -1;
this.file = null;
this.next();
}
Loop.prototype.each = function (entry) {
var request = entry['request'];
if (request['method'] != 'GET') return;
var response = entry['response'];
if (response['status'] >= 400) return;
this.action.each(request, response);
};
Loop.prototype.next = function () {
this.index++;
if (this.index < this.length) {
this.file = this.files[this.index];
document.title = (
'[' + (this.index + '/' + this.length) + '] ' +
this.context.verb + '... - ' + this.context.title
);
fileReader.readAsText(this.file);
} else {
this.action.done();
document.title = this.context.title;
this.context.fieldset.disabled = false;
}
};
var loop;
var fileReader = new FileReader();
fileReader.onerror = function () {
console.warn({
file: loop.file,
error: this.error
});
loop.next();
};
fileReader.onload = function () {
try {
var json = JSON.parse(this.result);
var entries = json['log']['entries'];
for (var i = 0; i < entries.length; i++) {
try {
loop.each(entries[i]);
} catch (error) {
console.warn({
file: loop.file,
index: i,
error: error
});
}
}
} catch (error) {
console.warn({
file: loop.file,
error: error
});
}
loop.next();
};
window.onload = function () {
var list = document.getElementById('list');
var elements = document.forms['form'].elements;
var context = new Context(elements);
elements['show'].onclick = function () {
context.verb = this.value;
loop = new Loop(context, new Show(list));
};
if (nw != null) {
var directory = elements['directory'];
elements['save'].onclick = function () {
var destination = directory.value;
if (destination) {
context.verb = this.value;
loop = new Loop(context, new Save(destination));
}
};
document.body.className = '';
}
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment