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

mendersoftware / mender-mcu / 1559779716

25 Nov 2024 06:45PM UTC coverage: 9.39% (-0.03%) from 9.418%
1559779716

push

gitlab-ci

danielskinstad
fix: fail deployment when it's aborted

Changelog: Title
Ticket: MEN-7693

Signed-off-by: Daniel Skinstad Drabitzius <daniel.drabitzius@northern.tech>

0 of 16 new or added lines in 3 files covered. (0.0%)

472 existing lines in 5 files now uncovered.

251 of 2673 relevant lines covered (9.39%)

0.67 hits per line

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

0.0
/platform/net/generic/curl/src/mender-http.c
1
/**
2
 * @file      mender-http.c
3
 * @brief     Mender HTTP interface for curl platform, requires libcurl >= 7.80.0
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19

20
#define _GNU_SOURCE // asprintf
21
#include <curl/curl.h>
22
#include "mender-http.h"
23
#include "mender-log.h"
24
#include "mender-utils.h"
25

26
/**
27
 * @brief HTTP User-Agent
28
 */
29
#ifdef MENDER_CLIENT_VERSION
30
#define MENDER_HTTP_USER_AGENT "mender-mcu-client/" MENDER_CLIENT_VERSION " (mender-http) curl/" LIBCURL_VERSION
31
#else
32
#define MENDER_HTTP_USER_AGENT "mender-mcu-client (mender-http) curl/" LIBCURL_VERSION
33
#endif /* MENDER_CLIENT_VERSION */
34

35
/* CURL_MAX_WRITE_SIZE is the maximum amount of data curl passes to the
36
   WRITEFUNCTION (see below) according to man:CURLOPT_WRITEFUNCTION(3). */
37
const size_t mender_http_recv_buf_length = CURL_MAX_WRITE_SIZE;
38

39
/**
40
 * @brief User data
41
 */
42
typedef struct {
43
    mender_err_t (*callback)(mender_http_client_event_t, void *, size_t, void *); /**< Callback invoked on HTTP events */
44
    void *params;                                                                 /**< Parameters passed to the callback, NULL if not used */
45
} mender_http_curl_user_data_t;
46

47
/**
48
 * @brief Mender HTTP configuration
49
 */
50
static mender_http_config_t http_config;
51

52
/**
53
 * @brief HTTP PREREQ callback, used to inform the client is connected to the server
54
 * @param params User data
55
 * @param conn_primary_ip Primary IP of the remote server 
56
 * @param conn_local_ip Originating IP of the connection
57
 * @param conn_primary_port Primary port number on the remote server
58
 * @param conn_local_port Originating port number of the connection
59
 * @return CURL_PREREQFUNC_OK if the function succeeds, CURL_PREREQFUNC_ABORT otherwise
60
 */
61
static int http_prereq_callback(void *params, char *conn_primary_ip, char *conn_local_ip, int conn_primary_port, int conn_local_port);
62

63
/**
64
 * @brief HTTP write callback, used to retrieve data from the server
65
 * @param data Data from the server
66
 * @param size Size of the data
67
 * @param nmemb Number of element
68
 * @param params User data
69
 * @return Real size of data if the function succeeds, -1 otherwise
70
 */
71
static size_t http_write_callback(char *data, size_t size, size_t nmemb, void *params);
72

73
/**
74
 * @brief HTTP PREREQ callback for artifact
75
 * @see http_prereq_callback()
76
 */
77
static int artifact_prereq_callback(void *user_data, char *conn_primary_ip, char *conn_local_ip, int conn_primary_port, int conn_local_port);
78

79
/**
80
 * @brief HTTP write callback for artifact
81
 * @see http_write_callback()
82
 */
83
static size_t artifact_write_callback(char *data, size_t size, size_t nmemb, void *user_data);
84

85
mender_err_t
86
mender_http_init(mender_http_config_t *config) {
×
87

88
    assert(NULL != config);
×
89
    assert(NULL != config->host);
×
90

91
    /* Save configuration */
92
    memcpy(&http_config, config, sizeof(mender_http_config_t));
×
93

94
    /* Initialization of curl */
95
    curl_global_init(CURL_GLOBAL_DEFAULT);
×
96

97
    return MENDER_OK;
×
98
}
99

