Merge pull request #3573 from Rob--W/crx-view-local-files

[CRX] Fixes to view local files again
Adds reference for the Opera extension

Addresses https://github.com/mozilla/pdf.js/issues/3600#issuecomment-23018555
Really call unregister for _pdfRedirectorFactory (fixing issue #3598)
Merge pull request #3601 from jmozmoz/unregister

Really call unregister for _pdfRedirectorFactory (fixing issue #3598)
Proof of concept using chrome.streamsPrivate API

The current method uses the webRequest API with a XHTML Content-Type and
dynamic content scripts to render the viewer.

This commit shows a proof of concept using a NEW method, using the
chrome.streamsPrivate API.

Advantages of new method:
- Access to the response body of the original request.
- As a consequence of the previous, POST requests are supported.
- Fewer network requests.
- Less resource usage during casual browsing, because the MIME-type
  detection is done by Chrome instead of the background page.

Disadvantage:
- The nice URL in the omnibox is gone.
  (this feature can be re-added, but a small delay in the rendering will
  be introduced - Redirect the top frame to the origin of the PDF file,
  if needed (this may take a few seconds on a slow connection), then use
  history.replaceState to rewrite the URL. Finally, insert the viewer
  using the original method (see pdfHandler.js) and use a work-around
  to get the data for the blob-URL of the stream because the viewer's
  origin is not chrome-extension://...)

Possible improvements:
- Use declared content scripts instead of dynamic chrome.tabs.executeScript.
  This allows the extension to render the viewer in frames when the
  extension is disallowed to run executeScript for the top URL.
- Get nice URL in omnibox (see note at "Disadvantage" for implementation hint)
- Use chrome.declarativeWebRequest instead of webRequest, and replace
  background page with event page (don't forget to profile the
  difference & will the background/event page still work as intended?).
Add incognito:split, require Chrome 28+, ...

"split" incognito mode is required in order to get the new viewer to show up
in incognito browsing mode.
However, bug http://crbug.com/224094 caused crashes when this flag was
set. This bug has been fixed 4 months ago, on April 11th and shipped
with Chrome 28. Since both methods (the old and the new method) are
affected by this bug, I have set "minimum_chrome_version": 28 in the
manifest file.

The work-arounds in pdfHandler-local.js have been deleted, and the
remaining few lines have been appended to pdfHandler-v1.js

Depending on the available permissions, either pdfHandler-v1.js or
pdfHandler-v2.js is loaded in the background page.
Use tab-specific stream storage

Also:
- Don't abort the dummy request on failure, but reply with a 1x1 pixel image
  to avoid logs in the console about failed requests.
- Use webNavigation.getAllFrames to find out whether the navigation has
  already started. This is (at least) needed for top-level navigation to
  a stream. The webNavigation.onErrorOccurred event has become obsolete,
  and has been removed.
- Delay removal of webRequest events to avoid unnecessary requests when
  the network stack is busy handling non-fake requests.
Allow fetch of PDF file when stream is unavailable

When the viewer is inside an iframe, and the iframe is reloaded (either
manually via context menu, or via session restore), then the stream is
unavailable. Further, the file cannot be loaded either, because the
extension manifest's permissions do not propagate to extension pages
outside the extension's process.

To relax the Same Origin policy, this commit adds CORS headers
(Access-Control-Allow-Origin) for XMLHttpRequests originating from a
page within the PDF.js Chrome extension.

An issue with the implementation is that it's not possible to satisfy
OPTIONS requests, because the server could reply with a non-200 status,
and the extension won't be able to modify this value.

The current implementation uses the efficient declarativeWebRequest API,
and falls back to the webRequest API if DWR is unavailable.

Alternative implementation:
- Cache all PDFs using the HTML5 fileSystem API, and fetch the file from
  this virtual, sandboxed filesystem if the PDF stream is not found.
[CRX] Show nicely formatted URL in omnibox

Before commit:
chrome-extension://EXTENSIONID/content/web/viewer.html?file=http%3A%2F%2Fexample.com%2Ffile.pdf

After commit:
chrome-extension://EXTENSIONID/http://example/file.pdf

Technical details:
- The extension's background page uses the webRequest API to intercept
  requests for <extension host>/<real path to pdf>, and redirect it to
  the viewer's URL.
- viewer.js uses history.replaceState to rewrite the URL, so that it's
  easier for users to recognize and copy-paste URLs.
- The fake paths /http:, /https:, /file:, etc. have been added to the
  web_accessible_resources section of the manifest file, in order to
  avoid seeing chrome-extension://invalid/ instead of the actual URL
  when using history back/forward to navigate from/to the PDF viewer.
- Since the relative path resolving doesn't work because relative URLs
  are inaccurate, a <base> tag has been added. This method has already
  been proven to work in the Firefox add-on.
Set URL in history.replaceState/pushState

When <base href> is present, history.replaceState and
history.pushState behave inconsistent with relative URLs.
http://code.google.com/p/chromium/issues/detail?id=274024

Contrary to what one expect, passing '' as the URL parameter to
replaceState/pushState does not associate the currently active
URL with the history entry, but a path relative to <base href>.

To fix the issue, explicitly associate the current active URL
with the history's state.
Integration tests for Chrome extension
Work-around for http://crbug.com/276898

When a new incognito session is started, the
onExecuteMimeTypeHandler event is often not
dispatched in time. Instead, it's triggered
in the non-incognito profile.

This commit offers a work-around that allows
new incognito instances to view PDF files.
As of this commit, all tests in
test/chrome_extension_tests will pass.