Coverage Report

Created: 2024-09-08 06:32

/src/nghttp2/lib/nghttp2_buf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * nghttp2 - HTTP/2 C Library
3
 *
4
 * Copyright (c) 2014 Tatsuhiro Tsujikawa
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
#include "nghttp2_buf.h"
26
27
#include <stdio.h>
28
29
#include "nghttp2_helper.h"
30
#include "nghttp2_debug.h"
31
32
25.1k
void nghttp2_buf_init(nghttp2_buf *buf) {
33
25.1k
  buf->begin = NULL;
34
25.1k
  buf->end = NULL;
35
25.1k
  buf->pos = NULL;
36
25.1k
  buf->last = NULL;
37
25.1k
  buf->mark = NULL;
38
25.1k
}
39
40
8.46k
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
41
8.46k
  nghttp2_buf_init(buf);
42
8.46k
  return nghttp2_buf_reserve(buf, initial, mem);
43
8.46k
}
44
45
40.6k
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) {
46
40.6k
  if (buf == NULL) {
47
0
    return;
48
0
  }
49
50
40.6k
  nghttp2_mem_free(mem, buf->begin);
51
40.6k
  buf->begin = NULL;
52
40.6k
}
53
54
8.46k
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) {
55
8.46k
  uint8_t *ptr;
56
8.46k
  size_t cap;
57
58
8.46k
  cap = nghttp2_buf_cap(buf);
59
60
8.46k
  if (cap >= new_cap) {
61
0
    return 0;
62
0
  }
63
64
8.46k
  new_cap = nghttp2_max_size(new_cap, cap * 2);
65
66
8.46k
  ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
67
8.46k
  if (ptr == NULL) {
68
0
    return NGHTTP2_ERR_NOMEM;
69
0
  }
70
71
8.46k
  buf->pos = ptr + (buf->pos - buf->begin);
72
8.46k
  buf->last = ptr + (buf->last - buf->begin);
73
8.46k
  buf->mark = ptr + (buf->mark - buf->begin);
74
8.46k
  buf->begin = ptr;
75
8.46k
  buf->end = ptr + new_cap;
76
77
8.46k
  return 0;
78
8.46k
}
79
80
104k
void nghttp2_buf_reset(nghttp2_buf *buf) {
81
104k
  buf->pos = buf->last = buf->mark = buf->begin;
82
104k
}
83
84
94.6k
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
85
94.6k
  buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin;
86
94.6k
  if (len) {
87
61.4k
    buf->end += len;
88
61.4k
  }
89
94.6k
}
90
91
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
92
8.46k
                         nghttp2_mem *mem) {
93
8.46k
  int rv;
94
95
8.46k
  *chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
96
8.46k
  if (*chain == NULL) {
97
0
    return NGHTTP2_ERR_NOMEM;
98
0
  }
99
100
8.46k
  (*chain)->next = NULL;
101
102
8.46k
  rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
103
8.46k
  if (rv != 0) {
104
0
    nghttp2_mem_free(mem, *chain);
105
0
    return NGHTTP2_ERR_NOMEM;
106
0
  }
107
108
8.46k
  return 0;
109
8.46k
}
110
111
8.46k
static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) {
112
8.46k
  nghttp2_buf_free(&chain->buf, mem);
113
8.46k
  nghttp2_mem_free(mem, chain);
114
8.46k
}
115
116
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
117
0
                      nghttp2_mem *mem) {
118
0
  return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
119
0
}
120
121
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
122
0
                       size_t max_chunk, size_t offset, nghttp2_mem *mem) {
123
0
  return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
124
0
                            mem);
125
0
}
126
127
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
128
                       size_t max_chunk, size_t chunk_keep, size_t offset,
129
8.35k
                       nghttp2_mem *mem) {
130
8.35k
  int rv;
131
8.35k
  nghttp2_buf_chain *chain;
132
133
8.35k
  if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
134
0
    return NGHTTP2_ERR_INVALID_ARGUMENT;
135
0
  }
136
137
8.35k
  rv = buf_chain_new(&chain, chunk_length, mem);