100
mender_err_t
101
mender_http_perform(char                *jwt,
×
102
                    char                *path,
103
                    mender_http_method_t method,
104
                    char                *payload,
105
                    char                *signature,
106
                    mender_err_t (*callback)(mender_http_client_event_t, void *, size_t, void *),
107
                    void *params,
108
                    int  *status) {
109

110
    assert(NULL != path);
×
111
    assert(NULL != callback);
×
112
    assert(NULL != status);
×
113
    CURLcode           err;
114
    mender_err_t       ret             = MENDER_OK;
×
115
    CURL              *curl            = NULL;
×
116
    char              *url             = NULL;
×
117
    char              *bearer          = NULL;
×
118
    char              *x_men_signature = NULL;
×
119
    struct curl_slist *headers         = NULL;
×
120

121
    /* Compute URL if required */
122
    if (!mender_utils_strbeginswith(path, "http://") && !mender_utils_strbeginswith(path, "https://")) {
×
123
        if (-1 == asprintf(&url, "%s%s", http_config.host, path)) {
×
124
            mender_log_error("Unable to allocate memory for URL");
×
125
            ret = MENDER_FAIL;
×
126
            goto END;
×
127
        }
128
    }
129

130
    /* Initialization of the client */
131
    if (NULL == (curl = curl_easy_init())) {
×
132
        mender_log_error("Unable to allocate memory");
×
133
        ret = MENDER_FAIL;
×
134
        goto END;
×
135
    }
136

137
    /* Configuration of the client */
138
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_URL, (NULL != url) ? url : path))) {
×
139
        mender_log_error("Unable to set HTTP URL: %s", curl_easy_strerror(err));
×
140
        ret = MENDER_FAIL;
×
141
        goto END;
×
142
    }
143
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_USERAGENT, MENDER_HTTP_USER_AGENT))) {
×
144
        mender_log_error("Unable to set HTTP User-Agent: %s", curl_easy_strerror(err));
×
145
        ret = MENDER_FAIL;
×
146
        goto END;
×
147
    }
148
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2))) {
×
149
        mender_log_error("Unable to set TLSv1.2: %s", curl_easy_strerror(err));
×
150
        ret = MENDER_FAIL;
×
151
        goto END;
×
152
    }
153
    mender_http_curl_user_data_t user_data = { .callback = callback, .params = params };
×
154
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, &http_prereq_callback))) {
×
155
        mender_log_error("Unable to set HTTP PREREQ function: %s", curl_easy_strerror(err));
×
156
        ret = MENDER_FAIL;
×
157
        goto END;
×
158
    }
159
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_PREREQDATA, &user_data))) {
×
160
        mender_log_error("Unable to set HTTP PREREQ data: %s", curl_easy_strerror(err));
×
161
        ret = MENDER_FAIL;
×
162
        goto END;
×
163
    }
164
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &http_write_callback))) {
×
165
        mender_log_error("Unable to set HTTP write function: %s", curl_easy_strerror(err));
×
166
        ret = MENDER_FAIL;
×
167
        goto END;
×
168
    }
169
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &user_data))) {
×
170
        mender_log_error("Unable to set HTTP write data: %s", curl_easy_strerror(err));
×
171
        ret = MENDER_FAIL;
×
172
        goto END;
×
173
    }
174
    if (NULL != jwt) {
×
175
        size_t str_length = strlen("Authorization: Bearer ") + strlen(jwt) + 1;
×
176
        if (NULL == (bearer = (char *)malloc(str_length))) {
×
177
            mender_log_error("Unable to allocate memory");
×
178
            ret = MENDER_FAIL;
×
179
            goto END;
×
180
        }
181
        snprintf(bearer, str_length, "Authorization: Bearer %s", jwt);
×
182
        headers = curl_slist_append(headers, bearer);
×
183
    }
184
    if (NULL != signature) {
×
185
        size_t str_length = strlen("X-MEN-Signature: ") + strlen(signature) + 1;
×
186
        if (NULL == (x_men_signature = (char *)malloc(str_length))) {
×
187
            mender_log_error("Unable to allocate memory");
×
188
            ret = MENDER_FAIL;
×
189
            goto END;
×
190
        }
191
        snprintf(x_men_signature, str_length, "X-MEN-Signature: %s", signature);
×
192
        headers = curl_slist_append(headers, x_men_signature);
×
193
    }
194
    if (NULL != payload) {
×
195
        headers = curl_slist_append(headers, "Content-Type: application/json");
×
196
    }
197
    if (NULL != headers) {
×
198
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
×
199
    }
200

201
    /* Write data if payload is defined */
202
    if (NULL != payload) {
×
203
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);
×
204
        if (MENDER_HTTP_PUT == method) {
×
205
            curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
×
206
        }
207
    }
208

209
    /* Perform request */
210
    if (CURLE_OK != (err = curl_easy_perform(curl))) {
×
211
        mender_log_error("Unable to perform HTTP request: %s", curl_easy_strerror(err));
×
212
        callback(MENDER_HTTP_EVENT_ERROR, NULL, 0, params);
×
213
        ret = MENDER_FAIL;
×
214
        goto END;
×
215
    }
