• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 2213

10 Apr 2024 11:21PM UTC coverage: 91.792% (-0.8%) from 92.623%
2213

push

Evergreen

web-flow
Add missing availability checks for SecCopyErrorMessageString (#7577)

This requires iOS 11.3 and we currently target iOS 11.

94842 of 175770 branches covered (53.96%)

7 of 22 new or added lines in 2 files covered. (31.82%)

1861 existing lines in 82 files now uncovered.

242866 of 264583 relevant lines covered (91.79%)

5593111.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.57
/src/realm/util/uri.cpp
1
#include <realm/util/uri.hpp>
2

3
#include <realm/exceptions.hpp>
4
#include <realm/util/assert.hpp>
5
#include <realm/util/backtrace.hpp>
6

7
#include <algorithm>
8
#include <utility>
9
#include <stdexcept>
10
#include <cctype>
11
#include <sstream>
12
#include <iomanip>
13

14
using namespace realm;
15

16

17
// reserved    = gen-delims sub-delims
18
// gen-delims  = : / ? # [ ] @
19
// sub-delims  = ! $ & ' ( ) * + , ; =
20
// unreserved  = alpha digit - . _ ~
21
// scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
22
// host        = IP-literal / IPv4address / reg-name
23
// reg-name    = *( unreserved / pct-encoded / sub-delims )
24

25

26
util::Uri::Uri(std::string_view str)
27
{
43,730✔
28
    const char* b = str.data();
43,730✔
29
    const char* e = b + str.size();
43,730✔
30

21,414✔
31
    // Scheme
21,414✔
32
    {
43,730✔
33
        const char* c = ":/?#";
43,730✔
34
        const char* p = std::find_first_of(b, e, c, c + 4);
43,730✔
35
        if (p != e && *p == ':') {
43,730✔
36
            m_scheme.assign(b, ++p); // Throws
43,726✔
37
            b = p;
43,726✔
38
        }
43,726✔
39
    }
43,730✔
40

21,414✔
41
    // Authority
21,414✔
42
    if (2 <= e - b && b[0] == '/' && b[1] == '/') {
43,730✔
43
        const char* c = "/?#";
43,722✔
44
        const char* p = std::find_first_of(b + 2, e, c, c + 3);
43,722✔
45
        m_auth.assign(b, p); // Throws
43,722✔
46
        b = p;
43,722✔
47
    }
43,722✔
48

21,414✔
49
    // Path
21,414✔
50
    {
43,730✔
51
        const char* c = "?#";
43,730✔
52
        const char* p = std::find_first_of(b, e, c, c + 2);
43,730✔
53
        m_path.assign(b, p); // Throws
43,730✔
54
        b = p;
43,730✔
55
    }
43,730✔
56

21,414✔
57
    // Query
21,414✔
58
    {
43,730✔
59
        const char* p = std::find(b, e, '#');
43,730✔
60
        m_query.assign(b, p); // Throws
43,730✔
61
        b = p;
43,730✔
62
    }
43,730✔
63

21,414✔
64
    // Fragment
21,414✔
65
    m_frag.assign(b, e); // Throws
43,730✔
66
}
43,730✔
67

68
StatusWith<util::Uri> util::Uri::try_parse(std::string_view str)
69
{
39,740✔
70
    Uri uri(str);
39,740✔
71
    if (uri.m_scheme.empty()) {
39,740✔
72
        return {ErrorCodes::BadServerUrl, util::format("URL missing scheme: %1", str)};
4✔
73
    }
4✔
74
    if (uri.m_auth.empty()) {
39,736✔
UNCOV
75
        return {ErrorCodes::BadServerUrl, util::format("URL missing server: %1", str)};
×
UNCOV
76
    }
×
77
    return uri;
39,736✔
78
}
39,736✔
79

80
util::Uri util::Uri::parse(std::string_view str)
81
{
39,508✔
82
    auto status = try_parse(str);
39,508✔
83
    if (!status.is_ok()) {
39,508✔
UNCOV
84
        throw Exception(status.get_status());
×
UNCOV
85
    }
×
86
    return status.get_value();
39,508✔
87
}
39,508✔
88

89
void util::Uri::set_scheme(const std::string& val)
90
{
20✔
91
    if (!val.empty()) {
20✔
92
        if (val.back() != ':')
16✔
93
            throw util::invalid_argument("URI scheme part must have a trailing ':'");
4✔
94
        if (val.substr(0, val.size() - 1).find_first_of(":/?#") != std::string::npos) {
12✔
95
            throw util::invalid_argument("URI scheme part must not contain '/', '?' or '#', "
4✔
96
                                         "nor may it contain more than one ':'");
4✔
97
        }
4✔
98
    }
12✔
99
    m_scheme = val;
12✔
100
}
12✔
101

102

103
void util::Uri::set_auth(const std::string& val)
104
{
48✔
105
    if (!val.empty()) {
48✔
106
        if (val.size() < 2 || val[0] != '/' || val[1] != '/')
44✔
107
            throw util::invalid_argument("URI authority part must have '//' as a prefix");
8✔
108
        if (val.find_first_of("/?#", 2) != std::string::npos) {
36✔
109
            throw util::invalid_argument("URI authority part must not contain '?' or '#', "
20✔
110
                                         "nor may it contain '/' beyond the two in the prefix");
20✔
111
        }
20✔
112
    }
20✔
113
    m_auth = val;
20✔
114
}
20✔
115

116

117
void util::Uri::set_path(const std::string& val)
118
{
28✔
119
    if (val.find_first_of("?#") != std::string::npos)
28✔
120
        throw util::invalid_argument("URI path part must not contain '?' or '#'");
4✔
121
    m_path = val;
24✔
122
}
24✔
123

124

125
void util::Uri::set_query(const std::string& val)
126
{
32✔
127
    if (!val.empty()) {
32✔
128
        if (val.front() != '?')
28✔
129
            throw util::invalid_argument("URI query string must have a leading '?'");
4✔
130
        if (val.find('#', 1) != std::string::npos)
24✔
131
            throw util::invalid_argument("URI query string must not contain '#'");
4✔
132
    }
24✔
133
    m_query = val;
24✔
134
}
24✔
135

136

137
void util::Uri::set_frag(const std::string& val)
138
{
20✔
139
    if (!val.empty() && val.front() != '#')
20✔
140
        throw util::invalid_argument("Fragment identifier must have a leading '#'");
4✔
141
    m_frag = val;
16✔
142
}
16✔
143

144

145
void util::Uri::canonicalize()
146
{
3,978✔
147
    if (m_scheme.size() == 1)
3,978✔
148
        m_scheme.clear();
4✔
149
    if (m_auth.size() == 2)
3,978✔
150
        m_auth.clear();
4✔
151
    if (m_path.empty() && (!m_scheme.empty() || !m_auth.empty()))
3,978✔
152
        m_path = '/';
8✔
153
    if (m_query.size() == 1)
3,978✔
154
        m_query.clear();
4✔
155
    if (m_frag.size() == 1)
3,978✔
156
        m_frag.clear();
4✔
157
}
3,978✔
158

159

160
bool util::Uri::get_auth(std::string& userinfo, std::string& host, std::string& port) const
161
{
3,982✔
162
    if (m_auth.empty())
3,982✔
163
        return false;
4✔
164

1,814✔
165
    std::string userinfo_2, host_2, port_2;
3,978✔
166
    using size_type = std::string::size_type;
3,978✔
167
    REALM_ASSERT(m_auth.size() >= 2);
3,978✔
168
    size_type i = 2;
3,978✔
169
    size_type j = m_auth.find('@', i);
3,978✔
170
    if (j != std::string::npos) {
3,978✔
171
        userinfo_2 = m_auth.substr(i, j - i); // Throws
4✔
172
        i = j + 1;
4✔
173
    }
4✔
174
    size_type k = m_auth.substr(i).rfind(':');
3,978✔
175
    if (k == std::string::npos) {
3,978✔
176
        k = m_auth.size();
72✔
177
    }
72✔
178
    else {
3,906✔
179
        k = i + k;
3,906✔
180
        port_2 = m_auth.substr(k + 1); // Throws
3,906✔
181
    }
3,906✔
182
    host_2 = m_auth.substr(i, k - i); // Throws
3,978✔
183

1,814✔
184
    userinfo = std::move(userinfo_2);
3,978✔
185
    host = std::move(host_2);
3,978✔
186
    port = std::move(port_2);
3,978✔
187
    return true;
3,978✔
188
}
3,978✔
189

190
namespace {
191

192
bool is_unreserved(unsigned char ch)
193
{
3,876✔
194
    return isalnum(ch) || ch == '-' || ch == '.' || ch == '_' || ch == '~';
3,876✔
195
}
3,876✔
196

197
int decode_char(unsigned char ch)
198
{
1,668✔
199
    if (ch >= '0' && ch <= '9')
1,668✔
200
        return ch - '0';
892✔
201
    if (ch >= 'A' && ch <= 'F')
776✔
202
        return 10 + (ch - 'A');
764✔
203
    if (ch >= 'a' && ch <= 'f')
12✔
UNCOV
204
        return 10 + (ch - 'a');
×
205
    return -1;
12✔
206
}
12✔
207

208
int decode_pair_of_char(unsigned char ch_1, unsigned char ch_2)
209
{
836✔
210
    int result_1 = decode_char(ch_1);
836✔
211
    if (result_1 == -1)
836✔
212
        return -1;
4✔
213
    int result_2 = decode_char(ch_2);
832✔
214
    if (result_2 == -1)
832✔
215
        return -1;
8✔
216
    return result_1 * 16 + result_2;
824✔
217
}
824✔
218

219
} // unnamed namespace
220

221
std::string util::uri_percent_encode(const std::string& unescaped)
222
{
1,068✔
223
    std::ostringstream escaped;
1,068✔
224
    escaped.fill('0');
1,068✔
225
    escaped << std::hex;
1,068✔
226

534✔
227
    for (size_t i = 0; i < unescaped.size(); ++i) {
3,412✔
228
        const unsigned char ch = static_cast<unsigned char>(unescaped[i]);
2,344✔
229
        if (is_unreserved(ch)) {
2,344✔
230
            escaped << ch;
1,520✔
231
        }
1,520✔
232
        else {
824✔
233
            escaped << std::uppercase;
824✔
234
            escaped << '%' << std::setw(2) << static_cast<int>(ch);
824✔
235
            escaped << std::nouppercase;
824✔
236
        }
824✔
237
    }
2,344✔
238

534✔
239
    return escaped.str();
1,068✔
240
}
1,068✔
241

242
std::string util::uri_percent_decode(const std::string& escaped)
243
{
1,100✔
244
    std::ostringstream unescaped;
1,100✔
245

550✔
246
    size_t pos = 0;
1,100✔
247
    while (pos < escaped.size()) {
3,444✔
248
        const unsigned char ch = static_cast<unsigned char>(escaped[pos]);
2,376✔
249
        if (ch == '%') {
2,376✔
250
            if (pos + 2 >= escaped.size())
844✔
251
                throw util::runtime_error("Invalid character in escaped string: " + escaped);
8✔
252
            unsigned char ch_1 = static_cast<unsigned char>(escaped[pos + 1]);
836✔
253
            unsigned char ch_2 = static_cast<unsigned char>(escaped[pos + 2]);
836✔
254
            int result = decode_pair_of_char(ch_1, ch_2);
836✔
255
            if (result == -1)
836✔
256
                throw util::runtime_error("Invalid character in escaped string: " + escaped);
12✔
257
            unescaped << static_cast<char>(result);
824✔
258
            pos += 3;
824✔
259
        }
824✔
260
        else if (is_unreserved(ch)) {
1,532✔
261
            unescaped << ch;
1,520✔
262
            ++pos;
1,520✔
263
        }
1,520✔
264
        else {
12✔
265
            throw util::runtime_error("Invalid character in escaped string: " + escaped);
12✔
266
        }
12✔
267
    }
2,376✔
268

550✔
269
    return unescaped.str();
1,084✔
270
}
1,100✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc