• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "discovery/dnssd/public/dns_sd_txt_record.h"
6 
7 #include <cctype>
8 #include <utility>
9 
10 namespace openscreen {
11 namespace discovery {
12 
13 // static
IsValidTxtValue(const std::string & key,const std::vector<uint8_t> & value)14 bool DnsSdTxtRecord::IsValidTxtValue(const std::string& key,
15                                      const std::vector<uint8_t>& value) {
16   // The max length of any individual TXT record is 255 bytes.
17   if (key.size() + value.size() + 1 /* for equals */ > 255) {
18     return false;
19   }
20 
21   return IsKeyValid(key);
22 }
23 
24 // static
IsValidTxtValue(const std::string & key,uint8_t value)25 bool DnsSdTxtRecord::IsValidTxtValue(const std::string& key, uint8_t value) {
26   return IsValidTxtValue(key, std::vector<uint8_t>{value});
27 }
28 
29 // static
IsValidTxtValue(const std::string & key,const std::string & value)30 bool DnsSdTxtRecord::IsValidTxtValue(const std::string& key,
31                                      const std::string& value) {
32   return IsValidTxtValue(key, std::vector<uint8_t>(value.begin(), value.end()));
33 }
34 
SetValue(const std::string & key,std::vector<uint8_t> value)35 Error DnsSdTxtRecord::SetValue(const std::string& key,
36                                std::vector<uint8_t> value) {
37   if (!IsValidTxtValue(key, value)) {
38     return Error::Code::kParameterInvalid;
39   }
40 
41   key_value_txt_[key] = std::move(value);
42   ClearFlag(key);
43   return Error::None();
44 }
45 
SetValue(const std::string & key,const std::string & value)46 Error DnsSdTxtRecord::SetValue(const std::string& key,
47                                const std::string& value) {
48   return SetValue(key, std::vector<uint8_t>(value.begin(), value.end()));
49 }
50 
SetFlag(const std::string & key,bool value)51 Error DnsSdTxtRecord::SetFlag(const std::string& key, bool value) {
52   if (!IsKeyValid(key)) {
53     return Error::Code::kParameterInvalid;
54   }
55 
56   if (value) {
57     boolean_txt_.insert(key);
58   } else {
59     ClearFlag(key);
60   }
61   ClearValue(key);
62   return Error::None();
63 }
64 
GetValue(const std::string & key) const65 ErrorOr<DnsSdTxtRecord::ValueRef> DnsSdTxtRecord::GetValue(
66     const std::string& key) const {
67   if (!IsKeyValid(key)) {
68     return Error::Code::kParameterInvalid;
69   }
70 
71   auto it = key_value_txt_.find(key);
72   if (it != key_value_txt_.end()) {
73     return std::cref(it->second);
74   }
75 
76   return Error::Code::kItemNotFound;
77 }
78 
GetFlag(const std::string & key) const79 ErrorOr<bool> DnsSdTxtRecord::GetFlag(const std::string& key) const {
80   if (!IsKeyValid(key)) {
81     return Error::Code::kParameterInvalid;
82   }
83 
84   return boolean_txt_.find(key) != boolean_txt_.end();
85 }
86 
ClearValue(const std::string & key)87 Error DnsSdTxtRecord::ClearValue(const std::string& key) {
88   if (!IsKeyValid(key)) {
89     return Error::Code::kParameterInvalid;
90   }
91 
92   key_value_txt_.erase(key);
93   return Error::None();
94 }
95 
ClearFlag(const std::string & key)96 Error DnsSdTxtRecord::ClearFlag(const std::string& key) {
97   if (!IsKeyValid(key)) {
98     return Error::Code::kParameterInvalid;
99   }
100 
101   boolean_txt_.erase(key);
102   return Error::None();
103 }
104 
105 // static
IsKeyValid(const std::string & key)106 bool DnsSdTxtRecord::IsKeyValid(const std::string& key) {
107   // The max length of any individual TXT record is 255 bytes.
108   if (key.size() > 255) {
109     return false;
110   }
111 
112   // The length of a key must be at least 1.
113   if (key.size() < 1) {
114     return false;
115   }
116 
117   // Keys must contain only valid characters.
118   for (char key_char : key) {
119     if (key_char < char{0x20} || key_char > char{0x7E} || key_char == '=') {
120       return false;
121     }
122   }
123 
124   return true;
125 }
126 
GetData() const127 std::vector<std::vector<uint8_t>> DnsSdTxtRecord::GetData() const {
128   std::vector<std::vector<uint8_t>> data;
129   for (const auto& pair : key_value_txt_) {
130     data.emplace_back();
131     std::vector<uint8_t>* new_entry = &data.back();
132     new_entry->reserve(pair.first.size() + 1 + pair.second.size());
133     new_entry->insert(new_entry->end(), pair.first.begin(), pair.first.end());
134     new_entry->push_back('=');
135     new_entry->insert(new_entry->end(), pair.second.begin(), pair.second.end());
136   }
137 
138   for (const auto& flag : boolean_txt_) {
139     data.emplace_back();
140     std::vector<uint8_t>* new_entry = &data.back();
141     new_entry->insert(new_entry->end(), flag.begin(), flag.end());
142   }
143 
144   return data;
145 }
146 
operator ()(const std::string & lhs,const std::string & rhs) const147 bool DnsSdTxtRecord::CaseInsensitiveComparison::operator()(
148     const std::string& lhs,
149     const std::string& rhs) const {
150   if (lhs.size() != rhs.size()) {
151     return lhs < rhs;
152   }
153 
154   for (size_t i = 0; i < lhs.size(); i++) {
155     int lhs_char = tolower(lhs[i]);
156     int rhs_char = tolower(rhs[i]);
157 
158     if (lhs_char != rhs_char) {
159       return lhs_char < rhs_char;
160     }
161   }
162 
163   return false;
164 }
165 
166 }  // namespace discovery
167 }  // namespace openscreen
168