base::Value (de)serialization for some basic net types

Working on some HostCache::Entry replacement work, which requires going
to/from base::Value for these types. This essentially duplicates some of
the (de)serialization logic, which will hopefully eventually be deleted,
in host_cache.cc.

Change-Id: Ib28b4d4b5b1da29824f64fae3bc7d83f602269a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3964882
Commit-Queue: Eric Orth <[email protected]>
Reviewed-by: Tsuyoshi Horo <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1062892}
diff --git a/net/base/ip_endpoint.cc b/net/base/ip_endpoint.cc
index 05466120..7947b58 100644
--- a/net/base/ip_endpoint.cc
+++ b/net/base/ip_endpoint.cc
@@ -8,15 +8,19 @@
 
 #include <string.h>
 #include <tuple>
+#include <utility>
 
 #include "base/check.h"
 #include "base/check_op.h"
 #include "base/notreached.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_byteorder.h"
+#include "base/values.h"
 #include "build/build_config.h"
 #include "net/base/ip_address.h"
 #include "net/base/sys_addrinfo.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 #if BUILDFLAG(IS_WIN)
 #include <winsock2.h>
@@ -27,6 +31,39 @@
 
 namespace net {
 
+namespace {
+
+// Value dictionary keys
+constexpr base::StringPiece kValueAddressKey = "address";
+constexpr base::StringPiece kValuePortKey = "port";
+
+}  // namespace
+
+// static
+absl::optional<IPEndPoint> IPEndPoint::FromValue(const base::Value& value) {
+  const base::Value::Dict* dict = value.GetIfDict();
+  if (!dict)
+    return absl::nullopt;
+
+  const base::Value* address_value = dict->Find(kValueAddressKey);
+  if (!address_value)
+    return absl::nullopt;
+  absl::optional<IPAddress> address = IPAddress::FromValue(*address_value);
+  if (!address.has_value())
+    return absl::nullopt;
+  // Expect IPAddress to only allow deserializing valid addresses.
+  DCHECK(address.value().IsValid());
+
+  absl::optional<int> port = dict->FindInt(kValuePortKey);
+  if (!port.has_value() ||
+      !base::IsValueInRangeForNumericType<uint16_t>(port.value())) {
+    return absl::nullopt;
+  }
+
+  return IPEndPoint(address.value(),
+                    base::checked_cast<uint16_t>(port.value()));
+}
+
 IPEndPoint::IPEndPoint() = default;
 
 IPEndPoint::~IPEndPoint() = default;
@@ -182,6 +219,16 @@
   return !(*this == that);
 }
 
+base::Value IPEndPoint::ToValue() const {
+  base::Value::Dict dict;
+
+  DCHECK(address_.IsValid());
+  dict.Set(kValueAddressKey, address_.ToValue());
+  dict.Set(kValuePortKey, port_);
+
+  return base::Value(std::move(dict));
+}
+
 std::ostream& operator<<(std::ostream& os, const IPEndPoint& ip_endpoint) {
   return os << ip_endpoint.ToString();
 }