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

realm / realm-core / jorgen.edelbo_402

21 Aug 2024 11:10AM UTC coverage: 91.054% (-0.03%) from 91.085%
jorgen.edelbo_402

Pull #7803

Evergreen

jedelbo
Small fix to Table::typed_write

When writing the realm to a new file from a write transaction,
the Table may be COW so that the top ref is changed. So don't
use the ref that is present in the group when the operation starts.
Pull Request #7803: Feature/string compression

103494 of 181580 branches covered (57.0%)

1929 of 1999 new or added lines in 46 files covered. (96.5%)

695 existing lines in 51 files now uncovered.

220142 of 241772 relevant lines covered (91.05%)

7344461.76 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
{
7,334✔
16
    static_cast<void>(protocol_version);
7,334✔
17
    out << "bind " << session_ident << " " << server_path.size() << " " << signed_user_token.size() << " "
7,334✔
18
        << int(need_client_file_ident) << " " << int(is_subserver) << "\n"; // Throws
7,334✔
19
    REALM_ASSERT(!out.fail());
7,334✔
20

21
    out.write(server_path.data(), server_path.size());             // Throws
7,334✔
22
    out.write(signed_user_token.data(), signed_user_token.size()); // Throws
7,334✔
23
}
7,334✔
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,896✔
29
    static_cast<void>(protocol_version);
1,896✔
30
    std::string json_data_stg;
1,896✔
31
    // Protocol version v8 and above accepts stringified json_data for the first data argument
32
    if (!json_data.empty()) {
1,896✔
33
        json_data_stg = json_data.dump();
1,892✔
34
    }
1,892✔
35

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

40
    out.write(json_data_stg.data(), json_data_stg.size());         // Throws
1,896✔
41
    out.write(signed_user_token.data(), signed_user_token.size()); // Throws
1,896✔
42
}
1,896✔
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,996✔
47
    out << "ident " << session_ident << " " << client_file_ident.ident << " " << client_file_ident.salt << " "
5,996✔
48
        << progress.download.server_version << " " << progress.download.last_integrated_client_version << " "
5,996✔
49
        << progress.latest_server_version.version << " " << progress.latest_server_version.salt << "\n"; // Throws
5,996✔
50
    REALM_ASSERT(!out.fail());
5,996✔
51
}
5,996✔
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,382✔
68
    out << "query " << session << " " << version << " " << query_body.size() << "\n" << query_body; // throws
1,382✔
69
    REALM_ASSERT(!out.fail());
1,382✔
70
}
1,382✔
71

72
void ClientProtocol::make_json_error_message(OutputBuffer& out, session_ident_type session, int error_code,
73
                                             std::string_view error_body)
74
{
34✔
75
    out << "json_error " << error_code << " " << error_body.size() << " " << session << "\n" << error_body; // throws
34✔
76
    REALM_ASSERT(!out.fail());
34✔
77
}
34✔
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,252✔
90
    , m_compression_buffer{compression_buffer}
28,252✔
91
    , m_compress_memory_arena{compress_memory_arena}
28,252✔
92
{
56,302✔
93
    m_body_buffer.reset();
56,302✔
94
}
56,302✔
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,208✔
101
    m_body_buffer << client_version << " " << server_version << " " << origin_timestamp << " " << origin_file_ident
43,208✔
102
                  << " " << changeset.size() << " "; // Throws
43,208✔
103
    changeset.write_to(m_body_buffer);               // Throws
43,208✔
104
    REALM_ASSERT(!m_body_buffer.fail());
43,208✔
105

106
    ++m_num_changesets;
43,208✔
107
}
43,208✔
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
{
56,302✔
115
    static_cast<void>(protocol_version);
56,302✔
116
    BinaryData body = {m_body_buffer.data(), std::size_t(m_body_buffer.size())};
56,302✔
117

118
    constexpr std::size_t g_max_uncompressed = 1024;
56,302✔
119

120
    bool is_body_compressed = false;
56,302✔
121
    if (body.size() > g_max_uncompressed) {
56,302✔
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;
56,302✔
129

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

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

141
    REALM_ASSERT(!out.fail());
56,302✔
142
}
56,302✔
143

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

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

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

162

163
void ClientProtocol::make_ping(OutputBuffer& out, milliseconds_type timestamp, milliseconds_type rtt)
164
{
188✔
165
    out << "ping " << timestamp << " " << rtt << "\n"; // Throws
188✔
166
}
188✔
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,340✔
187
    static_cast<void>(protocol_version);
1,340✔
188
    out << "ident " << session_ident << " " << client_file_ident << " " << client_file_ident_salt << "\n"; // Throws
1,340✔
189
}
1,340✔
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
{
42,786✔
210
    const sync::HistoryEntry& entry = changeset_info.entry;
42,786✔
211

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

217
    if (logger.would_log(util::Logger::Level::trace)) {
42,786✔
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
}
42,786✔
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
{
40,832✔
238
    static_cast<void>(protocol_version);
40,832✔
239
    // The header of the download message.
240
    out << "download " << session_ident << " " << download_server_version << " " << download_client_version << " "
40,832✔
241
        << latest_server_version << " " << latest_server_version_salt << " " << upload_client_version << " "
40,832✔
242
        << upload_server_version << " " << downloadable_bytes << " " << int(body_is_compressed) << " "
40,832✔
243
        << uncompressed_body_size << " " << compressed_body_size << "\n"; // Throws
40,832✔
244

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

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

259

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

265

266
void ServerProtocol::make_mark_message(OutputBuffer& out, session_ident_type session_ident,
267
                                       request_ident_type request_ident)
268
{
11,990✔
269
    out << "mark " << session_ident << " " << request_ident << "\n"; // Throws
11,990✔
270
    REALM_ASSERT(!out.fail());
11,990✔
271
}
11,990✔
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
{
96✔
278
    static_cast<void>(protocol_version);
96✔
279
    sync::ProtocolError error_code_2 = error_code;
96✔
280
    out << "error " << int(error_code_2) << " " << message_size << " " << int(try_again) << " " << session_ident
96✔
281
        << "\n";                      // Throws
96✔
282
    out.write(message, message_size); // Throws
96✔
283
}
96✔
284

285

286
void ServerProtocol::make_pong(OutputBuffer& out, milliseconds_type timestamp)
287
{
114✔
288
    out << "pong " << timestamp << "\n"; // Throws
114✔
289
}
114✔
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
{
6,106✔
294
    nlohmann::json log_msg_json;
6,106✔
295
    log_msg_json["level"] = util::Logger::level_to_string(level);
6,106✔
296
    log_msg_json["msg"] = message;
6,106✔
297
    if (co_id) {
6,106✔
298
        log_msg_json["co_id"] = *co_id;
2,032✔
299
    }
2,032✔
300
    std::string json_data_stg = log_msg_json.dump();
6,106✔
301
    out << "log_message " << sess_id << " " << json_data_stg.length() << "\n" << json_data_stg;
6,106✔
302
}
6,106✔
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