138
8.35k
  if (rv != 0) {
139
0
    return rv;
140
0
  }
141
142
8.35k
  bufs->mem = mem;
143
8.35k
  bufs->offset = offset;
144
145
8.35k
  bufs->head = chain;
146
8.35k
  bufs->cur = bufs->head;
147
148
8.35k
  nghttp2_buf_shift_right(&bufs->cur->buf, offset);
149
150
8.35k
  bufs->chunk_length = chunk_length;
151
8.35k
  bufs->chunk_used = 1;
152
8.35k
  bufs->max_chunk = max_chunk;
153
8.35k
  bufs->chunk_keep = chunk_keep;
154
155
8.35k
  return 0;
156
8.35k
}
157
158
0
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
159
0
  int rv;
160
0
  nghttp2_buf_chain *chain;
161
162
0
  if (chunk_length < bufs->offset) {
163
0
    return NGHTTP2_ERR_INVALID_ARGUMENT;
164
0
  }
165
166
0
  rv = buf_chain_new(&chain, chunk_length, bufs->mem);
167
0
  if (rv != 0) {
168
0
    return rv;
169
0
  }
170
171
0
  nghttp2_bufs_free(bufs);
172
173
0
  bufs->head = chain;
174
0
  bufs->cur = bufs->head;
175
176
0
  nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
177
178
0
  bufs->chunk_length = chunk_length;
179
0
  bufs->chunk_used = 1;
180
181
0
  return 0;
182
0
}
183
184
8.35k
void nghttp2_bufs_free(nghttp2_bufs *bufs) {
185
8.35k
  nghttp2_buf_chain *chain, *next_chain;
186
187
8.35k
  if (bufs == NULL) {
188
0
    return;
189
0
  }
190
191
16.7k
  for (chain = bufs->head; chain;) {
192
8.35k
    next_chain = chain->next;
193
194
8.35k
    buf_chain_del(chain, bufs->mem);
195
196
8.35k
    chain = next_chain;
197
8.35k
  }
198
199
8.35k
  bufs->head = NULL;
200
8.35k
}
201
202
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
203
0
                           nghttp2_mem *mem) {
204
0
  nghttp2_buf_chain *chain;
205
206
0
  chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
207
0
  if (chain == NULL) {
208
0
    return NGHTTP2_ERR_NOMEM;
209
0
  }
210
211
0
  chain->next = NULL;
212
213
0
  nghttp2_buf_wrap_init(&chain->buf, begin, len);
214
215
0
  bufs->mem = mem;
216
0
  bufs->offset = 0;
217
218
0
  bufs->head = chain;
219
0
  bufs->cur = bufs->head;
220
221
0
  bufs->chunk_length = len;
222
0
  bufs->chunk_used = 1;
223
0
  bufs->max_chunk = 1;
224
0
  bufs->chunk_keep = 1;
225
226
0
  return 0;
227
0
}
228
229
int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
230
0
                            size_t veclen, nghttp2_mem *mem) {
231
0
  size_t i = 0;
232
0
  nghttp2_buf_chain *cur_chain;
233
0
  nghttp2_buf_chain *head_chain;
234
0
  nghttp2_buf_chain **dst_chain = &head_chain;
235
236
0
  if (veclen == 0) {
237
0
    return nghttp2_bufs_wrap_init(bufs, NULL, 0, mem);
238
0
  }
239
240
0
  head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * veclen);
241
0
  if (head_chain == NULL) {
242
0
    return NGHTTP2_ERR_NOMEM;
243
0
  }
244
245
0
  for (i = 0; i < veclen; ++i) {
246
0
    cur_chain = &head_chain[i];
247
0
    cur_chain->next = NULL;
248
0
    nghttp2_buf_wrap_init(&cur_chain->buf, vec[i].base, vec[i].len);
249
250
0
    *dst_chain = cur_chain;
251
0
    dst_chain = &cur_chain->next;
252
0
  }
253
254
0
  bufs->mem = mem;
255
0
  bufs->offset = 0;
256
257
0
  bufs->head = head_chain;
