Fix encoding arraybuffer in base64 for upload.

These weren't being encoded properly after switch to compressed traces.

Also, previously we were generating uncompressed json via chrome. If you were to load a gzipped file and then attempt to upload it, you'd hit a "missing data" error. Now, we check the file type and use the appropriate path.

R=dsinclair@chromium.org

Review URL: https://codereview.appspot.com/247380043.
diff --git a/trace_viewer/base/base64.html b/trace_viewer/base/base64.html
index 5b070a2..aeb7fa8 100644
--- a/trace_viewer/base/base64.html
+++ b/trace_viewer/base/base64.html
@@ -31,6 +31,16 @@
     return input.length * 3 + 1 >> 2;
   }
 
+  Base64.EncodeArrayBufferToString = function(input) {
+    // http://stackoverflow.com/questions/9267899/
+    var binary = '';
+    var bytes = new Uint8Array(input);
+    var len = bytes.byteLength;
+    for (var i = 0; i < len; i++)
+      binary += String.fromCharCode(bytes[i]);
+    return btoa(binary);
+  }
+
   Base64.DecodeToTypedArray = function(input, output) {
 
     var nInLen = input.length;
diff --git a/trace_viewer/ui/extras/about_tracing/profiling_view.html b/trace_viewer/ui/extras/about_tracing/profiling_view.html
index 48a58d9..a69f4b5 100644
--- a/trace_viewer/ui/extras/about_tracing/profiling_view.html
+++ b/trace_viewer/ui/extras/about_tracing/profiling_view.html
@@ -5,6 +5,7 @@
 found in the LICENSE file.
 -->
 
+<link rel="import" href="/base/base64.html">
 <link rel="import"
       href="/ui/extras/about_tracing/record_and_capture_controller.html">
 <link rel="import"
@@ -522,8 +523,16 @@
       this.uploadOverlay_.buttons.removeChild(
           this.uploadOverlay_.buttons.firstChild);
       this.uploadOverlay_.buttons.firstChild.textContent = 'Close';
-      var data_base64 = btoa(this.activeTrace_.data);
-      chrome.send('doUploadBase64', [data_base64]);
+
+      var filename = this.activeTrace_.filename;
+      var isBinary = /[.]gz$/.test(filename) || /[.]zip$/.test(filename);
+      if (isBinary) {
+        var data_base64 = tr.b.Base64.EncodeArrayBufferToString(
+            this.activeTrace_.data);
+        chrome.send('doUploadBase64', [data_base64]);
+      } else {
+        chrome.send('doUpload', [this.activeTrace_.data]);
+      }
     },
 
     hideUploadOverlay_: function() {
diff --git a/trace_viewer/ui/extras/about_tracing/profiling_view_test.html b/trace_viewer/ui/extras/about_tracing/profiling_view_test.html
index a62d683..9e6f615 100644
--- a/trace_viewer/ui/extras/about_tracing/profiling_view_test.html
+++ b/trace_viewer/ui/extras/about_tracing/profiling_view_test.html
@@ -5,6 +5,7 @@
 found in the LICENSE file.
 -->
 
+<link rel="import" href="/base/base.html">
 <link rel="import"
       href="/ui/extras/about_tracing/mock_tracing_controller_client.html">
 <link rel="import" href="/extras/importer/trace_event_importer.html">
@@ -129,6 +130,69 @@
     });
   });
 
+  test('upload_compressed', function() {
+    var mock = new tr.ui.e.about_tracing.MockTracingControllerClient();
+    mock.allowLooping = true;
+    mock.expectRequest('getMonitoringStatus', function() {
+      return btoa(JSON.stringify(monitoringOptions));
+    });
+    var view = new ProfilingView(mock);
+    this.addHTMLOutput(view);
+    var buttons = view.querySelector('x-timeline-view-buttons');
+    var uploadButton = buttons.querySelector('#upload-button');
+    assert.isNotNull(uploadButton);
+    assert.isTrue(uploadButton.disabled);
+    assert.isNull(view.uploadOverlay_);
+
+    view.setActiveTrace('testFile.gz', []);
+
+    var original_data = 'dGVzdAAA';
+    var decoded_size = tr.b.Base64.getDecodedBufferLength(original_data);
+    var buffer = new ArrayBuffer(decoded_size);
+    tr.b.Base64.DecodeToTypedArray(original_data, new DataView(buffer));
+    view.activeTrace_.data = buffer;
+    assert.isFalse(uploadButton.disabled);
+
+    var overlay = null;
+    var clickUploadAndVerify = function() {
+      view.onUploadClicked_();
+      assert.isNotNull(view.uploadOverlay_);
+      assert.isTrue(view.uploadOverlay_.visible);
+      overlay = view.uploadOverlay_;
+      assert.notEqual(view.uploadOverlay_.buttons.style.display, 'none');
+      assert.equal(view.uploadOverlay_.buttons.childNodes.length, 2);
+    };
+    clickUploadAndVerify();
+
+    var cancelButton = view.uploadOverlay_.buttons.lastChild;
+    assert.equal(cancelButton.textContent, 'Cancel');
+    cancelButton.click();
+    assert.isNull(view.uploadOverlay_);
+    assert.isFalse(overlay.visible);
+
+    clickUploadAndVerify();
+    var okButton = view.uploadOverlay_.buttons.firstChild;
+    assert.equal(okButton.textContent, 'Ok');
+    var commandSent = null;
+    var dataSent = null;
+    chrome.send = function(command, data) {
+      commandSent = command;
+      dataSent = data;
+    };
+    okButton.click();
+    assert.equal(commandSent, 'doUploadBase64');
+    assert.equal(dataSent[0], original_data);
+
+    assert.isTrue(view.uploadOverlay_.visible);
+    overlay = view.uploadOverlay_;
+    assert.equal(view.uploadOverlay_.buttons.childNodes.length, 1);
+    var closeButton = view.uploadOverlay_.buttons.childNodes[0];
+    assert.equal(closeButton.textContent, 'Close');
+    closeButton.click();
+    assert.isNull(view.uploadOverlay_);
+    assert.isFalse(overlay.visible);
+  });
+
   test('upload', function() {
     var mock = new tr.ui.e.about_tracing.MockTracingControllerClient();
     mock.allowLooping = true;
@@ -174,8 +238,8 @@
       dataSent = data;
     };
     okButton.click();
-    assert.equal(commandSent, 'doUploadBase64');
-    assert.equal(dataSent[0], btoa(view.activeTrace_.data));
+    assert.equal(commandSent, 'doUpload');
+    assert.equal(dataSent[0], view.activeTrace_.data);
 
     assert.isTrue(view.uploadOverlay_.visible);
     overlay = view.uploadOverlay_;