Sunday, January 8, 2012

Viewing Chrome cache (the easy way)

Chrome is a great browser, however it could use improvement is in its cache viewer. While the cache viewer can be used to recover a file, it's unnecessarily complex. I decided to create a solution which makes it easy to recover a file in the cache. I got the idea from reading a post about how to do the same thing in PHP. The problem was that I didn't have PHP set up, and, besides, a lot of people don't know how to use PHP. I wanted to create a solution that would be as easy as possible for anyone to use; a solution which wouldn't require you to download, install, or setup anything.

There are three methods you can use to view your cached data. They are sorted in three tabs from the easiest-to-use method on the left (copy/paste) to the most difficult-to-use one on the right (console).
Instructions:
  1. In Chrome, open a new tab and navigate to chrome://cache/
  2. Click on whichever file you want to view.
    You should then see a page with a bunch of text and numbers.
  3. Copy all the text on that page.
  4. Paste it in the text box below.
  5. Press "Go".
  6. The cached data will appear in the Results section below.
Note: the file contents are not uploaded anywhere. The entire processing is done client side.

Paste your content here:

Results:

Instructions:
  1. In Chrome, open a new tab and navigate to chrome://cache/
  2. Click on whichever file you want to view.
    You should then see a page with a bunch of text and numbers.
  3. Right-click the page and save it as an HTML file (choose "HTML only", not "Complete").
  4. On this page, press Choose File and choose the file which you just saved.
  5. The cached data will appear in the Results section below.
Note: the file is not uploaded anywhere. The entire processing is done client side.

Select your file here:

Results:

How to view a file from the cache:
  1. Copy the code at the bottom of this post.
  2. In Chrome, navigate to chrome://cache/
  3. Click on whichever file you want to view.
    You should then see a page with a bunch of text and numbers.
  4. In Chrome, go to Settings > Tools > JavaScript Console.
  5. Near the > character, paste the copied code.
  6. Press Enter on your keyboard.
    You should then see a link which says Download cached file on the top.
This has been tested on Chrome 17.0 on Mac OS X. In case you're wondering why it's not a one-click bookmarklet, it's because Chrome prevents bookmarklets from running on the cache pages.

Here's the code you will need to copy:

(function() {
    var preTags = document.getElementsByTagName('pre');
    var preWithHeaderInfo = preTags[0];
    var preWithContent = preTags[2];

    var lines = preWithContent.textContent.split('\n');
    var text = '';
    for (var i = 0; i < lines.length; i++) {
        var line = lines[i];
        var firstIndex = 11; // first index of the chars to match
        var indexJump = 4;
        var totalCharsPerLine = 16;
        index = firstIndex;
        for (var j = 0; j < totalCharsPerLine; j++) {
            var hexValAsStr = line.substr(index, 2);
            if (hexValAsStr == '  ') {
                // no more chars
                break;
            }

            var asciiVal = parseInt(hexValAsStr, 16);
            text += String.fromCharCode(asciiVal);

            index += indexJump;
        }
    }

    var headerText = preWithHeaderInfo.textContent;
    var elToInsertBefore = document.body.childNodes[0];
    var insertedDiv = document.createElement("div");
    document.body.insertBefore(insertedDiv, elToInsertBefore);

    // find the filename
    var nodes = [document.body];
    var filepath = '';
    while (true) {
        var node = nodes.pop();
        if (node.hasChildNodes()) {
            var children = node.childNodes;
            for (var i = children.length - 1; i >= 0; i--) {
                nodes.push(children[i]);
            }
        }

        if (node.nodeType === Node.TEXT_NODE && /\S/.test(node.nodeValue)) {
            // 1st depth-first text node (with non-whitespace chars) found
            filepath = node.nodeValue;
            break;
        }
    }
    
    outputResults(insertedDiv, convertToBase64(text), filepath, headerText);

    insertedDiv.appendChild(document.createElement('hr'));

    function outputResults(parentElement, fileContents, fileUrl, headerText) {
        // last updated 1/27/12
        var rgx = /.+\/([^\/]+)/;
        var filename = rgx.exec(fileUrl)[1];

        // get the content type
        rgx = /content-type: (.+)/i;
        var match = rgx.exec(headerText);
        var contentTypeFound = match != null;
        var contentType = "text/plain";
        if (contentTypeFound) {
            contentType = match[1];
        }

        var dataUri = "data:" + contentType + ";base64," + fileContents;

        // check for gzipped file
        var gZipRgx = /content-encoding: gzip/i;
        if (gZipRgx.test(headerText)) {
            filename += '.gz';
        }
        
        // check for image
        var imageRgx = /image/i;
        var isImage = imageRgx.test(contentType);
            
        // create link
        var aTag = document.createElement('a');
        aTag.textContent = "Left-click to download the cached file";
        aTag.setAttribute('href', dataUri);
        aTag.setAttribute('download', filename);
        parentElement.appendChild(aTag);
        parentElement.appendChild(document.createElement('br'));
    
        // create image
        if (isImage) {
            var imgTag = document.createElement('img');
            imgTag.setAttribute("src", dataUri);
            parentElement.appendChild(imgTag);
            parentElement.appendChild(document.createElement('br'));
        }
    
        // create warning
        if (!contentTypeFound) {
            var pTag = document.createElement('p');
            pTag.textContent = "WARNING: the type of file was not found in the headers... defaulting to text file.";
            parentElement.appendChild(pTag);
        }
    }

    function getBase64Char(base64Value) {
        if (base64Value < 0) {
            throw "Invalid number: " + base64Value;
        } else if (base64Value <= 25) {
            // A-Z
            return String.fromCharCode(base64Value + "A".charCodeAt(0));
        } else if (base64Value <= 51) {
            // a-z
            base64Value -= 26; // a
            return String.fromCharCode(base64Value + "a".charCodeAt(0));
        } else if (base64Value <= 61) {
            // 0-9
            base64Value -= 52; // 0
            return String.fromCharCode(base64Value + "0".charCodeAt(0));
        } else if (base64Value <= 62) {
            return '+';
        } else if (base64Value <= 63) {
            return '/';
        } else {
            throw "Invalid number: " + base64Value;
        }
    }

    function convertToBase64(input) {
        // http://en.wikipedia.org/wiki/Base64#Example
        var remainingBits;
        var result = "";
        var additionalCharsNeeded = 0;

        var charIndex = -1;
        var charAsciiValue;
        var advanceToNextChar = function() {
            charIndex++;
            charAsciiValue = input.charCodeAt(charIndex);
            return charIndex < input.length;
        };

        while (true) {
            var base64Char;

            // handle 1st char
            if (!advanceToNextChar()) break;
            base64Char = charAsciiValue >>> 2;
            remainingBits = charAsciiValue & 3; // 0000 0011
            result += getBase64Char(base64Char); // 1st char
            additionalCharsNeeded = 3;

            // handle 2nd char
            if (!advanceToNextChar()) break;
            base64Char = (remainingBits << 4) | (charAsciiValue >>> 4);
            remainingBits = charAsciiValue & 15; // 0000 1111
            result += getBase64Char(base64Char); // 2nd char
            additionalCharsNeeded = 2;

            // handle 3rd char
            if (!advanceToNextChar()) break;
            base64Char = (remainingBits << 2) | (charAsciiValue >>> 6);
            result += getBase64Char(base64Char); // 3rd char
            remainingBits = charAsciiValue & 63; // 0011 1111
            result += getBase64Char(remainingBits); // 4th char
            additionalCharsNeeded = 0;
        }

        // there may be an additional 2-3 chars that need to be added
        if (additionalCharsNeeded == 2) {
            remainingBits = remainingBits << 2; // 4 extra bits
            result += getBase64Char(remainingBits) + "=";
        } else if (additionalCharsNeeded == 3) {
            remainingBits = remainingBits << 4; // 2 extra bits
            result += getBase64Char(remainingBits) + "==";
        } else if (additionalCharsNeeded != 0) {
            throw "Unhandled number of additional chars needed: " + additionalCharsNeeded;
        }

        return result;
    }
})()
  • 1/27/12:
    • Added 2 new methods of viewing the cache (copy/paste and save/load).
    • Improved code.
  • 1/16/12:
    • Uses the original filename when downloading the file, and adds a '.gz' extension if necessary.

4 comments:

  1. Hallo, thank you for your great post! I don't have php installed so your post is great for me!
    I'm using Mac 10.6.8 snow leopard with Chrome 16.0.912.77.
    When I try to save the generated file on the top, Chrome crashes and closed immediately.
    Please, do you have an idea about this problem?
    I need to restore a file from cache...
    Thank you very much.
    Giovel

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Hallo, thank you for your replay: if I install chrome's beta version I think I will lose all my chronology... or no?

    ReplyDelete
  4. @giovel: you are right, that's too risky... I added two new methods you could use instead. The first thing I would do is right-click and save the file for backup purposes. You could then try using any of the first two methods to recover the file's contents. With these two new methods, you could even launch this webpage on another browser (e.g. Safari) and copy the data from Chrome into Safari, and it should let you recover your file that way. You could even save the cached file on your current computer, then transfer it to another computer which has the latest beta version of chrome installed, and use method 2 to recover your file.

    Beta version of chrome: http://www.google.com/landing/chrome/beta/ (Warning: your cached data might be deleted if you install a new version of Chrome. Therefore, I would recommend you save the cached file contents asap (see the "via saved cached file" method on top).

    ReplyDelete