aboutsummaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorJordan Bayles <jophba@chromium.org>2020-12-10 11:12:44 -0800
committerCommit Bot <commit-bot@chromium.org>2020-12-10 19:26:04 +0000
commit79c6ea2a0c44439e73d3c9d9859513eb4d086983 (patch)
treeb6eb16b78bc168225621f6a39a2aee83e2888514 /util
parentb2522b5f9832ad9e64428a2245f4a7fb0171ec8d (diff)
downloadopenscreen-79c6ea2a0c44439e73d3c9d9859513eb4d086983.tar.gz
Refactor session message sending
This patch refactors session message sending to include multiple new message types, such as RPC and GET_STATUS. Integration tests are included. Bug: b/170756458, b/174188662 Change-Id: I8b5de8a668171e0ce7cb3e74651d207aa7911c24 Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/2506651 Commit-Queue: Jordan Bayles <jophba@chromium.org> Reviewed-by: Yuri Wiitala <miu@chromium.org>
Diffstat (limited to 'util')
-rw-r--r--util/BUILD.gn7
-rw-r--r--util/base64.cc54
-rw-r--r--util/base64.h31
-rw-r--r--util/base64_unittest.cc60
-rw-r--r--util/json/json_helpers.h16
-rw-r--r--util/json/json_helpers_unittest.cc7
6 files changed, 169 insertions, 6 deletions
diff --git a/util/BUILD.gn b/util/BUILD.gn
index f1da81e4..1cb34360 100644
--- a/util/BUILD.gn
+++ b/util/BUILD.gn
@@ -21,6 +21,8 @@ source_set("util") {
sources = [
"alarm.cc",
"alarm.h",
+ "base64.cc",
+ "base64.h",
"big_endian.cc",
"big_endian.h",
"chrono_helpers.h",
@@ -78,6 +80,10 @@ source_set("util") {
deps = [
"../third_party/boringssl",
"../third_party/mozilla",
+
+ # We do a clone of Chrome's modp_b64 in order to share their BUILD.gn
+ # and license files, so this should always be an absolute reference.
+ "//third_party/modp_b64",
]
public_configs = [
@@ -91,6 +97,7 @@ source_set("unittests") {
sources = [
"alarm_unittest.cc",
+ "base64_unittest.cc",
"big_endian_unittest.cc",
"crypto/random_bytes_unittest.cc",
"crypto/rsa_private_key_unittest.cc",
diff --git a/util/base64.cc b/util/base64.cc
new file mode 100644
index 00000000..06e120e0
--- /dev/null
+++ b/util/base64.cc
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "util/base64.h"
+
+#include <stddef.h>
+
+#include "third_party/modp_b64/modp_b64.h"
+#include "util/osp_logging.h"
+#include "util/std_util.h"
+
+namespace openscreen {
+namespace base64 {
+
+std::string Encode(absl::Span<const uint8_t> input) {
+ return Encode(absl::string_view(reinterpret_cast<const char*>(input.data()),
+ input.size()));
+}
+
+std::string Encode(absl::string_view input) {
+ std::string out;
+ out.resize(modp_b64_encode_len(input.size()));
+
+ const size_t output_size =
+ modp_b64_encode(data(out), input.data(), input.size());
+ if (output_size == MODP_B64_ERROR) {
+ return {};
+ }
+
+ // The encode_len is generally larger than needed.
+ out.resize(output_size);
+ return out;
+}
+
+bool Decode(absl::string_view input, std::string* output) {
+ std::string out;
+ out.resize(modp_b64_decode_len(input.size()));
+
+ // We don't null terminate the result since it is binary data.
+ const size_t output_size =
+ modp_b64_decode(data(out), input.data(), input.size());
+ if (output_size == MODP_B64_ERROR) {
+ return false;
+ }
+
+ // The output size from decode_len is generally larger than needed.
+ out.resize(output_size);
+ output->swap(out);
+ return true;
+}
+
+} // namespace base64
+} // namespace openscreen
diff --git a/util/base64.h b/util/base64.h
new file mode 100644
index 00000000..b24c3b3f
--- /dev/null
+++ b/util/base64.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UTIL_BASE64_H_
+#define UTIL_BASE64_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+#include "platform/base/error.h"
+
+namespace openscreen {
+namespace base64 {
+
+// Encodes the input binary data in base64.
+std::string Encode(absl::Span<const uint8_t> input);
+
+// Encodes the input string in base64.
+std::string Encode(absl::string_view input);
+
+// Decodes the base64 input string. Returns true if successful and false
+// otherwise. The output string is only modified if successful. The decoding can
+// be done in-place.
+bool Decode(absl::string_view input, std::string* output);
+
+} // namespace base64
+} // namespace openscreen
+
+#endif // UTIL_BASE64_H_
diff --git a/util/base64_unittest.cc b/util/base64_unittest.cc
new file mode 100644
index 00000000..28d4fb1d
--- /dev/null
+++ b/util/base64_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "util/base64.h"
+
+#include "gtest/gtest.h"
+
+namespace openscreen {
+namespace base64 {
+
+namespace {
+
+constexpr char kText[] = "hello world";
+constexpr char kBase64Text[] = "aGVsbG8gd29ybGQ=";
+
+void CheckEncodeDecode(const char* to_encode, const char* encode_expected) {
+ std::string encoded = Encode(to_encode);
+ EXPECT_EQ(encode_expected, encoded);
+
+ std::string decoded;
+ EXPECT_TRUE(Decode(encoded, &decoded));
+ EXPECT_EQ(to_encode, decoded);
+}
+
+} // namespace
+
+TEST(Base64Test, ZeroSize) {
+ CheckEncodeDecode("", "");
+}
+
+TEST(Base64Test, Basic) {
+ CheckEncodeDecode(kText, kBase64Text);
+}
+
+TEST(Base64Test, Binary) {
+ const uint8_t kData[] = {0x00, 0x01, 0xFE, 0xFF};
+
+ std::string binary_encoded = Encode(absl::MakeConstSpan(kData));
+
+ // Check that encoding the same data through the StringPiece interface gives
+ // the same results.
+ std::string string_piece_encoded = Encode(
+ absl::string_view(reinterpret_cast<const char*>(kData), sizeof(kData)));
+
+ EXPECT_EQ(binary_encoded, string_piece_encoded);
+}
+
+TEST(Base64Test, InPlace) {
+ std::string text(kText);
+
+ text = Encode(text);
+ EXPECT_EQ(kBase64Text, text);
+
+ EXPECT_TRUE(Decode(text, &text));
+ EXPECT_EQ(text, kText);
+}
+
+} // namespace base64
+} // namespace openscreen
diff --git a/util/json/json_helpers.h b/util/json/json_helpers.h
index a4c43479..1943973d 100644
--- a/util/json/json_helpers.h
+++ b/util/json/json_helpers.h
@@ -6,6 +6,7 @@
#define UTIL_JSON_JSON_HELPERS_H_
#include <chrono>
+#include <cmath>
#include <functional>
#include <string>
#include <utility>
@@ -77,16 +78,19 @@ inline bool ParseBool(const Json::Value& value, bool* out) {
}
// A general note about parsing primitives. "Validation" in this context
-// generally means ensuring that the values are non-negative. There are
-// currently no cases in our usage of JSON strings where we accept negative
-// values. If this changes in the future, care must be taken to ensure
-// that we don't break anything in existing code.
-inline bool ParseAndValidateDouble(const Json::Value& value, double* out) {
+// generally means ensuring that the values are non-negative, excepting doubles
+// which may be negative in some cases.
+inline bool ParseAndValidateDouble(const Json::Value& value,
+ double* out,
+ bool allow_negative = false) {
if (!value.isDouble()) {
return false;
}
const double d = value.asDouble();
- if (d < 0) {
+ if (std::isnan(d)) {
+ return false;
+ }
+ if (!allow_negative && d < 0) {
return false;
}
*out = d;
diff --git a/util/json/json_helpers_unittest.cc b/util/json/json_helpers_unittest.cc
index fdac1897..c461cf93 100644
--- a/util/json/json_helpers_unittest.cc
+++ b/util/json/json_helpers_unittest.cc
@@ -42,6 +42,7 @@ TEST(ParsingHelpersTest, ParseAndValidateDouble) {
const Json::Value kNotDouble = "coffee beans";
const Json::Value kNegativeDouble = -4.2;
const Json::Value kZeroDouble = 0.0;
+ const Json::Value kNanDouble = std::nan("");
double out;
EXPECT_TRUE(ParseAndValidateDouble(kValid, &out));
@@ -51,6 +52,7 @@ TEST(ParsingHelpersTest, ParseAndValidateDouble) {
EXPECT_FALSE(ParseAndValidateDouble(kNotDouble, &out));
EXPECT_FALSE(ParseAndValidateDouble(kNegativeDouble, &out));
EXPECT_FALSE(ParseAndValidateDouble(kNone, &out));
+ EXPECT_FALSE(ParseAndValidateDouble(kNanDouble, &out));
}
TEST(ParsingHelpersTest, ParseAndValidateInt) {
@@ -105,18 +107,23 @@ TEST(ParsingHelpersTest, ParseAndValidateSimpleFraction) {
const Json::Value kNegative = "10/-2";
const Json::Value kInvalidNumber = "-1";
const Json::Value kNotSimpleFraction = "latte";
+ const Json::Value kInteger = 123;
+ const Json::Value kNegativeInteger = -5000;
SimpleFraction out;
EXPECT_TRUE(ParseAndValidateSimpleFraction(kValid, &out));
EXPECT_EQ((SimpleFraction{42, 30}), out);
EXPECT_TRUE(ParseAndValidateSimpleFraction(kValidNumber, &out));
EXPECT_EQ((SimpleFraction{42, 1}), out);
+ EXPECT_TRUE(ParseAndValidateSimpleFraction(kInteger, &out));
+ EXPECT_EQ((SimpleFraction{123, 1}), out);
EXPECT_FALSE(ParseAndValidateSimpleFraction(kUndefined, &out));
EXPECT_FALSE(ParseAndValidateSimpleFraction(kNegative, &out));
EXPECT_FALSE(ParseAndValidateSimpleFraction(kInvalidNumber, &out));
EXPECT_FALSE(ParseAndValidateSimpleFraction(kNotSimpleFraction, &out));
EXPECT_FALSE(ParseAndValidateSimpleFraction(kNone, &out));
EXPECT_FALSE(ParseAndValidateSimpleFraction(kEmptyString, &out));
+ EXPECT_FALSE(ParseAndValidateSimpleFraction(kNegativeInteger, &out));
}
TEST(ParsingHelpersTest, ParseAndValidateMilliseconds) {