From 477e91d75368aa275b9207d1ff12c10a99b1e51c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 14 Jan 2019 14:40:12 +0100 Subject: [PATCH] connectivity: don't cache HTTP response for comparing connectivity response We don't need to remember (and compare) all the bytes that we received. We can just compare them right away, and remember how many good bytes we received. --- src/nm-connectivity.c | 73 +++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index 8b9af5076..bc0e1d94c 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -92,7 +92,7 @@ struct _NMConnectivityCheckHandle { struct curl_slist *request_headers; struct curl_slist *hosts; - GString *recv_msg; + gsize response_good_cnt; guint curl_timer; int ch_ifindex; @@ -271,8 +271,6 @@ cb_data_complete (NMConnectivityCheckHandle *cb_data, #if WITH_CONCHECK _con_config_unref (cb_data->concheck.con_config); - if (cb_data->concheck.recv_msg) - g_string_free (cb_data->concheck.recv_msg, TRUE); #endif g_free (cb_data->ifspec); if (cb_data->completed_log_message_free) @@ -391,8 +389,7 @@ _con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask) } if ( response_code == 200 - && ( !cb_data->concheck.recv_msg - || cb_data->concheck.recv_msg->len == 0)) { + && cb_data->concheck.response_good_cnt == 0) { /* we expected no response, and indeed we got an empty reply (with status code 200) */ cb_data_queue_completed (cb_data, NM_CONNECTIVITY_FULL, @@ -561,6 +558,8 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) { NMConnectivityCheckHandle *cb_data = userdata; size_t len = size * nmemb; + size_t response_len; + size_t check_len; const char *response; if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { @@ -573,11 +572,6 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) return len; } - if (!cb_data->concheck.recv_msg) - cb_data->concheck.recv_msg = g_string_sized_new (len + 10); - - g_string_append_len (cb_data->concheck.recv_msg, buffer, len); - response = _con_config_get_response (cb_data->concheck.con_config);; if (response[0] == '\0') { @@ -586,22 +580,55 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) * response based on the status code 204. * * Continue receiving... */ + cb_data->concheck.response_good_cnt += len; + + if (cb_data->concheck.response_good_cnt > (gsize) (100 * 1024)) { + /* we expect an empty response. We accept either + * 1) status code 204 and any response + * 2) status code 200 and an empty reponse. + * + * Here, we want to continue receiving data, to see whether we have + * case 1). Arguably, the server shouldn't send us 204 with a non-empty + * response, but we accept that also with a non-empty response, so + * keep receiving. + * + * However, if we get an excessive amound of data, we put a stop on it + * and fail. */ + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_PORTAL, + "unexpected non-empty response", + NULL); + return 0; + } + return len; } - if (cb_data->concheck.recv_msg->len >= strlen (response)) { - /* We already have enough data -- check response */ - if (g_str_has_prefix (cb_data->concheck.recv_msg->str, response)) { - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "expected response", - NULL); - } else { - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_PORTAL, - "unexpected response", - NULL); - } + nm_assert (cb_data->concheck.response_good_cnt < strlen (response)); + + response_len = strlen (response); + + check_len = NM_MIN (len, + response_len - cb_data->concheck.response_good_cnt); + + if (strncmp (&response[cb_data->concheck.response_good_cnt], + buffer, + check_len) != 0) { + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_PORTAL, + "unexpected response", + NULL); + return 0; + } + + cb_data->concheck.response_good_cnt += len; + + if (cb_data->concheck.response_good_cnt >= response_len) { + /* We already have enough data, and it matched. */ + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_FULL, + "expected response", + NULL); return 0; }