Use a wrapper for creating binary NetLog values.

This renames the "hex_encoded_bytes" parameter to "bytes" (Base64 encoded).

The motivation is to move towards a consistent approach for how binary data is encoded.

Bug: 657115
Change-Id: I4762ee774682a0376979d779ac1faa177d2b8701
Reviewed-on: https://chromium-review.googlesource.com/c/1378845
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: Ryan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#616954}
diff --git a/net/log/net_log.cc b/net/log/net_log.cc
index b49fcfc6..f93e89d 100644
--- a/net/log/net_log.cc
+++ b/net/log/net_log.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
@@ -314,4 +315,11 @@
   return base::Value("%ESCAPED:\xE2\x80\x8B " + EscapeNonASCIIAndPercent(raw));
 }
 
+base::Value NetLogBinaryValue(const void* bytes, size_t length) {
+  std::string b64;
+  Base64Encode(base::StringPiece(reinterpret_cast<const char*>(bytes), length),
+               &b64);
+  return base::Value(std::move(b64));
+}
+
 }  // namespace net
diff --git a/net/log/net_log.h b/net/log/net_log.h
index e2c4611..60bcad0 100644
--- a/net/log/net_log.h
+++ b/net/log/net_log.h
@@ -249,6 +249,17 @@
 // may not be UTF-8.
 NET_EXPORT base::Value NetLogStringValue(base::StringPiece raw);
 
+// Creates a base::Value() to represent the octets |bytes|. This should be
+// used when adding binary data (i.e. not an ASCII or UTF-8 string) to the
+// NetLog. The resulting base::Value() holds a copy of the input data.
+//
+// This wrapper must be used rather than directly adding base::Value parameters
+// of type BINARY to the NetLog, since the JSON writer does not support
+// serializing them.
+//
+// This wrapper encodes |bytes| as a Base64 encoded string.
+NET_EXPORT base::Value NetLogBinaryValue(const void* bytes, size_t length);
+
 }  // namespace net
 
 #endif  // NET_LOG_NET_LOG_H_
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 9a2d762..b8f89f2 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -525,7 +525,7 @@
 // An SSL connection sent or received an alert.
 // The following parameters are attached:
 //   {
-//     "hex_encoded_bytes": <The exact bytes sent, as a hexadecimal string>
+//     "bytes": <The exact bytes sent, Base64 encoded>
 //   }
 EVENT_TYPE(SSL_ALERT_RECEIVED)
 EVENT_TYPE(SSL_ALERT_SENT)
@@ -537,8 +537,8 @@
 // The following parameters are attached:
 //   {
 //     "type": <The type of the handshake message, as an integer>
-//     "hex_encoded_bytes": <The exact bytes sent, as a hexadecimal string. May
-//                           be elided in some cases>
+//     "bytes": <The exact bytes sent, Base64 encoded.
+//               May be elided in some cases>
 //   }
 EVENT_TYPE(SSL_HANDSHAKE_MESSAGE_RECEIVED)
 EVENT_TYPE(SSL_HANDSHAKE_MESSAGE_SENT)
@@ -549,8 +549,8 @@
 // The following parameters are attached:
 //   {
 //     "byte_count": <Number of bytes that were just sent>,
-//     "hex_encoded_bytes": <The exact bytes sent, as a hexadecimal string.
-//                           Only present when byte logging is enabled>,
+//     "bytes": <The exact bytes sent, Base64 encoded.
+//               Only present when byte logging is enabled>,
 //   }
 EVENT_TYPE(SOCKET_BYTES_SENT)
 EVENT_TYPE(SSL_SOCKET_BYTES_SENT)
@@ -559,8 +559,8 @@
 // The following parameters are attached:
 //   {
 //     "byte_count": <Number of bytes that were just received>,
-//     "hex_encoded_bytes": <The exact bytes received, as a hexadecimal string.
-//                           Only present when byte logging is enabled>,
+//     "bytes": <The exact bytes received, Base64 encoded.
+//               Only present when byte logging is enabled>,
 //   }
 EVENT_TYPE(SOCKET_BYTES_RECEIVED)
 EVENT_TYPE(SSL_SOCKET_BYTES_RECEIVED)
@@ -694,8 +694,8 @@
 //     "address": <Remote address of data transfer.  Not present when not
 //                 specified for UDP_BYTES_SENT events>,
 //     "byte_count": <Number of bytes that were just received>,
-//     "hex_encoded_bytes": <The exact bytes received, as a hexadecimal string.
-//                           Only present when byte logging is enabled>,
+//     "bytes": <The exact bytes received, Base64 encoded.
+//               Only present when byte logging is enabled>,
 //   }
 EVENT_TYPE(UDP_BYTES_RECEIVED)
 EVENT_TYPE(UDP_BYTES_SENT)
@@ -855,7 +855,7 @@
 // The following parameters are attached:
 //   {
 //     "byte_count": <Number of bytes that were just sent>,
-//     "hex_encoded_bytes": <The exact bytes sent, as a hexadecimal string>,
+//     "bytes": <The exact bytes sent, Base64 encoded>,
 //   }
 EVENT_TYPE(URL_REQUEST_JOB_BYTES_READ)
 EVENT_TYPE(URL_REQUEST_JOB_FILTERED_BYTES_READ)
