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

realm / realm-core / 2604

05 Sep 2024 08:32AM UTC coverage: 91.108% (-0.04%) from 91.149%
2604

push

Evergreen

jedelbo
Add failing test

102796 of 181478 branches covered (56.64%)

8 of 8 new or added lines in 1 file covered. (100.0%)

122 existing lines in 17 files now uncovered.

217184 of 238381 relevant lines covered (91.11%)

5669407.07 hits per line

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

96.63
/src/realm/object-store/sync/app_utils.cpp
1
////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2020 Realm Inc.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or utilied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
//
17
////////////////////////////////////////////////////////////////////////////
18

19
#include <realm/object-store/sync/app_utils.hpp>
20

21
#include <realm/object-store/sync/generic_network_transport.hpp>
22
#include <realm/sync/network/http.hpp>
23
#include <realm/util/uri.hpp>
24

25
#include <external/json/json.hpp>
26

27
#include <algorithm>
28

29
namespace realm::app {
30

31
const std::pair<const std::string, std::string>*
32
AppUtils::find_header(const std::string& key_name, const std::map<std::string, std::string>& search_map)
33
{
37,633✔
34
    for (auto&& current : search_map) {
43,390✔
35
#ifdef _MSC_VER
36
        if (key_name.size() == current.first.size() && _stricmp(key_name.c_str(), current.first.c_str()) == 0) {
37
            return &current;
38
        }
39
#else
40
        if (key_name.size() == current.first.size() && strcasecmp(key_name.c_str(), current.first.c_str()) == 0) {
43,390✔
41
            return &current;
18,109✔
42
        }
18,109✔
43
#endif
43,390✔
44
    }
43,390✔
45
    return nullptr;
19,524✔
46
}
37,633✔
47

48
bool AppUtils::is_success_status_code(int status_code)
49
{
26,033✔
50
    return status_code == 0 || (status_code < 300 && status_code >= 200);
26,033✔
51
}
26,033✔
52

53
// Create a Response object with the given client error, message and optional http status code
54
Response AppUtils::make_clienterror_response(ErrorCodes::Error code, const std::string_view message,
55
                                             std::optional<int> http_status)
UNCOV
56
{
×
UNCOV
57
    return Response{http_status ? *http_status : 0, 0, {}, std::string(message), code};
×
UNCOV
58
}
×
59

60
#if REALM_APP_SERVICES
61
std::optional<AppError> AppUtils::check_for_errors(const Response& response)
62
{
25,823✔
63
    std::string error_msg;
25,823✔
64
    bool http_status_code_is_fatal = !AppUtils::is_success_status_code(response.http_status_code);
25,823✔
65

66
    try {
25,823✔
67
        auto ct = find_header("content-type", response.headers);
25,823✔
68
        if (ct && ct->second == "application/json" && !response.body.empty()) {
25,823✔
69
            auto body = nlohmann::json::parse(response.body);
6,299✔
70
            auto message = body.find("error");
6,299✔
71
            auto link = body.find("link");
6,299✔
72
            std::string parsed_link = link == body.end() ? "" : link->get<std::string>();
6,299✔
73

74
            if (auto error_code = body.find("error_code");
6,299✔
75
                error_code != body.end() && !error_code->get<std::string>().empty()) {
6,299✔
76
                auto server_error = error_code->get<std::string>();
440✔
77
                auto code = ErrorCodes::from_string(server_error);
440✔
78
                auto error_stg = message != body.end() ? message->get<std::string>() : "no error message";
440✔
79
                // If the err_code is not found or not an app error, create a generic AppError with
80
                // ErrorCodes::AppServerError "error_code" value from server response will be in the `server_error`
81
                // property
82
                if (code == ErrorCodes::UnknownError ||
440✔
83
                    !ErrorCodes::error_categories(code).test(ErrorCategory::app_error)) {
440✔
84
                    code = ErrorCodes::AppServerError;
188✔
85
                }
188✔
86
                return AppError(code, std::move(error_stg), std::move(parsed_link), response.http_status_code,
440✔
87
                                std::move(server_error));
440✔
88
            }
440✔
89
            // If the response only contains an error string, create a generic AppError with
90
            // ErrorCodes::AppUnknownError
91
            else if (message != body.end()) {
5,859✔
92
                return AppError(ErrorCodes::AppUnknownError, message->get<std::string>(), std::move(parsed_link),
52✔
93
                                response.http_status_code);
52✔
94
            }
52✔
95
        }
6,299✔
96
    }
25,823✔
97
    catch (const std::exception&) {
25,823✔
98
        // ignore parse errors from our attempt to read the error from json
99
    }
2✔
100

101
    if (response.client_error_code) {
25,331✔
102
        error_msg = response.body.empty() ? "client error code value considered fatal" : response.body;
4✔
103
        return AppError(*(response.client_error_code), error_msg, {}, response.http_status_code);
4✔
104
    }
4✔
105

106
    if (response.custom_status_code != 0) {
25,327✔
107
        error_msg = response.body.empty() ? "non-zero custom status code considered fatal" : response.body;
32✔
108
        return AppError(ErrorCodes::CustomError, error_msg, {}, response.custom_status_code);
32✔
109
    }
32✔
110

111
    if (http_status_code_is_fatal) {
25,295✔
112
        error_msg = response.body.empty() ? "http error code considered fatal"
82✔
113
                                          : "http error code considered fatal: " + response.body;
82✔
114
        return AppError(ErrorCodes::HTTPError, error_msg, {}, response.http_status_code);
82✔
115
    }
82✔
116

117
    return std::nullopt;
25,213✔
118
}
25,295✔
119

120
// Convert an AppError object into a Response object
121
Response AppUtils::make_apperror_response(const AppError& error)
122
{
378✔
123
    if (!error.server_error.empty() || error.code() == ErrorCodes::AppUnknownError) {
378✔
124
        auto body = nlohmann::json();
328✔
125
        body["error"] = error.reason();
328✔
126
        if (!error.server_error.empty()) {
328✔
127
            body["error_code"] = error.server_error;
324✔
128
        }
324✔
129
        if (!error.link_to_server_logs.empty()) {
328✔
130
            body["link"] = error.link_to_server_logs;
326✔
131
        }
326✔
132
        return {error.additional_status_code.value_or(0), 0, {{"content-type", "application/json"}}, body.dump()};
328✔
133
    }
328✔
134

135
    if (ErrorCodes::error_categories(error.code()).test(ErrorCategory::http_error)) {
50✔
136
        std::string message;
32✔
137
        // Try to extract the original body from the reason code
138
        static const char* match = "http error code considered fatal: ";
32✔
139
        if (auto pos = error.reason().find(match); pos != std::string::npos) {
32✔
140
            message = error.reason().substr(pos + std::char_traits<char>::length(match));
28✔
141
            // Remove the text added by AppError
142
            pos = message.find_last_of(".");
28✔
143
            if (pos != std::string::npos) {
28✔
144
                message.erase(pos);
28✔
145
            }
28✔
146
        }
28✔
147
        // Otherwise, body was originally empty
148
        return {error.additional_status_code.value_or(0), 0, {}, message};
32✔
149
    }
32✔
150
    if (ErrorCodes::error_categories(error.code()).test(ErrorCategory::custom_error)) {
18✔
151
        return {0, error.additional_status_code.value_or(0), {}, std::string(error.reason())};
14✔
152
    }
14✔
153

154
    // For other cases, put the error code in client_error_code field (client error or otherwise)
155
    return {error.additional_status_code.value_or(0), 0, {}, std::string(error.reason()), error.code()};
4✔
156
}
18✔
157

158
#endif // REALM_APP_SERVICES
159

160
} // namespace realm::app
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