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.

32 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
  5. OMG thank you so much for this. I was lost without this and my client would have been peed if I lost my files.

    ReplyDelete
  6. your JS on console works like a charm.

    ReplyDelete
  7. I really want to express my deepest gratitude for this amazing and terrific simple tool of yours!
    My hat goes off to you talented savior! ;D

    (ps. i really hate the blogger comment system but i really wanted to say "thank you" , so for this special occasion i created an open id account but it's just for this! Thank you again! ;) )

    ReplyDelete
  8. The download link no longer works :( Did it break?

    ReplyDelete
  9. I've been working for a week in a forum until the stupid host decided to suspend the account for no reason.
    I lost all my work... I thought. But well, it was still in cache! *-*
    So I searched exactly for a tool like this.
    Thank you so much, you're my hero. I can't express how grateful I am!

    ReplyDelete
  10. Thank you for your AMAZING tool! I wish you had a PayPal Donate button, I'd drop $5 USD in the pot in gratitude for the time and great trouble you have saved me today.

    ReplyDelete
  11. thank you thank you thank you thank you!!!!!!!!!!!!!

    ReplyDelete
  12. "Via Console" worked beautifully for me. Thank you.

    ReplyDelete
  13. This post is really good. So good that I decided to use it to improve a Firefox extension called CacheViewer Continued, with your permission of course...

    Here is the link to download the result:
    http://dl.dropbox.com/u/12425686/cacheviewer_continued-0.9-fx.xpi

    To see your code in it, change the xpi to zip and unzip. Then open the file:
    /chrome/contente/cacheviewer/cacheviewer.js
    Your code for convert to Base64 is on line 870.

    The changes I made to extension were:

    1. Add a filter to device type (memory, disk, offline).
    2. I used the converttobase64 function to correct the handling of images from memory, specially ASP.NET dynamic-generated images.

    I would like to submit this to the extension's author, do you allow it?

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

    ReplyDelete
  15. You sir are amazing. I've managed to save the cache files, the only thing is they get saved as winrar files, upon opening them up I just get a "file" type file. When I open them with a text viewer, the entire thing more or less looks like this.(See below) and it goes on for quite a long while. I'm wondering if there's a certain type of program for it to open as or such?(I had to put periods in the middle of words such as Script, Meta, title and such because it wouldn't let me copy and paste the code with those words in it.)





    deviantART: Submission





    var _gaq = _gaq || [];
    _gaq.push(
    ['_setAccount', '']
    ,['_setDomainName', '..com']


    );


    var _qevents = _qevents || [];

    (function() {
    var elem = document.createElement('scri.pt');

    elem.src = (document.location.protocol == "https:" ? "https://secure" : "http://edge") + ".quantserve.com/quant.js";
    elem.async = true;
    elem.type = "text/javascrip.t";
    var scpt = document.getElementsByTagName('scrip.t')[0];
    scpt.parentNode.insertBefore(elem, scpt);
    })();


    window.vms_features={'':1};
    function vms_feature(feature) {
    return (feature in window.vms_features);
    }
    function is_beta() {
    return false;
    }

    ReplyDelete
  16. Extremely useful! Not sure why Google makes this so inaccesible in Chrome relative to every other browser I've used, but I'm glad you saved the day.

    ReplyDelete
    Replies
    1. FYI I followed over here from your post at Frozax.

      Delete
  17. You just saved me from rewriting an entire blog post that I "lost" earlier today. Thank you SO MUCH!

    ReplyDelete
  18. Omg. You just saved my blog... thank you, kindly! I was just about to break down & bawl... just thinking about all the weeks of work I put into my coding... just to lose it all.

    PHEW! THANK YOU.

    ReplyDelete
  19. Ooops I thought I'd lost the flight award !! Many thanks for the solution :-)

    ReplyDelete
  20. Thank you! Just recovered some important information with this tool. What a relief!

    ReplyDelete
  21. Thanks, this is awesome and a life saver!

    ReplyDelete
  22. I can't get any of this to work.

    ReplyDelete
  23. You really saved my life today. Thank you!

    ReplyDelete
  24. It is possible to view Google Chrome cache by using an extension called "View Link in Google Cache". Download the extension here.

    https://chrome.google.com/webstore/search/cache%20viewer?hl=en-US

    Once you have installed this extension, an icon will appear on the right top portion of your Chrome window.

    Open a webpage. Click the icon to see the cache of this webpage. It doesn't matter if the webpage no longer exists. If the content of this webpage is available in your Chrome cache, the extension will show it for you.

    ReplyDelete
  25. I really appreciate you taking the time to write this post and sharing such a valuable tip. Good Karma coming to you :)

    ReplyDelete
  26. Holy shit!!!!

    Man, you saved my day and my work!!!

    You should put a donate button, really

    ReplyDelete
  27. You... are.... AWESOME! WOW! I want to send you $1 for helping me. :) Any way you could provide this as an offline tool? It would be very helpful for internet outages. This time my college portal was out for maintenance and it really prevented me from doing my work. Thank you again.

    ReplyDelete
  28. I have to say you are genius man. I like your post and i read it carefully !

    Just simple question : is there any way to get access to the cache file using php (programmatically) ? i want to combine this with curl but I'm stuck.

    Thanks a lot.


    ReplyDelete