@@ -1266,8 +1266,8 @@
 // The following parameters are attached:
 //   {
 //     "byte_count": <Number of bytes that were just sent>,
-//     "hex_encoded_bytes": <The exact bytes sent, as a hexadecimal string.
-//                           Only present when byte logging is enabled>,
+//     "bytes": <The exact bytes sent, Base64 encoded.
+//               Only present when byte logging is enabled>,
 //   }
 EVENT_TYPE(BIDIRECTIONAL_STREAM_BYTES_SENT)
 
@@ -1275,8 +1275,8 @@
 // The following parameters are attached:
 //   {
 //     "byte_count": <Number of bytes that were just received>,
-//     "hex_encoded_bytes": <The exact bytes received, as a hexadecimal string.
-//                           Only present when byte logging is enabled>,
+//     "bytes": <The exact bytes received, Base64 encoded.
+//               Only present when byte logging is enabled>,
 //   }
 EVENT_TYPE(BIDIRECTIONAL_STREAM_BYTES_RECEIVED)
 
diff --git a/net/log/net_log_unittest.cc b/net/log/net_log_unittest.cc
index 1384106c..b4b9c0b 100644
--- a/net/log/net_log_unittest.cc
+++ b/net/log/net_log_unittest.cc
@@ -436,6 +436,21 @@
   }
 }
 
+TEST(NetLogTest, NetLogBinaryValue) {
+  // Test the encoding for empty bytes.
+  auto value1 = NetLogBinaryValue(nullptr, 0);
+  std::string string1;
+  ASSERT_TRUE(value1.GetAsString(&string1));
+  EXPECT_EQ("", string1);
+
+  // Test the encoding for a non-empty sequence (which needs padding).
+  const uint8_t kBytes[] = {0x00, 0xF3, 0xF8, 0xFF};
+  auto value2 = NetLogBinaryValue(kBytes, base::size(kBytes));
+  std::string string2;
+  ASSERT_TRUE(value2.GetAsString(&string2));
+  EXPECT_EQ("APP4/w==", string2);
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/net/log/net_log_with_source.cc b/net/log/net_log_with_source.cc
index 50020e5..0e88cdf 100644
--- a/net/log/net_log_with_source.cc
+++ b/net/log/net_log_with_source.cc
@@ -11,7 +11,6 @@
 #include "base/callback.h"
 #include "base/debug/alias.h"
 #include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "net/base/net_errors.h"
 #include "net/log/net_log.h"
@@ -23,8 +22,7 @@
 
 // Returns parameters for logging data transferred events. At a minimum includes
 // the number of bytes transferred. If the capture mode allows logging byte
-// contents and |byte_count| > 0, then will include the actual bytes. The
-// bytes are hex-encoded, since base::Value only supports UTF-8.
+// contents and |byte_count| > 0, then will include the actual bytes.
 std::unique_ptr<base::Value> BytesTransferredCallback(
     int byte_count,
     const char* bytes,
@@ -32,7 +30,7 @@
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
   dict->SetInteger("byte_count", byte_count);
   if (capture_mode.include_socket_bytes() && byte_count > 0)
-    dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count));
+    dict->SetKey("bytes", NetLogBinaryValue(bytes, byte_count));
   return std::move(dict);
 }
 
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 99caa15..450c8c3 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -21,7 +21,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
@@ -116,7 +115,7 @@
     size_t len,
     NetLogCaptureMode capture_mode) {
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, len));
+  dict->SetKey("bytes", NetLogBinaryValue(bytes, len));
   return std::move(dict);
 }
 
@@ -142,7 +141,7 @@
   // information on the user's identity.
   if (!is_write || type != SSL3_MT_CERTIFICATE ||
       capture_mode.include_socket_bytes()) {
-    dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, len));
+    dict->SetKey("bytes", NetLogBinaryValue(bytes, len));
   }
 
   return std::move(dict);
diff --git a/net/socket/udp_net_log_parameters.cc b/net/socket/udp_net_log_parameters.cc
index 235fde5..4efcbd9 100644
--- a/net/socket/udp_net_log_parameters.cc
+++ b/net/socket/udp_net_log_parameters.cc
@@ -7,9 +7,9 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "net/base/ip_endpoint.h"
+#include "net/log/net_log.h"
 
 namespace net {
 
@@ -23,7 +23,7 @@
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
   dict->SetInteger("byte_count", byte_count);
   if (capture_mode.include_socket_bytes())
-    dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count));
+    dict->SetKey("bytes", NetLogBinaryValue(bytes, byte_count));
   if (address)
     dict->SetString("address", address->ToString());
   return std::move(dict);
diff --git a/net/tools/print_certificates.py b/net/tools/print_certificates.py
index 908b36d..9889b6f 100755
--- a/net/tools/print_certificates.py
+++ b/net/tools/print_certificates.py
@@ -121,6 +121,7 @@
   lines = netlog_text.splitlines()
 
   # Skip the text preceeding the actual hexdump.
+  # TODO(eroman): New logs name this field "bytes" and it is Base64 encoded.
   while lines and 'hex_encoded_bytes' not in lines[0]:
     del lines[0]
   if not lines: