Coverage Report

Created: 2026-08-31 06:47

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
0
#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
0
{
44
0
  struct cf_recvbuf_ctx *ctx = cf->ctx;
45
0
  (void)data;
46
0
  if(ctx) {
47
0
    Curl_bufq_free(&ctx->recvbuf);
48
0
    curlx_free(ctx);
49
0
  }
50
0
}
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
0
{
57
0
  struct cf_recvbuf_ctx *ctx = cf->ctx;
58
59
0
  if(!Curl_bufq_is_empty(&ctx->recvbuf)) {
60
0
    return Curl_bufq_cread(&ctx->recvbuf, buf, len, pnread);
61
0
  }
62
63
0
  if(cf->next)
64
0
    return cf->next->cft->do_recv(cf->next, data, buf, len, pnread);
65
0
  *pnread = 0;
66
0
  return CURLE_RECV_ERROR;
67
0
}
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
0
{
102
0
  struct Curl_cfilter *cf = NULL;
103
0
  struct cf_recvbuf_ctx *ctx;
104
0
  CURLcode result = CURLE_OK;
105
0
  size_t nwritten = 0;
106
107
0
  (void)data;
108
0
  ctx = curlx_calloc(1, sizeof(*ctx));
109
0
  if(!ctx) {
110
0
    result = CURLE_OUT_OF_MEMORY;
111
0
    goto out;
112
0
  }
113
0
  Curl_bufq_init2(&ctx->recvbuf, CURL_CF_RECVBUF_CHUNK,
114
0
                  (blen / CURL_CF_RECVBUF_CHUNK) + 1,
115
0
                  (BUFQ_OPT_SOFT_LIMIT | BUFQ_OPT_NO_SPARES));
116
0
  result = Curl_bufq_write(&ctx->recvbuf, buf, blen, &nwritten);
117
0
  if(result)
118
0
    goto out;
119
0
  if(nwritten != blen) {
120
0
    result = CURLE_FAILED_INIT;
121
0
    goto out;
122
0
  }
123
124
0
  result = Curl_cf_create(&cf, &Curl_cft_recvbuf, ctx);
125
0
  if(result)
126
0
    goto out;
127
0
  ctx = NULL;
128
129
0
out:
130
0
  *pcf = result ? NULL : cf;
131
0
  if(ctx) {
132
0
    Curl_bufq_free(&ctx->recvbuf);
133
0
    curlx_free(ctx);
134
0
  }
135
0
  return result;
136
0
}
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
0
{
143
0
  struct Curl_cfilter *cf;
144
0
  CURLcode result = CURLE_OK;
145
146
0
  DEBUGASSERT(data);
147
0
  result = cf_recvbuf_create(&cf, data, buf, blen);
148
0
  if(result)
149
0
    goto out;
150
151
0
  cf->connected = Curl_conn_is_connected(conn, sockindex);
152
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
153
0
out:
154
0
  return result;
155
0
}
156
157
#endif /* !CURL_DISABLE_WEBSOCKETS */