Coverage Report

Created: 2026-10-28 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/cf-recvbuf.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#ifndef CURL_DISABLE_WEBSOCKETS
27
/* only used for this protocol, so far */
28
29
#include "urldata.h"
30
#include "bufq.h"
31
#include "cfilters.h"
32
#include "cf-recvbuf.h"
33
#include "curl_trc.h"
34
35
2.33k
#define CURL_CF_RECVBUF_CHUNK     (16 * 1024)
36
37
struct cf_recvbuf_ctx {
38
  struct bufq recvbuf;
39
};
40
41
static void cf_recvbuf_destroy(struct Curl_cfilter *cf,
42
                               struct Curl_easy *data)
43
1.15k
{
44
1.15k
  struct cf_recvbuf_ctx *ctx = cf->ctx;
45
1.15k
  (void)data;
46
1.15k
  if(ctx) {
47
1.15k
    Curl_bufq_free(&ctx->recvbuf);
48
1.15k
    curlx_free(ctx);
49
1.15k
  }
50
1.15k
}
51
52
static CURLcode cf_recvbuf_recv(struct Curl_cfilter *cf,
53
                                struct Curl_easy *data,
54
                                char *buf, size_t len,
55
                                size_t *pnread)
56
9.03k
{
57
9.03k
  struct cf_recvbuf_ctx *ctx = cf->ctx;
58
59
9.03k
  if(!Curl_bufq_is_empty(&ctx->recvbuf)) {
60
1.12k
    return Curl_bufq_cread(&ctx->recvbuf, buf, len, pnread);
61
1.12k
  }
62
63
7.90k
  if(cf->next)
64
7.90k
    return cf->next->cft->do_recv(cf->next, data, buf, len, pnread);
65
0
  *pnread = 0;
66
0
  return CURLE_RECV_ERROR;
67
7.90k
}
68
69
static bool cf_recvbuf_data_pending(struct Curl_cfilter *cf,
70
                                    const struct Curl_easy *data)
71
0
{
72
0
  struct cf_recvbuf_ctx *ctx = cf->ctx;
73
74
0
  if(!Curl_bufq_is_empty(&ctx->recvbuf))
75
0
    return TRUE;
76
77
0
  return cf->next ?
78
0
    cf->next->cft->has_data_pending(cf->next, data) : FALSE;
79
0
}
80
81
struct Curl_cftype Curl_cft_recvbuf = {
82
  "RECVBUF",
83
  0,
84
  CURL_LOG_LVL_NONE,
85
  cf_recvbuf_destroy,
86
  Curl_cf_def_connect,
87
  Curl_cf_def_shutdown,
88
  Curl_cf_def_adjust_pollset,
89
  cf_recvbuf_data_pending,
90
  Curl_cf_def_send,
91
  cf_recvbuf_recv,
92
  Curl_cf_def_cntrl,
93
  Curl_cf_def_conn_is_alive,
94
  Curl_cf_def_conn_keep_alive,
95
  Curl_cf_def_query,
96
};
97
98
static CURLcode cf_recvbuf_create(struct Curl_cfilter **pcf,
99
                                  struct Curl_easy *data,
100
                                  const uint8_t *buf, size_t blen)
101
1.17k
{
102
1.17k
  struct Curl_cfilter *cf = NULL;
103
1.17k
  struct cf_recvbuf_ctx *ctx;
104
1.17k
  CURLcode result = CURLE_OK;
105
1.17k
  size_t nwritten = 0;
106
107
1.17k
  (void)data;
108
1.17k
  ctx = curlx_calloc(1, sizeof(*ctx));
109
1.17k
  if(!ctx) {
110
5
    result = CURLE_OUT_OF_MEMORY;
111
5
    goto out;
112
5
  }
113
1.16k
  Curl_bufq_init2(&ctx->recvbuf, CURL_CF_RECVBUF_CHUNK,
114
1.16k
                  (blen / CURL_CF_RECVBUF_CHUNK) + 1,
115
1.16k
                  (BUFQ_OPT_SOFT_LIMIT | BUFQ_OPT_NO_SPARES));
116
1.16k
  result = Curl_bufq_write(&ctx->recvbuf, buf, blen, &nwritten);
117
1.16k
  if(result)
118
8
    goto out;
119
1.16k
  if(nwritten != blen) {
120
0
    result = CURLE_FAILED_INIT;
121
0
    goto out;
122
0
  }
123
124
1.16k
  result = Curl_cf_create(&cf, &Curl_cft_recvbuf, ctx);
125
1.16k
  if(result)
126
6
    goto out;
127
1.15k
  ctx = NULL;
128
129
1.17k
out:
130
1.17k
  *pcf = result ? NULL : cf;
131
1.17k
  if(ctx) {
132
14
    Curl_bufq_free(&ctx->recvbuf);
133
14
    curlx_free(ctx);
134
14
  }
135
1.17k
  return result;
136
1.15k
}
137
138
CURLcode Curl_cf_recvbuf_add(struct Curl_easy *data,
139
                             struct connectdata *conn,
140
                             int8_t sockindex,
141
                             const uint8_t *buf, size_t blen)
142
1.17k
{
143
1.17k
  struct Curl_cfilter *cf;
144
1.17k
  CURLcode result = CURLE_OK;
145
146
1.17k
  DEBUGASSERT(data);
147
1.17k
  result = cf_recvbuf_create(&cf, data, buf, blen);
148
1.17k
  if(result)
149
19
    goto out;
150
151
1.15k
  cf->connected = Curl_conn_is_connected(conn, sockindex);
152
1.15k
  Curl_conn_cf_add(data, conn, sockindex, cf);
153
1.17k
out:
154
1.17k
  return result;
155
1.15k
}
156
157
#endif /* !CURL_DISABLE_WEBSOCKETS */