216

217
    /* Read HTTP status code */
218
    long response_code;
219
    if (CURLE_OK != (err = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code))) {
×
220
        mender_log_error("Unable to read HTTP response code: %s", curl_easy_strerror(err));
×
221
        ret = MENDER_FAIL;
×
222
        goto END;
×
223
    }
224
    *status = (int)response_code;
×
225
    if (MENDER_OK != (ret = callback(MENDER_HTTP_EVENT_DISCONNECTED, NULL, 0, params))) {
×
226
        mender_log_error("An error occurred when processing HTTP disconnection");
×
227
        goto END;
×
228
    }
229

230
END:
×
231

232
    /* Release memory */
233
    curl_easy_cleanup(curl);
×
234
    curl_slist_free_all(headers);
×
235
    free(x_men_signature);
×
236
    free(bearer);
×
237
    free(url);
×
238

239
    return ret;
×
240
}
241

242
mender_err_t
243
mender_http_artifact_download(const char *uri, mender_artifact_download_data_t *dl_data, int *status) {
×
244
    assert(NULL != uri);
×
245
    assert(NULL != dl_data);
×
246
    assert(NULL != status);
×
247

248
    CURLcode           err;
249
    mender_err_t       ret     = MENDER_OK;
×
250
    CURL              *curl    = NULL;
×
251
    char              *url     = NULL;
×
252
    struct curl_slist *headers = NULL;
×
253

254
    /* Compute URL if required */
255
    if (!mender_utils_strbeginswith(uri, "http://") && !mender_utils_strbeginswith(uri, "https://")) {
×
256
        if (-1 == asprintf(&url, "%s%s", http_config.host, uri)) {
×
257
            mender_log_error("Unable to allocate memory");
×
258
            ret = MENDER_FAIL;
×
259
            goto END;
×
260
        }
261
    }
262

263
    /* Initialization of the client */
264
    if (NULL == (curl = curl_easy_init())) {
×
265
        mender_log_error("Unable to allocate memory");
×
266
        ret = MENDER_FAIL;
×
267
        goto END;
×
268
    }
269

270
    /* Configuration of the client */
271
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_URL, (NULL != url) ? url : uri))) {
×
272
        mender_log_error("Unable to set HTTP URL: %s", curl_easy_strerror(err));
×
273
        ret = MENDER_FAIL;
×
274
        goto END;
×
275
    }
276

277
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2))) {
×
278
        mender_log_error("Unable to set TLSv1.2: %s", curl_easy_strerror(err));
×
279
        ret = MENDER_FAIL;
×
280
        goto END;
×
281
    }
282

283
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, &artifact_prereq_callback))) {
×
284
        mender_log_error("Unable to set HTTP PREREQ function: %s", curl_easy_strerror(err));
×
285
        ret = MENDER_FAIL;
×
286
        goto END;
×
287
    }
288
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_PREREQDATA, dl_data))) {
×
289
        mender_log_error("Unable to set HTTP PREREQ data: %s", curl_easy_strerror(err));
×
290
        ret = MENDER_FAIL;
×
291
        goto END;
×
292
    }
293
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &artifact_write_callback))) {
×
294
        mender_log_error("Unable to set HTTP write function: %s", curl_easy_strerror(err));
×
295
        ret = MENDER_FAIL;
×
296
        goto END;
×
297
    }
298
    if (CURLE_OK != (err = curl_easy_setopt(curl, CURLOPT_WRITEDATA, dl_data))) {
×
299
        mender_log_error("Unable to set HTTP write data: %s", curl_easy_strerror(err));
×
300
        ret = MENDER_FAIL;
×
301
        goto END;
×
302
    }
303

304
    /* Perform request */
305
    if (CURLE_OK != (err = curl_easy_perform(curl))) {
×
306
        mender_log_error("Unable to perform HTTP request: %s", curl_easy_strerror(err));
×
307
        dl_data->artifact_download_callback(MENDER_HTTP_EVENT_ERROR, NULL, 0, dl_data);
×
308
        ret = MENDER_FAIL;
×
309
        goto END;
×
310
    }
311

312
    /* Artifact download failed*/
UNCOV
313
    if (MENDER_OK != dl_data->ret) {
×
314
        ret = MENDER_FAIL;
×
315
        goto END;
×
316
    }
317

318
    /* Read HTTP status code */
319
    long response_code;