258
0
  bufs->cur = bufs->head;
259
260
  /* We don't use chunk_length since no allocation is expected. */
261
0
  bufs->chunk_length = 0;
262
0
  bufs->chunk_used = veclen;
263
0
  bufs->max_chunk = veclen;
264
0
  bufs->chunk_keep = veclen;
265
266
0
  return 0;
267
0
}
268
269
0
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
270
0
  if (bufs == NULL) {
271
0
    return;
272
0
  }
273
274
0
  if (bufs->head) {
275
0
    nghttp2_mem_free(bufs->mem, bufs->head);
276
0
  }
277
0
}
278
279
0
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) {
280
0
  nghttp2_buf_chain *ci;
281
282
0
  for (ci = bufs->cur; ci; ci = ci->next) {
283
0
    if (nghttp2_buf_len(&ci->buf) == 0) {
284
0
      return;
285
0
    } else {
286
0
      bufs->cur = ci;
287
0
    }
288
0
  }
289
0
}
290
291
8.38k
size_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
292
8.38k
  nghttp2_buf_chain *ci;
293
8.38k
  size_t len;
294
295
8.38k
  len = 0;
296
16.8k
  for (ci = bufs->head; ci; ci = ci->next) {
297
8.49k
    len += nghttp2_buf_len(&ci->buf);
298
8.49k
  }
299
300
8.38k
  return len;
301
8.38k
}
302
303
112
static int bufs_alloc_chain(nghttp2_bufs *bufs) {
304
112
  int rv;
305
112
  nghttp2_buf_chain *chain;
306
307
112
  if (bufs->cur->next) {
308
0
    bufs->cur = bufs->cur->next;
309
310
0
    return 0;
311
0
  }
312
313
112
  if (bufs->max_chunk == bufs->chunk_used) {
314
0
    return NGHTTP2_ERR_BUFFER_ERROR;
315
0
  }
316
317
112
  rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
318
112
  if (rv != 0) {
319
0
    return rv;
320
0
  }
321
322
112
  DEBUGF("new buffer %zu bytes allocated for bufs %p, used %zu\n",
323
112
         bufs->chunk_length, bufs, bufs->chunk_used);
324
325
112
  ++bufs->chunk_used;
326
327
112
  bufs->cur->next = chain;
328
112
  bufs->cur = chain;
329
330
112
  nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
331
332
112
  return 0;
333
112
}
334
335
841k
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
336
841k
  int rv;
337
841k
  size_t nwrite;
338
841k
  nghttp2_buf *buf;
339
841k
  const uint8_t *p;
340
341
841k
  p = data;
342
343
1.63M
  while (len) {
344
794k
    buf = &bufs->cur->buf;
345
346
794k
    nwrite = nghttp2_min_size(nghttp2_buf_avail(buf), len);
347
794k
    if (nwrite == 0) {
348
67
      rv = bufs_alloc_chain(bufs);
349
67
      if (rv != 0) {
350
0
        return rv;
351
0
      }
352
67
      continue;
353
67
    }
354
355
793k
    buf->last = nghttp2_cpymem(buf->last, p, nwrite);
356
793k
    p += nwrite;
357
793k
    len -= nwrite;
358
793k
  }
359
360
841k
  return 0;
361
841k
}
362
363
260k
static int bufs_ensure_addb(nghttp2_bufs *bufs) {
364
260k
  int rv;
365
260k
  nghttp2_buf *buf;
366
367
260k
  buf = &bufs->cur->buf;
368
369
260k
  if (nghttp2_buf_avail(buf) > 0) {
370
260k
    return 0;
371
260k
  }
372
373
45
  rv = bufs_alloc_chain(bufs);
374
45
  if (rv != 0) {
375
0
    return rv;
376
0
  }
377
378
45
  return 0;
379
45
}
380
381
260k
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) {
382
260k
  int rv;
383
384
260k
  rv = bufs_ensure_addb(bufs);
385
260k
  if (rv != 0) {
386
0
    return rv;
387
0
  }
388
389
260k
  *bufs->cur->buf.last++ = b;
390
391
260k
  return 0;
392
260k
}
393
394
0
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) {
395
0
  int rv;
396
397
0
  rv = bufs_ensure_addb(bufs);
398
0
  if (rv != 0) {
399
0
    return rv;
400
0
  }
401
402
0
  *bufs->cur->buf.last = b;
403
404
0
  return 0;
405
0
}
406
407
0
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) {
408
0
  int rv;
409
410
0
  rv = bufs_ensure_addb(bufs);
411
0
  if (rv != 0) {
412
0
    return rv;
413
0
  }
414
415
0
  *bufs->cur->buf.last++ |= b;
416
417
0
  return 0;
418
0
}
419
420
0
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
421
0
  int rv;
