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

realm / realm-core / daniel.tabacaru_887

07 Aug 2024 08:36PM UTC coverage: 91.108% (+0.02%) from 91.087%
daniel.tabacaru_887

Pull #7963

Evergreen

danieltabacaru
Unregister SyncSession callbacks when SyncManager is destroyed
Pull Request #7963: RJS-2784 Fix callback crashes when reloading with React Native

102796 of 181584 branches covered (56.61%)

35 of 37 new or added lines in 2 files covered. (94.59%)

294 existing lines in 9 files now uncovered.

217072 of 238259 relevant lines covered (91.11%)

5903576.39 hits per line

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

82.51
/src/realm/sync/noinst/protocol_codec.cpp
1
#include <realm/util/assert.hpp>
2
#include <realm/util/base64.hpp>
3
#include <realm/util/from_chars.hpp>
4
#include <realm/sync/noinst/protocol_codec.hpp>
5

6
namespace realm::_impl {
7

8
using OutputBuffer = util::ResettableExpandableBufferOutputStream;
9

10
// Client protocol
11

12
void ClientProtocol::make_pbs_bind_message(int protocol_version, OutputBuffer& out, session_ident_type session_ident,
13
                                           const std::string& server_path, const std::string& signed_user_token,
14
                                           bool need_client_file_ident, bool is_subserver)
15
{
6,520✔
16
    static_cast<void>(protocol_version);
6,520✔
17
    out << "bind " << session_ident << " " << server_path.size() << " " << signed_user_token.size() << " "
6,520✔
18
        << int(need_client_file_ident) << " " << int(is_subserver) << "\n"; // Throws
6,520✔
19
    REALM_ASSERT(!out.fail());
6,520✔
20

21
    out.write(server_path.data(), server_path.size());             // Throws
6,520✔
22
    out.write(signed_user_token.data(), signed_user_token.size()); // Throws
6,520✔
23
}
6,520✔
24

25
void ClientProtocol::make_flx_bind_message(int protocol_version, OutputBuffer& out, session_ident_type session_ident,
26
                                           const nlohmann::json& json_data, const std::string& signed_user_token,
27
                                           bool need_client_file_ident, bool is_subserver)
28
{
1,894✔
29
    static_cast<void>(protocol_version);
1,894✔
30
    std::string json_data_stg;
1,894✔
31
    // Protocol version v8 and above accepts stringified json_data for the first data argument
32
    if (!json_data.empty()) {
1,894✔
33
        json_data_stg = json_data.dump();
1,890✔
34
    }
1,890✔
35

36
    out << "bind " << session_ident << " " << json_data_stg.size() << " " << signed_user_token.size() << " "
1,894✔
37
        << int(need_client_file_ident) << " " << int(is_subserver) << "\n"; // Throws
1,894✔
38
    REALM_ASSERT(!out.fail());
1,894✔
39

40
    out.write(json_data_stg.data(), json_data_stg.size());         // Throws
1,894✔
41
    out.write(signed_user_token.data(), signed_user_token.size()); // Throws
1,894✔
42
}
1,894✔
43

44
void ClientProtocol::make_pbs_ident_message(OutputBuffer& out, session_ident_type session_ident,
45
                                            SaltedFileIdent client_file_ident, const SyncProgress& progress)
46
{
5,880✔
47
    out << "ident " << session_ident << " " << client_file_ident.ident << " " << client_file_ident.salt << " "
5,880✔
48
        << progress.download.server_version << " " << progress.download.last_integrated_client_version << " "
5,880✔
49
        << progress.latest_server_version.version << " " << progress.latest_server_version.salt << "\n"; // Throws
5,880✔
50
    REALM_ASSERT(!out.fail());
5,880✔
51
}
5,880✔
52

53
void ClientProtocol::make_flx_ident_message(OutputBuffer& out, session_ident_type session_ident,
54
                                            SaltedFileIdent client_file_ident, const SyncProgress& progress,
55
                                            int64_t query_version, std::string_view query_body)
56
{
1,800✔
57
    out << "ident " << session_ident << " " << client_file_ident.ident << " " << client_file_ident.salt << " "
1,800✔
58
        << progress.download.server_version << " " << progress.download.last_integrated_client_version << " "
1,800✔
59
        << progress.latest_server_version.version << " " << progress.latest_server_version.salt << " "
1,800✔
60
        << query_version << " " << query_body.size() << "\n"
1,800✔
61
        << query_body; // Throws
1,800✔
62
    REALM_ASSERT(!out.fail());
1,800✔
63
}
1,800✔
64

65
void ClientProtocol::make_query_change_message(OutputBuffer& out, session_ident_type session, int64_t version,
66
                                               std::string_view query_body)
67
{
1,380✔
68
    out << "query " << session << " " << version << " " << query_body.size() << "\n" << query_body; // throws
1,380✔
69
    REALM_ASSERT(!out.fail());
1,380✔
70
}
1,380✔
71

72
void ClientProtocol::make_json_error_message(OutputBuffer& out, session_ident_type session, int error_code,
73
                                             std::string_view error_body)
74
{
30✔
75
    out << "json_error " << error_code << " " << error_body.size() << " " << session << "\n" << error_body; // throws
30✔
76
    REALM_ASSERT(!out.fail());
30✔
77
}
30✔
78

79
void ClientProtocol::make_test_command_message(OutputBuffer& out, session_ident_type session,
80
                                               request_ident_type request_ident, std::string_view body)
81
{
68✔
82
    out << "test_command " << session << " " << request_ident << " " << body.size() << "\n" << body;
68✔
83
    REALM_ASSERT(!out.fail());
68✔
84
}
68✔
85

86
ClientProtocol::UploadMessageBuilder::UploadMessageBuilder(
87
    OutputBuffer& body_buffer, std::vector<char>& compression_buffer,
88
    util::compression::CompressMemoryArena& compress_memory_arena)
89
    : m_body_buffer{body_buffer}
28,014✔
90
    , m_compression_buffer{compression_buffer}
28,014✔
91
    , m_compress_memory_arena{compress_memory_arena}
28,014✔
92
{
55,870✔
93
    m_body_buffer.reset();
55,870✔
94
}
55,870✔
95

96
void ClientProtocol::UploadMessageBuilder::add_changeset(version_type client_version, version_type server_version,
97
                                                         timestamp_type origin_timestamp,
98
                                                         file_ident_type origin_file_ident,
99
                                                         ChunkedBinaryData changeset)
100
{
43,012✔
101
    m_body_buffer << client_version << " " << server_version << " " << origin_timestamp << " " << origin_file_ident
43,012✔
102
                  << " " << changeset.size() << " "; // Throws
43,012✔
103
    changeset.write_to(m_body_buffer);               // Throws
43,012✔
104
    REALM_ASSERT(!m_body_buffer.fail());
43,012✔
105

106
    ++m_num_changesets;
43,012✔
107
}
43,012✔
108

109
void ClientProtocol::UploadMessageBuilder::make_upload_message(int protocol_version, OutputBuffer& out,
110
                                                               session_ident_type session_ident,
111
                                                               version_type progress_client_version,
112
                                                               version_type progress_server_version,
113
                                                               version_type locked_server_version)
114
{
55,870✔
115
    static_cast<void>(protocol_version);
55,870✔
116
    BinaryData body = {m_body_buffer.data(), std::size_t(m_body_buffer.size())};
55,870✔
117

118
    constexpr std::size_t g_max_uncompressed = 1024;
55,870✔
119

120
    bool is_body_compressed = false;
55,870✔
121
    if (body.size() > g_max_uncompressed) {
55,870✔
122
        util::compression::allocate_and_compress(m_compress_memory_arena, body,
4,840✔
123
                                                 m_compression_buffer); // Throws
4,840✔
124
        is_body_compressed = m_compression_buffer.size() < body.size();
4,840✔
125
    }
4,840✔
126

127
    // The compressed body is only sent if it is smaller than the uncompressed body.
128
    std::size_t compressed_body_size = is_body_compressed ? m_compression_buffer.size() : 0;
55,870✔
129

130
    // The header of the upload message.
131
    out << "upload " << session_ident << " " << int(is_body_compressed) << " " << body.size() << " "
55,870✔
132
        << compressed_body_size;
55,870✔
133
    out << " " << progress_client_version << " " << progress_server_version << " " << locked_server_version; // Throws
55,870✔
134
    out << "\n";                                                                                             // Throws
55,870✔
135

136
    if (is_body_compressed)
55,870✔
137
        out.write(m_compression_buffer.data(), compressed_body_size); // Throws
4,840✔
138
    else
51,030✔
139
        out.write(body.data(), body.size()); // Throws
51,030✔
140

141
    REALM_ASSERT(!out.fail());
55,870✔
142
}
55,870✔
143

144
ClientProtocol::UploadMessageBuilder ClientProtocol::make_upload_message_builder()
145
{
55,870✔
146
    return UploadMessageBuilder{m_output_buffer, m_buffer, m_compress_memory_arena};
55,870✔
147
}
55,870✔
148

149
void ClientProtocol::make_unbind_message(OutputBuffer& out, session_ident_type session_ident)
150
{
6,060✔
151
    out << "unbind " << session_ident << "\n"; // Throws
6,060✔
152
    REALM_ASSERT(!out.fail());
6,060✔
153
}
6,060✔
154

155
void ClientProtocol::make_mark_message(OutputBuffer& out, session_ident_type session_ident,
156
                                       request_ident_type request_ident)
157
{
17,890✔
158
    out << "mark " << session_ident << " " << request_ident << "\n"; // Throws
17,890✔
159
    REALM_ASSERT(!out.fail());
17,890✔
160
}
17,890✔
161

162

163
void ClientProtocol::make_ping(OutputBuffer& out, milliseconds_type timestamp, milliseconds_type rtt)
164
{
146✔
165
    out << "ping " << timestamp << " " << rtt << "\n"; // Throws
146✔
166
}
146✔
167

168

169
std::string ClientProtocol::compressed_hex_dump(BinaryData blob)
170
{
×
171
    std::vector<char> buf;
×
172
    util::compression::allocate_and_compress(m_compress_memory_arena, blob, buf); // Throws
×
173

174
    std::string encode_buffer;
×
175
    auto encoded_size = util::base64_encoded_size(buf.size());
×
176
    encode_buffer.resize(encoded_size);
×
177
    util::base64_encode(buf, encode_buffer);
×
178

179
    return encode_buffer;
×
180
}
×
181

182
// Server protocol
183

184
void ServerProtocol::make_ident_message(int protocol_version, OutputBuffer& out, session_ident_type session_ident,
185
                                        file_ident_type client_file_ident, salt_type client_file_ident_salt)
186
{
1,346✔
187
    static_cast<void>(protocol_version);
1,346✔
188
    out << "ident " << session_ident << " " << client_file_ident << " " << client_file_ident_salt << "\n"; // Throws
1,346✔
189
}
1,346✔
190

191
void ServerProtocol::make_alloc_message(OutputBuffer& out, session_ident_type session_ident,
192
                                        file_ident_type file_ident)
193
{
×
194
    out << "alloc " << session_ident << " " << file_ident << "\n"; // Throws
×
195
}
×
196

197

198
/// insert_single_changeset_download_message() inserts a single changeset and
199
/// the associated meta data into the output buffer.
200
///
201
/// It is the functions responsibility to make sure that the buffer has
202
/// capacity to hold the inserted data.
203
///
204
/// The message format for the single changeset is <server_version>
205
/// <client_version> <timestamp> <client_file_ident> <changeset size>
206
/// <changeset>
207
void ServerProtocol::insert_single_changeset_download_message(OutputBuffer& out, const ChangesetInfo& changeset_info,
208
                                                              util::Logger& logger)
209
{
43,230✔
210
    const sync::HistoryEntry& entry = changeset_info.entry;
43,230✔
211

212
    out << changeset_info.server_version << " " << changeset_info.client_version << " " << entry.origin_timestamp
43,230✔
213
        << " " << entry.origin_file_ident << " " << changeset_info.original_size << " " << entry.changeset.size()
43,230✔
214
        << " ";
43,230✔
215
    entry.changeset.write_to(out);
43,230✔
216

217
    if (logger.would_log(util::Logger::Level::trace)) {
43,230✔
218
        logger.trace(util::LogCategory::changeset,
×
219
                     "DOWNLOAD: insert single changeset (server_version=%1, "
×
UNCOV
220
                     "client_version=%2, timestamp=%3, client_file_ident=%4, "
×
221
                     "original_changeset_size=%5, changeset_size=%6, changeset='%7').",
×
222
                     changeset_info.server_version, changeset_info.client_version, entry.origin_timestamp,
×
223
                     entry.origin_file_ident, changeset_info.original_size, entry.changeset.size(),
×
224
                     _impl::clamped_hex_dump(entry.changeset.get_first_chunk())); // Throws
×
225
    }
×
226
}
43,230✔
227

228

229
void ServerProtocol::make_download_message(int protocol_version, OutputBuffer& out, session_ident_type session_ident,
230
                                           version_type download_server_version, version_type download_client_version,
231
                                           version_type latest_server_version, salt_type latest_server_version_salt,
232
                                           version_type upload_client_version, version_type upload_server_version,
233
                                           std::uint_fast64_t downloadable_bytes, std::size_t num_changesets,
234
                                           const char* body, std::size_t uncompressed_body_size,
235
                                           std::size_t compressed_body_size, bool body_is_compressed,
236
                                           util::Logger& logger)
237
{
41,468✔
238
    static_cast<void>(protocol_version);
41,468✔
239
    // The header of the download message.
240
    out << "download " << session_ident << " " << download_server_version << " " << download_client_version << " "
41,468✔
241
        << latest_server_version << " " << latest_server_version_salt << " " << upload_client_version << " "
41,468✔
242
        << upload_server_version << " " << downloadable_bytes << " " << int(body_is_compressed) << " "
41,468✔
243
        << uncompressed_body_size << " " << compressed_body_size << "\n"; // Throws
41,468✔
244

245
    std::size_t body_size = (body_is_compressed ? compressed_body_size : uncompressed_body_size);
41,468✔
246
    out.write(body, body_size);
41,468✔
247

248
    logger.detail(util::LogCategory::changeset,
41,468✔
249
                  "Sending: DOWNLOAD(download_server_version=%1, download_client_version=%2, "
41,468✔
250
                  "latest_server_version=%3, latest_server_version_salt=%4, "
41,468✔
251
                  "upload_client_version=%5, upload_server_version=%6, "
41,468✔
252
                  "num_changesets=%7, is_body_compressed=%8, body_size=%9, "
41,468✔
253
                  "compressed_body_size=%10)",
41,468✔
254
                  download_server_version, download_client_version, latest_server_version, latest_server_version_salt,
41,468✔
255
                  upload_client_version, upload_server_version, num_changesets, body_is_compressed,
41,468✔
256
                  uncompressed_body_size, compressed_body_size); // Throws
41,468✔
257
}
41,468✔
258

259

260
void ServerProtocol::make_unbound_message(OutputBuffer& out, session_ident_type session_ident)
261
{
1,810✔
262
    out << "unbound " << session_ident << "\n"; // Throws
1,810✔
263
}
1,810✔
264

265

266
void ServerProtocol::make_mark_message(OutputBuffer& out, session_ident_type session_ident,
267
                                       request_ident_type request_ident)
268
{
11,982✔
269
    out << "mark " << session_ident << " " << request_ident << "\n"; // Throws
11,982✔
270
    REALM_ASSERT(!out.fail());
11,982✔
271
}
11,982✔
272

273

274
void ServerProtocol::make_error_message(int protocol_version, OutputBuffer& out, sync::ProtocolError error_code,
275
                                        const char* message, std::size_t message_size, bool try_again,
276
                                        session_ident_type session_ident)
277
{
92✔
278
    static_cast<void>(protocol_version);
92✔
279
    sync::ProtocolError error_code_2 = error_code;
92✔
280
    out << "error " << int(error_code_2) << " " << message_size << " " << int(try_again) << " " << session_ident
92✔
281
        << "\n";                      // Throws
92✔
282
    out.write(message, message_size); // Throws
92✔
283
}
92✔
284

285

286
void ServerProtocol::make_pong(OutputBuffer& out, milliseconds_type timestamp)
287
{
88✔
288
    out << "pong " << timestamp << "\n"; // Throws
88✔
289
}
88✔
290

291
void ServerProtocol::make_log_message(OutputBuffer& out, util::Logger::Level level, std::string message,
292
                                      session_ident_type sess_id, std::optional<std::string> co_id)
293
{
5,920✔
294
    nlohmann::json log_msg_json;
5,920✔
295
    log_msg_json["level"] = util::Logger::level_to_string(level);
5,920✔
296
    log_msg_json["msg"] = message;
5,920✔
297
    if (co_id) {
5,920✔
298
        log_msg_json["co_id"] = *co_id;
1,978✔
299
    }
1,978✔
300
    std::string json_data_stg = log_msg_json.dump();
5,920✔
301
    out << "log_message " << sess_id << " " << json_data_stg.length() << "\n" << json_data_stg;
5,920✔
302
}
5,920✔
303

304
std::string make_authorization_header(const std::string& signed_user_token)
UNCOV
305
{
×
UNCOV
306
    return "Bearer " + signed_user_token;
×
UNCOV
307
}
×
308

309

310
util::Optional<StringData> parse_authorization_header(const std::string& authorization_header)
UNCOV
311
{
×
UNCOV
312
    StringData prefix = "Bearer ";
×
313
    // Token contains at least three characters. Stricter checks are possible, but do
314
    // not belong here.
315
    if (authorization_header.size() < prefix.size() + 4)
×
UNCOV
316
        return util::none;
×
317

318
    if (authorization_header.compare(0, prefix.size(), prefix) != 0)
×
319
        return util::none;
×
320

321
    std::size_t token_size = authorization_header.size() - prefix.size();
×
322
    return StringData{authorization_header.data() + prefix.size(), token_size};
×
UNCOV
323
}
×
324

325
} // namespace realm::_impl
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

© 2025 Coveralls, Inc