320
    if (CURLE_OK != (err = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code))) {
×
321
        mender_log_error("Unable to read HTTP response code: %s", curl_easy_strerror(err));
×
322
        ret = MENDER_FAIL;
×
UNCOV
323
        goto END;
×
324
    }
325
    *status = (int)response_code;
×
UNCOV
326
    if (MENDER_OK != (ret = dl_data->artifact_download_callback(MENDER_HTTP_EVENT_DISCONNECTED, NULL, 0, dl_data))) {
×
UNCOV
327
        mender_log_error("An error occurred when processing disconnection in artifact download");
×
328
        goto END;
×
329
    }
330

UNCOV
331
END:
×
332

333
    /* Release memory */
UNCOV
334
    curl_easy_cleanup(curl);
×
UNCOV
335
    curl_slist_free_all(headers);
×
336
    free(url);
×
337

UNCOV
338
    return ret;
×
339
}
340

341
mender_err_t
UNCOV
342
mender_http_exit(void) {
×
343

344
    /* Cleaning */
345
    curl_global_cleanup();
×
346

UNCOV
347
    return MENDER_OK;
×
348
}
349

350
static int
351
http_prereq_callback(void                   *params,
×
352
                     MENDER_ARG_UNUSED char *conn_primary_ip,
353
                     MENDER_ARG_UNUSED char *conn_local_ip,
354
                     MENDER_ARG_UNUSED int   conn_primary_port,
355
                     MENDER_ARG_UNUSED int   conn_local_port) {
356

357
    assert(NULL != params);
×
UNCOV
358
    mender_http_curl_user_data_t *user_data = (mender_http_curl_user_data_t *)params;
×
359

360
    /* Invoke callback */
UNCOV
361
    if (MENDER_OK != user_data->callback(MENDER_HTTP_EVENT_CONNECTED, NULL, 0, user_data->params)) {
×
UNCOV
362
        mender_log_error("An error occurred when processing HTTP connection");
×
UNCOV
363
        return CURL_PREREQFUNC_ABORT;
×
364
    }
365

366
    return CURL_PREREQFUNC_OK;
×
367
}
368

369
static size_t
UNCOV
370
http_write_callback(char *data, size_t size, size_t nmemb, void *params) {
×
371

372
    assert(NULL != params);
×
373
    mender_http_curl_user_data_t *user_data = (mender_http_curl_user_data_t *)params;
×
374
    size_t                        realsize  = size * nmemb;
×
375

376
    /* Transmit data received to the upper layer */
UNCOV
377
    if (realsize > 0) {
×
378
        if (MENDER_OK != user_data->callback(MENDER_HTTP_EVENT_DATA_RECEIVED, (void *)data, realsize, user_data->params)) {
×
UNCOV
379
            mender_log_error("An error occurred, stop reading data");
×
UNCOV
380
            return -1;
×
381
        }
382
    }
383

UNCOV
384
    return realsize;
×
385
}
386

387
static int
UNCOV
388
artifact_prereq_callback(void                   *user_data,
×
389
                         MENDER_ARG_UNUSED char *conn_primary_ip,
390
                         MENDER_ARG_UNUSED char *conn_local_ip,
391
                         MENDER_ARG_UNUSED int   conn_primary_port,
392
                         MENDER_ARG_UNUSED int   conn_local_port) {
393
    assert(NULL != user_data);
×
394

UNCOV
395
    mender_artifact_download_data_t *dl_data = user_data;
×
396

397
    /* Invoke callback */
UNCOV
398
    if (MENDER_OK != dl_data->artifact_download_callback(MENDER_HTTP_EVENT_CONNECTED, NULL, 0, dl_data)) {
×
UNCOV
399
        mender_log_error("An error occurred when processing HTTP connection on artifact download");
×
UNCOV
400
        return CURL_PREREQFUNC_ABORT;
×
401
    }
402

UNCOV
403
    return CURL_PREREQFUNC_OK;
×
404
}
405

406
static size_t
UNCOV
407
artifact_write_callback(char *data, size_t size, size_t nmemb, void *user_data) {
×
408
    assert(NULL != user_data);
×
409

410
    mender_artifact_download_data_t *dl_data  = user_data;
×
411
    size_t                           realsize = size * nmemb;
×
412

413
    /* Transmit data received to the upper layer */
UNCOV
414
    if (realsize > 0) {
×
415
        if (MENDER_OK != dl_data->artifact_download_callback(MENDER_HTTP_EVENT_DATA_RECEIVED, (void *)data, realsize, dl_data)) {
×
UNCOV
416
            mender_log_error("An error occurred, stop reading data");
×
UNCOV
417
            return -1;
×
418
        }
419
    }
420

UNCOV
421
    return realsize;
×
422
}
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