422
423
0
  rv = bufs_ensure_addb(bufs);
424
0
  if (rv != 0) {
425
0
    return rv;
426
0
  }
427
428
0
  *bufs->cur->buf.last |= b;
429
430
0
  return 0;
431
0
}
432
433
0
nghttp2_ssize nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
434
0
  size_t len;
435
0
  nghttp2_buf_chain *chain;
436
0
  nghttp2_buf *buf;
437
0
  uint8_t *res;
438
0
  nghttp2_buf resbuf;
439
440
0
  len = 0;
441
442
0
  for (chain = bufs->head; chain; chain = chain->next) {
443
0
    len += nghttp2_buf_len(&chain->buf);
444
0
  }
445
446
0
  if (len == 0) {
447
0
    res = NULL;
448
0
    return 0;
449
0
  }
450
451
0
  res = nghttp2_mem_malloc(bufs->mem, len);
452
0
  if (res == NULL) {
453
0
    return NGHTTP2_ERR_NOMEM;
454
0
  }
455
456
0
  nghttp2_buf_wrap_init(&resbuf, res, len);
457
458
0
  for (chain = bufs->head; chain; chain = chain->next) {
459
0
    buf = &chain->buf;
460
0
    resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
461
0
  }
462
463
0
  *out = res;
464
465
0
  return (nghttp2_ssize)len;
466
0
}
467
468
0
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
469
0
  size_t len;
470
0
  nghttp2_buf_chain *chain;
471
0
  nghttp2_buf *buf;
472
0
  nghttp2_buf resbuf;
473
474
0
  len = nghttp2_bufs_len(bufs);
475
476
0
  nghttp2_buf_wrap_init(&resbuf, out, len);
477
478
0
  for (chain = bufs->head; chain; chain = chain->next) {
479
0
    buf = &chain->buf;
480
0
    resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
481
0
  }
482
483
0
  return len;
484
0
}
485
486
74.0k
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
487
74.0k
  nghttp2_buf_chain *chain, *ci;
488
74.0k
  size_t k;
489
490
74.0k
  k = bufs->chunk_keep;
491
492
74.0k
  for (ci = bufs->head; ci; ci = ci->next) {
493
74.0k
    nghttp2_buf_reset(&ci->buf);
494
74.0k
    nghttp2_buf_shift_right(&ci->buf, bufs->offset);
495
496
74.0k
    if (--k == 0) {
497
74.0k
      break;
498
74.0k
    }
499
74.0k
  }
500
501
74.0k
  if (ci) {
502
74.0k
    chain = ci->next;
503
74.0k
    ci->next = NULL;
504
505
74.1k
    for (ci = chain; ci;) {
506
112
      chain = ci->next;
507
508
112
      buf_chain_del(ci, bufs->mem);
509
510
112
      ci = chain;
511
112
    }
512
513
74.0k
    bufs->chunk_used = bufs->chunk_keep;
514
74.0k
  }
515
516
74.0k
  bufs->cur = bufs->head;
517
74.0k
}
518
519
0
int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); }
520
521
16.9k
int nghttp2_bufs_next_present(nghttp2_bufs *bufs) {
522
16.9k
  nghttp2_buf_chain *chain;
523
524
16.9k
  chain = bufs->cur->next;
525
526
16.9k
  return chain && nghttp2_buf_len(&chain->buf);
527
16.9k
}