Skip to content

Commit 031442d

Browse files
mikelehenCorrob
authored andcommitted
Take 2: Move input validation logic from FIRFieldPath to model::FieldPath. (#2727) (#2790)
* Move input validation logic from FIRFieldPath to model::FieldPath. (#2727)
1 parent 0ee2aa3 commit 031442d

File tree

4 files changed

+65
-19
lines changed

4 files changed

+65
-19
lines changed

Firestore/Source/API/FIRFieldPath.mm

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,10 @@ - (instancetype)initWithFields:(NSArray<NSString *> *)fieldNames {
5151
std::vector<std::string> field_names;
5252
field_names.reserve(fieldNames.count);
5353
for (int i = 0; i < fieldNames.count; ++i) {
54-
if (fieldNames[i].length == 0) {
55-
ThrowInvalidArgument("Invalid field name at index %s. Field names must not be empty.", i);
56-
}
5754
field_names.emplace_back(util::MakeString(fieldNames[i]));
5855
}
5956

60-
return [self initPrivate:FieldPath(std::move(field_names))];
57+
return [self initPrivate:FieldPath::FromSegments(std::move(field_names))];
6158
}
6259

6360
+ (instancetype)documentID {
@@ -72,21 +69,8 @@ - (instancetype)initPrivate:(FieldPath)fieldPath {
7269
}
7370

7471
+ (instancetype)pathWithDotSeparatedString:(NSString *)path {
75-
if ([[FIRFieldPath reservedCharactersRegex]
76-
numberOfMatchesInString:path
77-
options:0
78-
range:NSMakeRange(0, path.length)] > 0) {
79-
ThrowInvalidArgument(
80-
"Invalid field path (%s). Paths must not contain '~', '*', '/', '[', or ']'", path);
81-
}
82-
@try {
83-
return [[FIRFieldPath alloc] initWithFields:[path componentsSeparatedByString:@"."]];
84-
} @catch (NSException *exception) {
85-
ThrowInvalidArgument(
86-
"Invalid field path (%s). Paths must not be empty, begin with '.', end with '.', or "
87-
"contain '..'",
88-
path);
89-
}
72+
return
73+
[[FIRFieldPath alloc] initPrivate:FieldPath::FromDotSeparatedString(util::MakeString(path))];
9074
}
9175

9276
/** Matches any characters in a field path string that are reserved. */

Firestore/core/src/firebase/firestore/model/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ cc_library(
5050
DEPENDS
5151
absl_optional
5252
absl_strings
53+
firebase_firestore_api_input_validation
5354
firebase_firestore_immutable
5455
firebase_firestore_util
5556
firebase_firestore_types

Firestore/core/src/firebase/firestore/model/field_path.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <algorithm>
2020
#include <utility>
2121

22+
#include "Firestore/core/src/firebase/firestore/api/input_validation.h"
2223
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
2324
#include "absl/strings/str_join.h"
2425
#include "absl/strings/str_replace.h"
@@ -28,6 +29,8 @@ namespace firebase {
2829
namespace firestore {
2930
namespace model {
3031

32+
using api::ThrowInvalidArgument;
33+
3134
namespace {
3235

3336
/**
@@ -78,6 +81,28 @@ struct JoinEscaped {
7881
};
7982
} // namespace
8083

84+
FieldPath FieldPath::FromDotSeparatedString(absl::string_view path) {
85+
if (path.find_first_of("~*/[]") != absl::string_view::npos) {
86+
ThrowInvalidArgument(
87+
"Invalid field path (%s). Paths must not contain '~', '*', '/', '[', "
88+
"or ']'",
89+
path);
90+
}
91+
92+
SegmentsT segments =
93+
absl::StrSplit(path, '.', [path](absl::string_view segment) {
94+
if (segment.empty()) {
95+
ThrowInvalidArgument(
96+
"Invalid field path (%s). Paths must not be empty, begin with "
97+
"'.', end with '.', or contain '..'",
98+
path);
99+
}
100+
return true;
101+
});
102+
103+
return FieldPath(std::move(segments));
104+
}
105+
81106
FieldPath FieldPath::FromServerFormat(const absl::string_view path) {
82107
SegmentsT segments;
83108
std::string segment;

Firestore/core/src/firebase/firestore/model/field_path.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <string>
2222
#include <utility>
2323

24+
#include "Firestore/core/src/firebase/firestore/api/input_validation.h"
2425
#include "Firestore/core/src/firebase/firestore/model/base_path.h"
2526
#include "absl/strings/string_view.h"
2627

@@ -51,6 +52,25 @@ class FieldPath : public impl::BasePath<FieldPath> {
5152
explicit FieldPath(SegmentsT&& segments) : BasePath{std::move(segments)} {
5253
}
5354

55+
/**
56+
* Creates and returns a new path from a dot-separated field-path string,
57+
* where path segments are separated by a dot ".".
58+
*
59+
* PORTING NOTE: We define this on the model class to avoid having a tiny
60+
* api::FieldPath wrapper class.
61+
*/
62+
static FieldPath FromDotSeparatedString(absl::string_view path);
63+
64+
/**
65+
* Creates and returns a new path from a set of segments received from the
66+
* public API.
67+
*/
68+
static FieldPath FromSegments(SegmentsT&& segments) {
69+
ValidateSegments(segments);
70+
FieldPath path(std::move(segments));
71+
return path;
72+
}
73+
5474
/**
5575
* Creates and returns a new path from the server formatted field-path string,
5676
* where path segments are separated by a dot "." and optionally encoded using
@@ -85,6 +105,22 @@ class FieldPath : public impl::BasePath<FieldPath> {
85105
bool operator>=(const FieldPath& rhs) const {
86106
return BasePath::operator>=(rhs);
87107
}
108+
109+
private:
110+
static void ValidateSegments(const SegmentsT& segments) {
111+
if (segments.empty()) {
112+
api::ThrowInvalidArgument(
113+
"Invalid field path. Provided names must not be empty.");
114+
}
115+
116+
for (size_t i = 0; i < segments.size(); i++) {
117+
if (segments[i].empty()) {
118+
api::ThrowInvalidArgument(
119+
"Invalid field name at index %s. Field names must not be empty.",
120+
i);
121+
}
122+
}
123+
}
88124
};
89125

90126
} // namespace model

0 commit comments

Comments
 (0)