Archival only; if you try to use this the cyber police will send you to jail
3 files changed, 121 insertions(+), 0 deletions(-)

A => cache.js
A => config.js
A => imitare.js
A => cache.js +72 -0
@@ 0,0 1,72 @@ 
+/* Heu heu hue
+ */
+
+var http = require('http');
+var fs = require('fs');
+var config = require('./config');
+
+var cache = {};
+
+function AddCacheItem(path) {
+    var item = {path: path, subscribers: []};
+    cache[path] = item
+    item.inProgress = false;
+    fetch(item);
+    setInterval(function() { fetch(item); }, config.expiry);
+    return item;
+}
+
+function fetch(item) {
+    console.log('going to fetch' + item.path);
+    if(item.inProgress) return; // Oh dear!
+
+    item.inProgress = true;
+    http.get({host: config.target, port: 80, path: item.path}, function(res) {
+        item.data = '';
+
+        res.on('data', function(chunk) {
+            item.data += chunk.toString('binary');
+        });
+
+        res.on('end', function() {
+            item.statusCode = res.statusCode;
+            item.headers = {};
+            ['connection', 'content-type', 'content-length', 'location'].map(function(header){
+                if (res.headers[header]) // We may want to do this replacement in the body as well
+                    item.headers[header] = res.headers[header].replace(config.target, config.host);
+            })
+            if(item.headers['content-type'].lastIndexOf('text/html', 0) == 0) {
+                var sexy_message = '$1 - Page cached by ' + config.host + ' at ' + new Date() + '$2';
+                item.data = item.data.replace(/(<title>.*)(<\/title>)/, sexy_message);
+            }
+
+            item.inProgress = false;
+
+            while (item.subscribers.length)
+                item.subscribers.pop()(item);
+        });
+
+    }).on('error', function(e) {
+        console.log('Tried to cache ' + item.path + ' but encountered a wild "' + e.message + '"');
+        item.inProgress = false;
+        // Try again?
+        fetch(item);
+    });
+}
+
+
+// Pushes content immediately if it's available or queues callback
+function pushContent(item, callback) {
+    if (item.inProgress)
+        item.subscribers.push(callback);
+    else
+        callback(item);
+}
+
+// Exports
+module.exports.getPage = function(path, callback) {
+    console.log('getPage ' + path);
+    var item = path in cache ? cache[path] : AddCacheItem(path);
+    if (callback != undefined)
+        pushContent(item, callback);
+}

          
A => config.js +14 -0
@@ 0,0 1,14 @@ 
+// Since our unit time is microseconds, some constants have been provided to
+//   help express time in larger units
+var second = 1000;
+var minute = 60 * second;
+var hour   = 60 * minute;
+var day    = 24 * hour;
+var week   = 7 * day;
+
+
+module.exports = {
+    target: 'wiki.mythea.com',
+    port: 8012,
+    expiry: 5 * day,
+}

          
A => imitare.js +35 -0
@@ 0,0 1,35 @@ 
+/* Imitare is a piece of software used to create a mirror of a website */
+
+var http = require('http');
+var urlmodule = require('url');
+var config = require('./config');
+var cache = require('./cache');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function givePageToResponse(path, res) {
+    //console.log('givePageToResponse');
+    cache.getPage(path, function(item) {
+        //console.log('page gotted');
+        res.writeHead(item.statusCode, item.headers);
+        //console.log('sending...')
+        //console.log(item.statusCode);
+        //console.log(item.headers);
+        //console.log('/sending...')
+        res.end(item.data, 'binary');
+    })
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+http.createServer(function(req, res) {
+    // We get signal!
+    var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
+    var path = urlmodule.parse(req.url).path;
+    var host = req.headers.host;
+    config.host = host;
+    console.log(ip + ' - ' + path);
+    givePageToResponse(path, res);
+}).listen(config.port, '127.0.0.1');
+
+console.log('imitare for ' + config.target + ' started on port ' + config.port);